Initial import of protobuf.js

Change-Id: I4cdf03cfcc4d78ad7c91355b6af5dcf76118d7b9
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..b0ff90a
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,15 @@
+**/node_modules/*
+bin/*
+cli/wrappers/*
+coverage/*
+dist/*
+docs/*
+lib/deep-equal/*
+lib/prelude.js
+lib/polyfill.js
+lib/tape-adapter.js
+lib/tsd-jsdoc/*
+lib/*/tests/*
+sandbox/*
+scripts/*
+tests/*
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..4f5cea4
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+bin/* text eol=lf
+dist/* binary
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..22b9922
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,11 @@
+protobuf.js version: <please fill in>
+
+<please describe the expected and actual behavior>
+
+```js
+<please provide a code snippet for reproduction>
+```
+
+```
+<please paste the stack trace of the error if applicable>
+```
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
new file mode 100644
index 0000000..19e65a7
--- /dev/null
+++ b/.github/workflows/release.yaml
@@ -0,0 +1,13 @@
+on:
+  push:
+    branches:
+      - master
+name: release-please
+jobs:
+  release-please:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: google-github-actions/release-please-action@v3
+        with:
+          command: manifest
+          package-name: release-please-action
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..b6795f9
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,48 @@
+name: "Test"
+on:
+  push:
+    branches:
+    - master
+  pull_request:
+    types: [assigned, opened, synchronize, reopened, labeled]
+jobs:
+  lint:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v1
+    - uses: actions/setup-node@v1
+      with:
+        node-version: "12"
+    - name: "Install dependencies"
+      run: npm install
+    - name: "Lint sources"
+      run: npm run lint:sources -- --max-warnings 0
+    - name: "Lint types"
+      run: npm run lint:types
+  test:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        node_version: ["12", "14", "16", "18"]
+    steps:
+    - uses: actions/checkout@v1
+    - uses: actions/setup-node@v1
+      with:
+        node-version: ${{ matrix.node_version }}
+    - name: "Install dependencies"
+      run: npm install
+    - name: "Test sources"
+      run: npm run test:sources
+    - name: "Test types"
+      run: npm run test:types
+  bench:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v1
+    - uses: actions/setup-node@v1
+      with:
+        node-version: "12"
+    - name: "Install dependencies"
+      run: npm install
+    - name: "Run benchmark"
+      run: npm run bench
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b284f56
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+.nyc_output
+.vscode
+*.log
+npm-debug.*
+node_modules/
+cli/node_modules/
+cli/package-lock.json
+docs/
+coverage/
+sandbox/
+.nyc_output
+dist/
+.gitpod.yml
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
new file mode 100644
index 0000000..03bfcc3
--- /dev/null
+++ b/.release-please-manifest.json
@@ -0,0 +1 @@
+{".":"7.2.2","cli":"1.1.1"}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..38f841e
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,1110 @@
+# Changelog
+
+## [7.2.2](https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.2.1...protobufjs-v7.2.2) (2023-02-07)
+
+
+### Bug Fixes
+
+* do not allow to extend same field twice to prevent the error ([#1784](https://github.com/protobufjs/protobuf.js/issues/1784)) ([14f0536](https://github.com/protobufjs/protobuf.js/commit/14f05364a04fe1ca0bfb278b3407e058c6b5a1ab))
+
+## [7.2.1](https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.2.0...protobufjs-v7.2.1) (2023-02-02)
+
+
+### Bug Fixes
+
+* **cli:** fix relative path to Google pb files ([#1859](https://github.com/protobufjs/protobuf.js/issues/1859)) ([e42eea4](https://github.com/protobufjs/protobuf.js/commit/e42eea4868b11f4a07934804a56683321ed191e2))
+* Revert "fix: error should be thrown" ([4489fa7](https://github.com/protobufjs/protobuf.js/commit/4489fa771464bcb49b57149760e9cc4131e8077e))
+* use bundled filename to fix common pb includes ([#1860](https://github.com/protobufjs/protobuf.js/issues/1860)) ([dce9a2e](https://github.com/protobufjs/protobuf.js/commit/dce9a2ef92d363752e40b295b0da9bd178f82e83))
+* use ES5 style function syntax ([#1830](https://github.com/protobufjs/protobuf.js/issues/1830)) ([64e8936](https://github.com/protobufjs/protobuf.js/commit/64e8936ad9f73c68b3fa1e57857dd38323b5a745))
+
+## [7.2.0](https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.1.2...protobufjs-v7.2.0) (2023-01-24)
+
+
+### Features
+
+* **cli:** generate static files at the granularity of proto messages ([#1840](https://github.com/protobufjs/protobuf.js/issues/1840)) ([32f2d6a](https://github.com/protobufjs/protobuf.js/commit/32f2d6a68b27997bd0f7619998695a9fa7a4fd70))
+
+
+### Bug Fixes
+
+* error should be thrown ([#1817](https://github.com/protobufjs/protobuf.js/issues/1817)) ([e7a3489](https://github.com/protobufjs/protobuf.js/commit/e7a34897a122342485468999a507626f1ea91507))
+
+## [7.1.2](https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.1.1...protobufjs-v7.1.2) (2022-09-22)
+
+
+### Bug Fixes
+
+* **types:** nested object can be a oneof ([#1812](https://github.com/protobufjs/protobuf.js/issues/1812)) ([119d90a](https://github.com/protobufjs/protobuf.js/commit/119d90aa1ce14d7bff20bb1dcc1ddc4544a80c23))
+
+## [7.1.1](https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.1.0...protobufjs-v7.1.1) (2022-09-09)
+
+
+### Bug Fixes
+
+* add import long to the generated .d.ts ([#1802](https://github.com/protobufjs/protobuf.js/issues/1802)) ([7c27b5a](https://github.com/protobufjs/protobuf.js/commit/7c27b5ad5d161c9f3711aa053ca704f8e1224e90))
+* generate valid js code for aliased enum values ([#1801](https://github.com/protobufjs/protobuf.js/issues/1801)) ([7120e93](https://github.com/protobufjs/protobuf.js/commit/7120e93b7980728614779c50f40877da57e3cf37))
+
+## [7.1.0](https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.0.0...protobufjs-v7.1.0) (2022-08-26)
+
+
+### Features
+
+* accept unknown enum values in fromObject ([#1793](https://github.com/protobufjs/protobuf.js/issues/1793)) ([ef24ae4](https://github.com/protobufjs/protobuf.js/commit/ef24ae4e93cf8635ff38398b37f3597e5d478330))
+* valuesOptions for enums ([#1358](https://github.com/protobufjs/protobuf.js/issues/1358)) ([bb6b1d4](https://github.com/protobufjs/protobuf.js/commit/bb6b1d4942d924bcb4ee3ad15f4823f2d9c1ab22))
+
+
+### Bug Fixes
+
+* **deps:** update dependency glob to v8 ([#1750](https://github.com/protobufjs/protobuf.js/issues/1750)) ([8303a64](https://github.com/protobufjs/protobuf.js/commit/8303a648bc12dcea5aa8e7efa042de39011857f9))
+* extensions broke oneof ([#1789](https://github.com/protobufjs/protobuf.js/issues/1789)) ([d7f501c](https://github.com/protobufjs/protobuf.js/commit/d7f501c49d523cda423a3ab8bcaeb59a0216b350))
+* remove unused `@types/long` ([#1785](https://github.com/protobufjs/protobuf.js/issues/1785)) ([0f4af83](https://github.com/protobufjs/protobuf.js/commit/0f4af83e4ed3cef1ec035c2833e0b06cab0bd87f))
+* support for nested messages and enums within group blocks ([#1790](https://github.com/protobufjs/protobuf.js/issues/1790)) ([f36d4e4](https://github.com/protobufjs/protobuf.js/commit/f36d4e4a2df809b47ff85f87aba319b86be90878))
+* **types:** update type deps ([#1776](https://github.com/protobufjs/protobuf.js/issues/1776)) ([d87978b](https://github.com/protobufjs/protobuf.js/commit/d87978b8eb2a176676c58379a89206b94a6d926a))
+
+## [7.0.0](https://github.com/protobufjs/protobuf.js/compare/protobufjs-v6.0.0...protobufjs-v7.0.0) (2022-07-08)
+
+
+### ⚠ BREAKING CHANGES
+
+* drop support for Node 4, 6, 8, 10 (#1764)
+* move command line tool to a new package named protobufjs-cli (#1234)
+* encoding of empty Buffers (#1514)
+
+### Features
+
+* add --no-service option for pbjs static target ([#1577](https://github.com/protobufjs/protobuf.js/issues/1577)) ([d01394a](https://github.com/protobufjs/protobuf.js/commit/d01394a1463062824c066b653aad53c449752202))
+* add alt-comment CLI option ([#1692](https://github.com/protobufjs/protobuf.js/issues/1692)) ([7558ef0](https://github.com/protobufjs/protobuf.js/commit/7558ef0f93177978272f68f1710144a26b63e525))
+* add configurable Root.prototype.fetch ([ad3cffd](https://github.com/protobufjs/protobuf.js/commit/ad3cffdc5a54a7c94830674270d3386e1a2b58fc))
+* add getTypeUrl method to generated code ([#1463](https://github.com/protobufjs/protobuf.js/issues/1463)) ([d13d5d5](https://github.com/protobufjs/protobuf.js/commit/d13d5d5688052e366aa2e9169f50dfca376b32cf))
+* add null-defaults option ([#1611](https://github.com/protobufjs/protobuf.js/issues/1611)) ([6e713ba](https://github.com/protobufjs/protobuf.js/commit/6e713baf54bd987ae52cbf92a4f2742c70201dc0))
+* add support for buffer configuration ([#1372](https://github.com/protobufjs/protobuf.js/issues/1372)) ([101aa1a](https://github.com/protobufjs/protobuf.js/commit/101aa1a4f148516fdc83a74f54a229f06e24a5de))
+* allow message.getTypeUrl provide custom typeUrlPrefix ([#1762](https://github.com/protobufjs/protobuf.js/issues/1762)) ([8aad1dd](https://github.com/protobufjs/protobuf.js/commit/8aad1dd994b1fc1f23bd71adf3a81b7a5616b210))
+* better comment parse ([#1419](https://github.com/protobufjs/protobuf.js/issues/1419)) ([7fd2e18](https://github.com/protobufjs/protobuf.js/commit/7fd2e182150c9b6be9ba21e6450b6e4668ad9f82))
+* move command line tool to a new package named protobufjs-cli ([#1234](https://github.com/protobufjs/protobuf.js/issues/1234)) ([da34f43](https://github.com/protobufjs/protobuf.js/commit/da34f43ccd51ad97017e139f137521782f5ef119))
+* parsed options ([#1256](https://github.com/protobufjs/protobuf.js/issues/1256)) ([7a25398](https://github.com/protobufjs/protobuf.js/commit/7a2539843055b6daecb9f369c67a6cf588dbb54c))
+* prepare initial publication of cli ([#1752](https://github.com/protobufjs/protobuf.js/issues/1752)) ([64811d5](https://github.com/protobufjs/protobuf.js/commit/64811d5878c31e4a86a39da5fec6aea35da22fcd))
+* proto3 optional support ([#1584](https://github.com/protobufjs/protobuf.js/issues/1584)) ([6c4d307](https://github.com/protobufjs/protobuf.js/commit/6c4d30716a9a756dcdc21d64f9c9d069315fc5b1))
+* support parsing of complex options ([#1744](https://github.com/protobufjs/protobuf.js/issues/1744)) ([b1746a8](https://github.com/protobufjs/protobuf.js/commit/b1746a8c5e2b9c29644318090cc9e581f7e34b6e))
+* update dependencies / general cleanup ([#1356](https://github.com/protobufjs/protobuf.js/issues/1356)) ([42f49b4](https://github.com/protobufjs/protobuf.js/commit/42f49b43f692c24c2bc1ae081b4d1ad9fa173cd7))
+
+
+### Bug Fixes
+
+* allow for an optional semicolon where there is an optional comma in parseOptionValue ([#1571](https://github.com/protobufjs/protobuf.js/issues/1571)) ([af1b449](https://github.com/protobufjs/protobuf.js/commit/af1b449602b360091e191a58abde2f246d8b0f1d))
+* allow Windows unc paths to be resolved and normalized ([#1351](https://github.com/protobufjs/protobuf.js/issues/1351)) ([cd4aeda](https://github.com/protobufjs/protobuf.js/commit/cd4aeda8036f80cfa3b9f1db4096d856b2fd05fb))
+* **deps:** patch minimatch vulnerability ([#1704](https://github.com/protobufjs/protobuf.js/issues/1704)) ([bac61b8](https://github.com/protobufjs/protobuf.js/commit/bac61b8c2757804bbb9c5fa0f8bc6a7bcf0bb374))
+* **deps:** update dependency long to v5 ([#1751](https://github.com/protobufjs/protobuf.js/issues/1751)) ([dadc65e](https://github.com/protobufjs/protobuf.js/commit/dadc65e12d654f96daf83253476e55da35214904))
+* **deps:** use eslint 8.x ([#1728](https://github.com/protobufjs/protobuf.js/issues/1728)) ([fa01883](https://github.com/protobufjs/protobuf.js/commit/fa01883a0f756824d69ce92bfb012de05ff223ef))
+* do not fail if no process ([#1440](https://github.com/protobufjs/protobuf.js/issues/1440)) ([f2faa8c](https://github.com/protobufjs/protobuf.js/commit/f2faa8c32e918b3b843005f0419608b8e158998d))
+* do not let setProperty change the prototype ([#1731](https://github.com/protobufjs/protobuf.js/issues/1731)) ([3357ef7](https://github.com/protobufjs/protobuf.js/commit/3357ef753871b394b825d15429ceb27b26e24d63))
+* **docs:** update CHANGELOG to match format of release-please ([#1376](https://github.com/protobufjs/protobuf.js/issues/1376)) ([15ed8a0](https://github.com/protobufjs/protobuf.js/commit/15ed8a0fbe72b2e408b87ba25028f877796cc191))
+* drop support for Node 4, 6, 8, 10 ([#1764](https://github.com/protobufjs/protobuf.js/issues/1764)) ([50370dd](https://github.com/protobufjs/protobuf.js/commit/50370dd7747a0986e83ddbe51c54b97033af5ead))
+* encoding of empty Buffers ([#1514](https://github.com/protobufjs/protobuf.js/issues/1514)) ([b4cae07](https://github.com/protobufjs/protobuf.js/commit/b4cae07440387399e097058e15e50608a0e764fd)), closes [#1500](https://github.com/protobufjs/protobuf.js/issues/1500) [#885](https://github.com/protobufjs/protobuf.js/issues/885)
+* es6 export enum ([#1446](https://github.com/protobufjs/protobuf.js/issues/1446)) ([9f33784](https://github.com/protobufjs/protobuf.js/commit/9f33784350b1efc2e774bbfc087cbd2c47828748))
+* fix util.global ([#1441](https://github.com/protobufjs/protobuf.js/issues/1441)) ([742b8dc](https://github.com/protobufjs/protobuf.js/commit/742b8dcbc750f9c2659088cbd88ea61fd11b24a7))
+* fromObject should not initialize oneof members ([#1597](https://github.com/protobufjs/protobuf.js/issues/1597)) ([90afe44](https://github.com/protobufjs/protobuf.js/commit/90afe4412de8070b0c0681e5905a6e0213072a85))
+* google.protobuf.Any type_url fixes ([#1068](https://github.com/protobufjs/protobuf.js/issues/1068)) ([192f5f1](https://github.com/protobufjs/protobuf.js/commit/192f5f12d071fa534ac625290d4666c839a46a9e))
+* handling of map entries with omitted key or value ([#1348](https://github.com/protobufjs/protobuf.js/issues/1348)) ([b950877](https://github.com/protobufjs/protobuf.js/commit/b950877c86676399674821fca4cf444f046b5acb))
+* handling properly fields with leading and trailing comments after field with trailing comment ([#1593](https://github.com/protobufjs/protobuf.js/issues/1593)) ([9011aac](https://github.com/protobufjs/protobuf.js/commit/9011aac161e1bf8eaa3cbf0f17e8f321b6e0d9c4))
+* make node detection a bit more forgiving ([#1445](https://github.com/protobufjs/protobuf.js/issues/1445)) ([4e75f6d](https://github.com/protobufjs/protobuf.js/commit/4e75f6de4a2e49f28c24b59107f262d472b68977))
+* make parsedOptions appear in method JSON representation ([#1506](https://github.com/protobufjs/protobuf.js/issues/1506)) ([3d29969](https://github.com/protobufjs/protobuf.js/commit/3d29969865f2119550d9dc88391846469da9fa7f))
+* proper relative path to protobufjs in cli ([#1753](https://github.com/protobufjs/protobuf.js/issues/1753)) ([a1d6029](https://github.com/protobufjs/protobuf.js/commit/a1d60292ecb22fcf89c493c562ae07ab10ef49c9))
+* properly parse empty messages in options ([#1429](https://github.com/protobufjs/protobuf.js/issues/1429)) ([7fbc79f](https://github.com/protobufjs/protobuf.js/commit/7fbc79f11d89b263dafc8f332ccba59a8d181fca))
+* proto3 optional scalars should default to null in reflection API ([#1693](https://github.com/protobufjs/protobuf.js/issues/1693)) ([d9144de](https://github.com/protobufjs/protobuf.js/commit/d9144dea611c9a1c0e01cc3e0e2491c6de5f9c97))
+* replace deprecated String.prototype.substr() ([#1701](https://github.com/protobufjs/protobuf.js/issues/1701)) ([e33a84a](https://github.com/protobufjs/protobuf.js/commit/e33a84a301eb6beaaa6a71a20756f0b5ccfb0459))
+* scope variable for map field to avoid redeclaration ([#1717](https://github.com/protobufjs/protobuf.js/issues/1717)) ([#1718](https://github.com/protobufjs/protobuf.js/issues/1718)) ([1d3c02a](https://github.com/protobufjs/protobuf.js/commit/1d3c02a89ea9ad794b454d11ca2de425db4772dd))
+* support for options with `repeated_value: [ "foo", "bar" ]` ([#1574](https://github.com/protobufjs/protobuf.js/issues/1574)) ([f5b893c](https://github.com/protobufjs/protobuf.js/commit/f5b893c03e9694bbe7da7c4001cc74b06039eb9c))
+* typo in pbjs help text ([#1552](https://github.com/protobufjs/protobuf.js/issues/1552)) ([7f46dbe](https://github.com/protobufjs/protobuf.js/commit/7f46dbeb538a6277035a896e1ab5e1a070e28681))
+* update minimal.js to evade override mistake ([#1742](https://github.com/protobufjs/protobuf.js/issues/1742)) ([e2f33a0](https://github.com/protobufjs/protobuf.js/commit/e2f33a04eddbcffcbc2ae16c72ac3820410057bc))
+* updated isNode check ([#1221](https://github.com/protobufjs/protobuf.js/issues/1221)) ([#1363](https://github.com/protobufjs/protobuf.js/issues/1363)) ([5564e7b](https://github.com/protobufjs/protobuf.js/commit/5564e7b5f07d3eab99762528e8ce88507af5a5a3))
+* utf8 -> utf16 decoding bug on surrogate pairs ([#1486](https://github.com/protobufjs/protobuf.js/issues/1486)) ([75172cd](https://github.com/protobufjs/protobuf.js/commit/75172cd11be137bbabd2fba7a02b15067695ebad))
+
+### [6.10.2](https://www.github.com/protobufjs/protobuf.js/compare/v6.10.1...v6.10.2) (2020-11-13)
+
+
+### Bug Fixes
+
+* es6 export enum ([#1446](https://www.github.com/protobufjs/protobuf.js/issues/1446)) ([9f33784](https://www.github.com/protobufjs/protobuf.js/commit/9f33784350b1efc2e774bbfc087cbd2c47828748))
+* make parsedOptions appear in method JSON representation ([#1506](https://www.github.com/protobufjs/protobuf.js/issues/1506)) ([3d29969](https://www.github.com/protobufjs/protobuf.js/commit/3d29969865f2119550d9dc88391846469da9fa7f))
+* utf8 -> utf16 decoding bug on surrogate pairs ([#1486](https://www.github.com/protobufjs/protobuf.js/issues/1486)) ([75172cd](https://www.github.com/protobufjs/protobuf.js/commit/75172cd11be137bbabd2fba7a02b15067695ebad))
+
+### [6.10.1](https://www.github.com/protobufjs/protobuf.js/compare/v6.10.0...v6.10.1) (2020-07-16)
+
+
+### Bug Fixes
+
+* make node detection a bit more forgiving ([#1445](https://www.github.com/protobufjs/protobuf.js/issues/1445)) ([4e75f6d](https://www.github.com/protobufjs/protobuf.js/commit/4e75f6de4a2e49f28c24b59107f262d472b68977))
+
+## [6.10.0](https://www.github.com/protobufjs/protobuf.js/compare/v6.9.0...v6.10.0) (2020-07-13)
+
+
+### Features
+
+* add configurable Root.prototype.fetch ([ad3cffd](https://www.github.com/protobufjs/protobuf.js/commit/ad3cffdc5a54a7c94830674270d3386e1a2b58fc))
+* better comment parse ([#1419](https://www.github.com/protobufjs/protobuf.js/issues/1419)) ([7fd2e18](https://www.github.com/protobufjs/protobuf.js/commit/7fd2e182150c9b6be9ba21e6450b6e4668ad9f82))
+* parsed options ([#1256](https://www.github.com/protobufjs/protobuf.js/issues/1256)) ([7a25398](https://www.github.com/protobufjs/protobuf.js/commit/7a2539843055b6daecb9f369c67a6cf588dbb54c))
+
+
+### Bug Fixes
+
+* allow Windows unc paths to be resolved and normalized ([#1351](https://www.github.com/protobufjs/protobuf.js/issues/1351)) ([cd4aeda](https://www.github.com/protobufjs/protobuf.js/commit/cd4aeda8036f80cfa3b9f1db4096d856b2fd05fb))
+* do not fail if no process ([#1440](https://www.github.com/protobufjs/protobuf.js/issues/1440)) ([f2faa8c](https://www.github.com/protobufjs/protobuf.js/commit/f2faa8c32e918b3b843005f0419608b8e158998d))
+* fix util.global ([#1441](https://www.github.com/protobufjs/protobuf.js/issues/1441)) ([742b8dc](https://www.github.com/protobufjs/protobuf.js/commit/742b8dcbc750f9c2659088cbd88ea61fd11b24a7))
+* google.protobuf.Any type_url fixes ([#1068](https://www.github.com/protobufjs/protobuf.js/issues/1068)) ([192f5f1](https://www.github.com/protobufjs/protobuf.js/commit/192f5f12d071fa534ac625290d4666c839a46a9e))
+* handling of map entries with omitted key or value ([#1348](https://www.github.com/protobufjs/protobuf.js/issues/1348)) ([b950877](https://www.github.com/protobufjs/protobuf.js/commit/b950877c86676399674821fca4cf444f046b5acb))
+* properly parse empty messages in options ([#1429](https://www.github.com/protobufjs/protobuf.js/issues/1429)) ([7fbc79f](https://www.github.com/protobufjs/protobuf.js/commit/7fbc79f11d89b263dafc8f332ccba59a8d181fca))
+* updated isNode check ([#1221](https://www.github.com/protobufjs/protobuf.js/issues/1221)) ([#1363](https://www.github.com/protobufjs/protobuf.js/issues/1363)) ([5564e7b](https://www.github.com/protobufjs/protobuf.js/commit/5564e7b5f07d3eab99762528e8ce88507af5a5a3))
+
+## [6.9.0](https://www.github.com/protobufjs/protobuf.js/compare/6.8.8...v6.9.0) (2020-04-17)
+
+
+### Features
+
+* add support for buffer configuration ([#1372](https://www.github.com/protobufjs/protobuf.js/issues/1372)) ([101aa1a](https://www.github.com/protobufjs/protobuf.js/commit/101aa1a4f148516fdc83a74f54a229f06e24a5de))
+* update dependencies / general cleanup ([#1356](https://www.github.com/protobufjs/protobuf.js/issues/1356)) ([42f49b4](https://www.github.com/protobufjs/protobuf.js/commit/42f49b43f692c24c2bc1ae081b4d1ad9fa173cd7))
+
+
+### Bug Fixes
+
+* allow file-level options everywhere in the file ([b70eebd](https://www.github.com/protobufjs/protobuf.js/commit/b70eebd86e113effaa7d13b24b19ee4a0cb9e1e5))
+* Import Long types ([1d98cb8](https://www.github.com/protobufjs/protobuf.js/commit/1d98cb86fcbc69bd54fb3d3254b348da6ac0a96b))
+* npm audit fixes ([ca52447](https://www.github.com/protobufjs/protobuf.js/commit/ca524478621bd2e08120eb444c7ad8089dba1929))
+* properly iterate and return method descriptors ([d96bb7a](https://www.github.com/protobufjs/protobuf.js/commit/d96bb7ae991ca7d5ef8eea3bca75a2089c6f1212))
+* run npm audit fix ([#1208](https://www.github.com/protobufjs/protobuf.js/issues/1208)) ([b5b6632](https://www.github.com/protobufjs/protobuf.js/commit/b5b66321762a24c5ac2753b68331cbe115969da7))
+* **docs:** update CHANGELOG to match format of release-please ([#1376](https://www.github.com/protobufjs/protobuf.js/issues/1376)) ([15ed8a0](https://www.github.com/protobufjs/protobuf.js/commit/15ed8a0fbe72b2e408b87ba25028f877796cc191))
+
+## [6.8.8](https://github.com/protobufjs/protobuf.js/releases/tag/6.8.8)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3001425b0d896d14188307cd0cc84ce195ad9e04) Persist recent index.d.ts changes in JSDoc<br />
+
+## [6.8.7](https://github.com/protobufjs/protobuf.js/releases/tag/6.8.7)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e8449c4bf1269a2cc423708db6f0b47a383d33f0) Fix package browser field descriptor ([#1046](https://github.com/protobufjs/protobuf.js/issues/1046))<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/996b3fa0c598ecc73302bfc39208c44830f07b1a) Fix static codegen issues with uglifyjs3<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a06317139b92fdd8c6b3b188fb7b9704dc8ccbf1) Fix lint issues / pbts on windows<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a927a6646e8fdddebcb3e13bc8b28b041b3ee40a) Fix empty 'bytes' field decoding, now using Buffer where applicable ([#1020](https://github.com/protobufjs/protobuf.js/issues/1020))<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f13a81fb41fbef2ce9dcee13f23b7276c83fbcfd) Fix circular dependency of Namespace and Enum ([#994](https://github.com/protobufjs/protobuf.js/issues/994))<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c05c58fad61c16e5ce20ca19758e4782cdd5d2e3) Ignore optional commas in aggregate options ([#999](https://github.com/protobufjs/protobuf.js/issues/999))<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/36fc964b8db1e4372c76b1baf9f03857cd875b07) Make Message<T> have a default type param ([#1086](https://github.com/protobufjs/protobuf.js/issues/1086))<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/996b3fa0c598ecc73302bfc39208c44830f07b1a) Explicitly define service method names when generating static code, see [#857](https://github.com/protobufjs/protobuf.js/issues/857)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/07c5d59e1da8c5533a39007ba332928206281408) Also handle services in ext/descriptor ([#1001](https://github.com/protobufjs/protobuf.js/issues/1001))<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2c5ef95818a310243f88ffba0331cd47ee603c0a) Extend list of ignored ESLint rules for pbjs, fixes [#1085](https://github.com/protobufjs/protobuf.js/issues/1085)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8576b49ad3e55b8beae2a8f044c51040484eef12) Fix declared return type of pbjs/pbts callback ([#1025](https://github.com/protobufjs/protobuf.js/issues/1025))<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9fceaa69667895e609a3ed78eb2efa7a0ecfb890) Added an option to pbts to allow custom imports ([#1038](https://github.com/protobufjs/protobuf.js/issues/1038))<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/65d113b0079fa2570837f3cf95268ce24714a248) Get node executable path from process.execPath ([#1018](https://github.com/protobufjs/protobuf.js/issues/1018))<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b611875cfbc1f98d8973a2e86f1506de84f00049) Slim down CI testing and remove some not ultimately necesssary dependencies with audit issues<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/812b38ddabb35e154f9ff94f32ad8ce2a70310f1) Move global handling to util, see [#995](https://github.com/protobufjs/protobuf.js/issues/995)<br />
+
+## [6.8.6](https://github.com/protobufjs/protobuf.js/releases/tag/6.8.6)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2ee1028d631a328e152d7e09f2a0e0c5c83dc2aa) Fix typeRefRe being vulnerable to ReDoS<br />
+
+## [6.8.5](https://github.com/protobufjs/protobuf.js/releases/tag/6.8.6)
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/462132f222d8febb8211d839635aad5b82dc6315) Preserve comments when serializing/deserializing with toJSON and fromJSON. ([#983](https://github.com/protobufjs/protobuf.js/issues/983))<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d29c0caa715a14214fc755b3cf10ac119cdaf199) Add more details to some frequent error messages ([#962](https://github.com/protobufjs/protobuf.js/issues/962))<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8400f87ad8ed2b47e659bc8bb6c3cf2467802425) Add IParseOptions#alternateCommentMode ([#968](https://github.com/protobufjs/protobuf.js/issues/968))<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d6e3b9e218896ec1910e02448b5ee87e4d96ede6) Added field_mask to built-in common wrappers ([#982](https://github.com/protobufjs/protobuf.js/issues/982))<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/635fef013fbb3523536d92c690ffd7d84829db35) Remove code climate config in order to use 'in-app' config instead<br />
+
+## [6.8.4](https://github.com/protobufjs/protobuf.js/releases/tag/6.8.4)
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/69440c023e6962c644715a0c95363ddf19db648f) Update jsdoc dependency (pinned vulnerable marked)<br />
+
+## [6.8.3](https://github.com/protobufjs/protobuf.js/releases/tag/6.8.3)
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/cc991a058b0636f3454166c76de7b664cf23a8f4) Use correct safeProp in json-module target, see [#956](https://github.com/protobufjs/protobuf.js/issues/956)<br />
+
+## [6.8.2](https://github.com/protobufjs/protobuf.js/releases/tag/6.8.2)
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6fc6481d790648e9e2169a961ad31a732398c911) Include dist files in npm package, see [#955](https://github.com/protobufjs/protobuf.js/issues/955)<br />
+
+## [6.8.1](https://github.com/protobufjs/protobuf.js/releases/tag/6.8.1)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/db2dd49f6aab6ecd606eee334b95cc0969e483c2) Prevent invalid JSDoc names when generating service methods, see [#870](https://github.com/protobufjs/protobuf.js/issues/870)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/62297998d681357ada70fb370b99bac5573e5054) Prevent parse errors when generating service method names, see [#870](https://github.com/protobufjs/protobuf.js/issues/870)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/478f332e0fc1d0c318a70b1514b1d59c8c200c37) Support parsing nested option-values with or without ':' ([#951](https://github.com/protobufjs/protobuf.js/issues/951), fixes [#946](https://github.com/protobufjs/protobuf.js/issues/946))<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/83477ca8e0e1f814ac79a642ea656f047563613a) Add support for reserved keyword in enums ([#950](https://github.com/protobufjs/protobuf.js/issues/950), fixes [#949](https://github.com/protobufjs/protobuf.js/issues/949))<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c482a5b76fd57769eae4308793e3ff8725264664) Unified safe property escapes and added a test for [#834](https://github.com/protobufjs/protobuf.js/issues/834)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1724581c36ecc4fc166ea14a9dd57af5e093a467) Fix codegen if type name starts with "Object"<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/adecd544c5fcbeba28d502645f895024e3552970) Fixed dependency for json-module to use "light".<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2a8dd74fca70d4e6fb41328a7cee81d1d50ad7ad) Basic support for URL prefixes in google.protobuf.Any types.<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/be78a3d9bc8d9618950c77f9e261b422670042ce) fixed 'error is not defined linter warning when using static/static-module and es6<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c712447b309ae81134c7afd60f8dfa5ecd3be230) Fixed wrong type_url for any type (no leading '.' allowed).<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/145bda25ee1de2c0678ce7b8a093669ec2526b1d) Fixed fromObject() for google.protobuf.Any types.<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7dec43d9d847481ad93fca498fd970b3a4a14b11) Handle case where 'extendee' is undefined in ext/descriptor<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/20a26271423319085d321878edc5166a5449e68a) Sanitize CR-only line endings (coming from jsdoc?)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/19d2af12b5db5a0f668f50b0cae3ee0f8a7affc2) Make sure enum typings become generated ([#884](https://github.com/protobufjs/protobuf.js/issues/884) didn't solve this)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a2c72c08b0265b112d367fa3d33407ff0de955b9) Remove exclude and include patterns from jsdoc config<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9afb8a2ff27c1e0a999d7331f3f65f568f5cced5) Skip defaults when generating proto3<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/952c7d1b478cc7c6de82475a17a1387992e8651f) Wait for both the 'end' and 'close' event to happen before finishing in pbts, see [#863](https://github.com/protobufjs/protobuf.js/issues/863)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ed7e2e71f5cde27c4128f4f2e3f4782cc51fbec7) Accept null for optional fields in generated static code<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/27cc66a539251216ef10aea04652d58113949df9) Annotate TS classes with @implements<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/05e7e0636727008c72549459b8594fa0442d346f) Annotate virtual oneofs as string literal unions<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/685adb0e7ef0f50e4b93a105013547884957cc98) Also check for reserved ids and names in enums<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/843d0d5b927968025ca11babff28495dd3bb2863) Also support 'reserved' in enum descriptors<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a8376b57fb0a858adff9dc8a1d1b5372eff9d85c) Include just relevant files in npm package, fixes [#781](https://github.com/protobufjs/protobuf.js/issues/781)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/bda1bc6917c681516f6be8be8f0e84ba1262c4ce) Fix travis build<br />
+
+## [6.8.0](https://github.com/protobufjs/protobuf.js/releases/tag/6.8.0)
+
+### Breaking
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ff858003f525db542cbb270777b6fab3a230c9bb) Replaced Buffer and Long types with interfaces and removed stubs<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/22f907c49adbbdf09b72bde5299271dbe0ee9cbe) Removed Message#toObject in favor of having just the static version (unnecessary static code otherwise)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c97b61811248df002f1fb93557b982bc0aa27309) Everything uses interfaces now instead of typedefs (SomethingProperties is now ISomething)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b9f179064f3ddf683f13e0d4e17840301be64010) ReflectionObject#toJSON properly omits explicit undefined values<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7a6f98b5e74f9e9142f9be3ba0683caeaff916c4) Initial implementation of TypeScript decorators<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7a6f98b5e74f9e9142f9be3ba0683caeaff916c4) Refactored protobuf.Class away<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7a6f98b5e74f9e9142f9be3ba0683caeaff916c4) TypeScript definitions now have (a lot of) generics<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7a6f98b5e74f9e9142f9be3ba0683caeaff916c4) Removed deprecated features<br />
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c306d19d806eb697913ffa2b8613f650127a4c50) Added 'undefined' besides 'null' as a valid value of an optional field, fixes [#826](https://github.com/protobufjs/protobuf.js/issues/826)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c5518c3bac0da9c2045e6f1baf0dee915afb4221) Fixed an issue with codegen typings, see [#819](https://github.com/protobufjs/protobuf.js/issues/819)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/66d149e92ff1baddfdfd4b6a88ca9bcea6fc6195) Ported utf8 chunking mechanism to base64 as well, fixes [#800](https://github.com/protobufjs/protobuf.js/issues/800)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e1f9d9856c98a0f0eb1aa8bdf4ac0df467bee8b9) Also be more verbose when defining properties for ES6, fixes [#820](https://github.com/protobufjs/protobuf.js/issues/820)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/cf36097305ab02047be5014eabeccc3154e18bde) Generate more verbose JSDoc comments for ES6 support, fixes [#820](https://github.com/protobufjs/protobuf.js/issues/820)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f2959795330966f13cb65bbb6034c88a01fc0bcc) Emit a maximum of one error var when generating verifiers, fixes [#786](https://github.com/protobufjs/protobuf.js/issues/786)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3b848a10b39c1897ca1ea3b5149ef72ae43fcd11) Fixed missing semicolon after 'extensions' and 'reserved' when generating proto files, fixes [#810](https://github.com/protobufjs/protobuf.js/issues/810)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/eb1b40497e14a09facbc370676f486bed1376f52) Call npm with '--no-bin-links' when installing CLI deps, fixes [#823](https://github.com/protobufjs/protobuf.js/issues/823)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/429de19d851477f1df2804d5bc0be30228cd0924) Fix Reader argument conversion in static module<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/03194c203d6ff61ae825e66f8a29ca204fa503b9) Use JSDoc, they said, it documents code, they said. Fixes [#770](https://github.com/protobufjs/protobuf.js/issues/770)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ec6a133ff541c638517e00f47b772990207c8640) parser should not confuse previous trailing line comments with comments for the next declaration, see [#762](https://github.com/protobufjs/protobuf.js/issues/762)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0589ace4dc9e5c565ff996cf6e6bf94e63f43c4e) Types should not clear constructor with cache (fixes decorators)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/056ecc3834a3b323aaaa676957efcbe3f52365a0) Namespace#lookup should also check in nested namespaces (wtf)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ed34b093839652db2ff7b84db87857fc57d96038) Reader#bytes should also support plain arrays<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/514afcfa890aa598e93254576c4fd6062e0eff3b) Fix markdown for pipe in code in table<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/17c2797592bc4effd9aaae3ba9777c9550bb75ac) Upgrade to codegen 2<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/57d7d35ddbb9e3a28c396b4ef1ae3b150eeb8035) ext/descriptor enables interoperability between reflection and descriptor.proto (experimental), see [#757](https://github.com/protobufjs/protobuf.js/issues/757)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3939667ef1f37b025bd7f9476015890496d50e00) Added 'json' conversion option for proto3 JSON mapping compatibility of NaN and Infinity + additional documentation of util.toJSONOptions, see [#351](https://github.com/protobufjs/protobuf.js/issues/351)<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4eac28c7d3acefb0af7b82c62cf8d19bf3e7d37b) Use protobuf/minimal when pbjs target is static-module<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3a959453fe63706c38ebbacda208e1f25f27dc99) Added closure wrapper<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/13bf9c2635e6a1a2711670fc8e28ae9d7b8d1c8f) Various improvements to statically generated JSDoc, also fixes [#772](https://github.com/protobufjs/protobuf.js/issues/772)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ffdc93c7cf7c8a716316b00864ea7c510e05b0c8) Check incompatible properties for namespaces only in tsd-jsdoc<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fb3f9c70436d4f81bcd0bf62b71af4d253390e4f) Additional tsd-jsdoc handling of properties inside of namespaces and TS specific API exposure<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2dcae25c99e2ed8afd01e27d21b106633b8c31b9) Several improvements to tsd-jsdoc emitted comments<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ff858003f525db542cbb270777b6fab3a230c9bb) Further TypeScript definition improvements<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/22f907c49adbbdf09b72bde5299271dbe0ee9cbe) Relieved tsd files from unnecessary comments<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/22f907c49adbbdf09b72bde5299271dbe0ee9cbe) Generate TS namespaces for vars and functions with properties<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b355115e619c6595ac9d91897cfe628ef0e46054) Prefer @tstype over @type when generating typedefs (tsd-jsdoc)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/23f4b990375efcac2c144592cf4ca558722dcf2d) Replaced nullable types with explicit type|null for better tooling compatibility, also fixes [#766](https://github.com/protobufjs/protobuf.js/issues/766) and fixes 767<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6493f52013c92a34b8305a25068ec7b8c4c29d54) Added more info to ext/descriptor README, see [#757](https://github.com/protobufjs/protobuf.js/issues/757)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ef92da3768d8746dbfe72e77232f78b879fc811d) Additional notes on ext/descriptor<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b646cf7499791a41b75eef2de1a80fb558d4159e) Updated CHANGELOG so everyone knows what's going on (and soon, breaking)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/35a663757efe188bea552aef017837bc6c6a481a) Additional docs on TS/decorators usage<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9726be0888a9461721447677e9dece16a682b9f6) Updated dist files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9726be0888a9461721447677e9dece16a682b9f6) Added package-lock.json<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/114f7ea9fa3813003afc3ebb453b2dd2262808e1) Minor formatting<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8a6e464954b472fdbb4d46d9270fe3b4b3c7272d) Generate files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/42f8a97630bcb30d197b0f1d6cbdd96879d27f96) Remove the no-constructor arg<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6446247cd7edbb77f03dc42c557f568811286a39) Remove the ctor option.<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2059ee0f6f951575d5c5d2dc5eb06b6fa34e27aa) Add support to generate types for JSON object.<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7445da0f8cb2e450eff17723f25f366daaf3bbbb) aspromise performance pass<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3f8b74ba6726567eaf68c4d447c120f75eac042f) codegen 2 performance pass, [#653](https://github.com/protobufjs/protobuf.js/issues/653) might benefit<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d44a7eec2fd393e5cb24196fb5818c8c278a0f34) Fixed minimal library including reflection functionality<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a18e6db9f02696c66032bce7ef4c0eb0568a8048) Minor compression ratio tuning<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b49a4edd38395e209bedac2e0bfb7b9d5c4e980b) Fixed failing test case + coverage<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8f7111cacd236501b7e26791b9747b1974a2d9eb) Improved fromObject wrapper for google.protobuf.Any.<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0e471a2516bde3cd3c27b2691afa0dcfbb01f042) Fixed failing tokenize test case<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/5867f076d8510fa97e3bd6642bbe61960f7fd196) Removed debug build, made it an extension<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/22f907c49adbbdf09b72bde5299271dbe0ee9cbe) Regenerated dist files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/5bc3541d2da19e2857dc884f743d37c27e8e21f2) Even more documentation and typings for ext/descriptor<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/773e6347b57e4a5236b1ef0bb8d361e4b233caf7) ext/descriptor docs<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/773e6347b57e4a5236b1ef0bb8d361e4b233caf7) Decorators coverage<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9a23ded94729ceeea2f87cb7e8460eaaaf1c8269) ext/descriptor support for various standard options, see [#757](https://github.com/protobufjs/protobuf.js/issues/757)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2d8ce6ec0abd261f9b261a44a0a258fdf57ecec3) ext/descriptor passes descriptor.proto test with no differences, see [#757](https://github.com/protobufjs/protobuf.js/issues/757)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3a20968c6d676312e4f2a510f7e079e0e0819daf) Properly remove unnecessary (packed) options from JSON descriptors<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2a30df8bd5f20d91143a38c2232dafc3a6f3a7bd) Use typedefs in ext/descriptor (like everywhere else), see [#757](https://github.com/protobufjs/protobuf.js/issues/757)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1fc911cef01e081c04fb82ead685f49dde1403bb) Fixed obvious issues with ext/descriptor, does not throw anymore when throwing descriptor.proto itself at it, see [#757](https://github.com/protobufjs/protobuf.js/issues/757)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6c37dbd14f39dad687f2f89f1558a875f7dcc882) Added still missing root traversal to ext/descriptor, see [#757](https://github.com/protobufjs/protobuf.js/issues/757)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7ab136daa5eb2769b616b6b7522e45a4e33a59f6) Initial map fields support for ext/descriptor, see [#757](https://github.com/protobufjs/protobuf.js/issues/757)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/708552bb84508364b6e6fdf73906aa69e83854e1) Added infrastructure for TypeScript support of extensions<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/23f26defa793b371c16b5f920fbacb3fb66bdf22) TypeScript generics improvements<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e49bef863c0fb10257ec1001a3c5561755f2ec6b) More ext/descriptor progress, see [#757](https://github.com/protobufjs/protobuf.js/issues/757)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6b94336c1e6eec0f2eb1bd5dca73a7a8e71a2153) Just export the relevant namespace in ext/descriptor<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fbb99489ed0c095174feff8f53431d30fb6c34a0) Initial descriptor.proto extension for reflection interoperability, see [#757](https://github.com/protobufjs/protobuf.js/issues/757)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/48e66d975bf7b4e6bdbb68ec24386c98b16c54c5) Moved custom wrappers to its own module instead, also makes the API easier to use manually, see [#677](https://github.com/protobufjs/protobuf.js/issues/677)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0c6e639d08fdf9be12677bf678563ea631bafb2c) Added infrastructure for custom wrapping/unwrapping of special types, see [#677](https://github.com/protobufjs/protobuf.js/issues/677)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0425b584f49841d87a8249fef30c78cc31c1c742) More decorator progress (MapField.d, optional Type.d)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7a6f98b5e74f9e9142f9be3ba0683caeaff916c4) tsd-jsdoc now has limited generics support<br />
+
+## [6.7.3](https://github.com/protobufjs/protobuf.js/releases/tag/6.7.3)
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/57f1da64945f2dc5537c6eaa53e08e8fdd477b67) long, @types/long and @types/node are just dependencies, see [#753](https://github.com/protobufjs/protobuf.js/issues/753)<br />
+
+## [6.7.2](https://github.com/protobufjs/protobuf.js/releases/tag/6.7.2)
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a7621be0a56585defc72d863f4e891e476905692) Split up NamespaceDescriptor to make nested plain namespaces a thing, see [#749](https://github.com/protobufjs/protobuf.js/issues/749)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e980e72ae3d4697ef0426c8a51608d31f516a2c4) More README<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1f76749d0b9a780c7b6cb56be304f7327d74ebdb) Replaced 'runtime message' with 'message instance' for clarity<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e6b6dedb550edbd0e54e212799e42aae2f1a87f1) Rephrased the Usage section around the concept of valid messages<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0d8100ba87be768ebdec834ca2759693e0bf4325) Added toolset diagram to README<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3405ae8d1ea775c96c30d1ef5cde666c9c7341b3) Touched benchmark output metrics once more<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e36b228f4bb8b1cd835bf31f8605b759a7f1f501) Fixed failing browser test<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7b3bdb562ee7d30c1a557d7b7851d55de3091da4) Output more human friendly metrics from benchmark<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/59e447889057c4575f383630942fd308a35c12e6) Stripped down static bench code to what's necessary<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f88dad098282ece65f5d6e224ca38305a8431829) Revamped benchmark, now also covers Google's JS implementation<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/45356be81ba7796faee0d4d8ad324abdd9f301fb) Updated dependencies and dist files<br />
+
+## [6.7.1](https://github.com/protobufjs/protobuf.js/releases/tag/6.7.1)
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3d23eed6f7c79007969672f06c1a9ccd691e2411) Made .verify behave more like .encode, see [#710](https://github.com/protobufjs/protobuf.js/issues/710)<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/bed514290c105c3b606f760f2abba80510721c77) With null/undefined eliminated by constructors and .create, document message fields as non-optional where applicable (ideally used with TS & strictNullChecks), see [#743](https://github.com/protobufjs/protobuf.js/issues/743)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/007b2329842679ddf994df7ec0f9c70e73ee3caf) Renamed --strict-long/message to --force-long/message with backward compatible aliases, see [#741](https://github.com/protobufjs/protobuf.js/issues/741)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6aae71f75e82ffd899869b0c952daf98991421b8) Keep $Properties with --strict-message but require actual instances within, see [#741](https://github.com/protobufjs/protobuf.js/issues/741)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c812cef0eff26998f14c9d58d4486464ad7b2bbc) Added --strict-message option to pbjs to strictly reference message instances instead of $Properties, see [#741](https://github.com/protobufjs/protobuf.js/issues/741)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/412407de9afb7ec3a999c4c9a3a1f388f971fce7) Restructured README<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1c4d9d7f024bfa096ddc24aabbdf39211ed8637a) Added more information on typings usage, see [#744](https://github.com/protobufjs/protobuf.js/issues/744)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/602065e16862751c515c2f3391ee8b880e8140b1) Clarified typescript example in README, see [#744](https://github.com/protobufjs/protobuf.js/issues/744)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/79d0ba2cc71a156910a9d937683af164df694f08) Clarified that the service API targets clients consuming a service, see [#742](https://github.com/protobufjs/protobuf.js/issues/742)<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a66f76452ba050088efd1aaebf3c503a55e6287c) Omit copying of undefined or null in constructors and .create, see [#743](https://github.com/protobufjs/protobuf.js/issues/743)<br />
+
+## [6.7.0](https://github.com/protobufjs/protobuf.js/releases/tag/6.7.0)
+
+### Breaking
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9c1bbf10e445c3495b23a354f9cbee951b4b20f0) Namespace#lookupEnum should actually look up the reflected enum and not just its values<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/44a8d3af5da578c2e6bbe0a1b948d469bbe27ca1) Decoder now throws if required fields are missing, see [#695](https://github.com/protobufjs/protobuf.js/issues/695) / [#696](https://github.com/protobufjs/protobuf.js/issues/696)<br />
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d1e3122e326480fdd44e96afd76ee72e9744b246) Added functionality to filter for multiple types at once in lookup(), used by lookupTypeOrEnum(), fixes [#740](https://github.com/protobufjs/protobuf.js/issues/740)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8aa21268aa5e0f568cb39e99a83b99ccb4084381) Ensure that fields have been resolved when looking up js types in static target, see [#731](https://github.com/protobufjs/protobuf.js/issues/731)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f755d36829b9f1effd7960fab3a86a141aeb9fea) Properly copy fields array before sorting in toObject, fixes [#729](https://github.com/protobufjs/protobuf.js/issues/729)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a06691f5b87f7e90fed0115b78ce6febc4479206) Actually emit TS compatible enums in static target if not aliases, see [#720](https://github.com/protobufjs/protobuf.js/issues/720)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b01bb58dec92ebf6950846d9b8d8e3df5442b15d) Hardened tokenize/parse, esp. comment parsing, see [#713](https://github.com/protobufjs/protobuf.js/issues/713)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/bc76ad732fc0689cb0a2aeeb91b06ec5331d7972) Exclude any fields part of some oneof when populating defaults in toObject, see [#710](https://github.com/protobufjs/protobuf.js/issues/710)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/68cdb5f11fdbb950623be089f98e1356cb7b1ea3) Most of the parser is not case insensitive, see [#705](https://github.com/protobufjs/protobuf.js/issues/705)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3e930b907a834a7da759478b8d3f52fef1da22d8) Retain options argument in Root#load when used with promises, see [#684](https://github.com/protobufjs/protobuf.js/issues/684)<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3c14ef42b3c8f2fef2d96d65d6e288211f86c9ef) Created a micromodule from (currently still bundled) float support<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7ecae9e9f2e1324ef72bf5073463e01deff50cd6) util.isset(obj, prop) can be used to test if a message property is considered to be set, see [#728](https://github.com/protobufjs/protobuf.js/issues/728)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c04d4a5ab8f91899bd3e1b17fe4407370ef8abb7) Implemented stubs for long.js / node buffers to be used where either one isn't wanted, see [#718](https://github.com/protobufjs/protobuf.js/issues/718)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b9574ad02521a31ebd509cdaa269e7807da78d7c) Simplified reusing / replacing internal constructors<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1f97b7af05b49ef69bd6e9d54906d1b7583f42c4) Constructors/.create always initialize proper mutable objects/arrays, see [#700](https://github.com/protobufjs/protobuf.js/issues/700)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/adb4bb001a894dd8d00bcfe03457497eb994f6ba) Verifiers return an error if multiple fields part of the same oneof are set, see [#710](https://github.com/protobufjs/protobuf.js/issues/710)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fe93d436b430d01b563318bff591e0dd408c06a4) Added `oneofs: true` to ConversionOptions, see [#710](https://github.com/protobufjs/protobuf.js/issues/710)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/228c882410d47a26576f839b15f1601e8aa7914d) Optional fields handle null just like undefined regardless of type see [#709](https://github.com/protobufjs/protobuf.js/issues/709)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/da6af8138afa5343a47c12a8beedb99889c0dd51) Encoders no longer examine virtual oneof properties but encode whatever is present, see [#710](https://github.com/protobufjs/protobuf.js/issues/710)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ac26a7aa60359a37dbddaad139c0134b592b3325) pbjs now generates multiple exports when using ES6 syntax, see [#686](https://github.com/protobufjs/protobuf.js/issues/686)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c1ca65dc6987384af6f9fac2fbd7700fcf5765b2) Sequentially serialize fields ordered by id, as of the spec.<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/26d9fadb21a85ca0b5609156c26453ae875e4933) decode throws specific ProtocolError with a reference to the so far decoded message if required fields are missing + example<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2b5577b238a452ae86aa395fb2ad3a3f45d755dc) Reader.create asserts that `buffer` is a valid buffer, see [#695](https://github.com/protobufjs/protobuf.js/issues/695)<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6f74d30f059e33a4678f28e7a50dc4878c54bed2) Exclude JSDoc on typedefs from generated d.ts files because typescript@next, see [#737](https://github.com/protobufjs/protobuf.js/issues/737)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2ebb1b781812e77de914cd260e7ab69612ffd99e) Prepare static code with estraverse instead of regular expressions, see [#732](https://github.com/protobufjs/protobuf.js/issues/732)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/29ce6cae0cacc0f1d87ca47e64be6a81325aaa55) Moved tsd-jsdoc to future cli package, see [#716](https://github.com/protobufjs/protobuf.js/issues/716)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8de21e1a947ddb50a167147dd63ad29d37b6a891) $Properties are just a type that's satisfied, not implemented, by classes, see [#723](https://github.com/protobufjs/protobuf.js/issues/723)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4bfe0c239b9c337f8fa64ea64f6a71baf5639b84) More progress on decoupling the CLI<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8a60174932d15198883ac3f07000ab4e7179a695) Fixed computed array indexes not being renamed in static code, see [#726](https://github.com/protobufjs/protobuf.js/issues/726)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8d9981588d17709791846de63f1f3bfd09433b03) Check upfront if key-var is required in static decoders with maps, see [#726](https://github.com/protobufjs/protobuf.js/issues/726)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/16adff0c7b67c69a2133b6aac375365c5f2bdbf7) Fixed handling of stdout if callback is specified, see [#724](https://github.com/protobufjs/protobuf.js/issues/724)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6423a419fe45e648593833bf535ba1736b31ef63) Preparations for moving the CLI to its own package, see [#716](https://github.com/protobufjs/protobuf.js/issues/716)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/afefa3de09620f50346bdcfa04d52952824c3c8d) Properly implement $Properties interface in JSDoc, see [#723](https://github.com/protobufjs/protobuf.js/issues/723)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a1f23e09fb5635275bb7646dfafc70caef74c6b8) Recursively use $Properties inside of $Properties in static code, see [#717](https://github.com/protobufjs/protobuf.js/issues/717)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c3f0a2124c661bb9ba35f92c21a98a4405d30b47) Added --strict-long option to pbjs to always emit 'Long' instead of 'number|Long' (only relevant with long.js), see [#718](https://github.com/protobufjs/protobuf.js/issues/718)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0bc4a14501f84f93afd6ce2933ad00749c82f4df) Statically emitted long type is 'Long' now instead of '$protobuf.Long', see [#718](https://github.com/protobufjs/protobuf.js/issues/718)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a75625d176b7478e0e506f05e2cee5e3d7a0d89a) Decoupled message properties as an interface in static code for TS intellisense support, see [#717](https://github.com/protobufjs/protobuf.js/issues/717)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/23f14a61e8c2f68b06d1bb4ed20b938764c78860) Static code statically resolves types[..], see [#715](https://github.com/protobufjs/protobuf.js/issues/715)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ef71e77726b6bf5978b948d598c18bf8b237ade4) Added type definitions for all possible JSON descriptors<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4bfe0c239b9c337f8fa64ea64f6a71baf5639b84) Explained the JSON structure in README and moved CLI specific information to the CLI package<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3ba3ad762f7486b4806ad1c45764e92a81ca24dd) Added information on how to use the stubs to README, see [#718](https://github.com/protobufjs/protobuf.js/issues/718)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a5dbba41341bf44876cd4226f08044f88148f37d) Added 'What is a valid message' section to README<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6f8f2c1fdf92e6f81363d77bc059820b2376fe32) Added a hint on using .create to initial example<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3ad28ec920e0fe8d0223db28804a7b3f8a6880c2) Even more usage for README<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/5a1f861a0f6b582faae7a4cc5c6ca7e4418086da) Additional information on general usage (README)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/320dea5a1d1387c72759e10a17afd77dc48c3de0) Restructured README to Installation, Usage and Examples sections<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1c9055dd69f7696d2582942b307a1ac8ac0f5533) Added a longish section on the correct use of the toolset to README<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/99667c8e1ff0fd3dac83ce8c0cff5d0b1e347310) Added a few additional notes on core methods to README, see [#710](https://github.com/protobufjs/protobuf.js/issues/710)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2130bc97e44567e766ea8efacb365383c909dbd4) Extended traverse-types example, see [#693](https://github.com/protobufjs/protobuf.js/issues/693)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/13e4aa3ff274ab42f1302e16fd59d074c5587b5b) Better explain how .verify, .encode and .decode are connected<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7502dd2dfdaea111e5c1a902c524ad0a51ff9bd4) Documented that Type#encode respectively Message.encode do not implicitly .verify, see [#696](https://github.com/protobufjs/protobuf.js/issues/696) [ci-skip]<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e7e123aa0b6c05eb4156a761739e37c008a3cbc1) Documented throwing behavior of Reader.create and Message.decode<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0fcde32306da77f02cb1ea81ed18a32cee01f17b) Added error handling notes to README, see [#696](https://github.com/protobufjs/protobuf.js/issues/696)<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fef924e5f708f14dac5713aedc484535d36bfb47) Use @protobufjs/float<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fef924e5f708f14dac5713aedc484535d36bfb47) Rebuilt dist files for 6.7.0<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ca0dce2d7f34cd45e4c1cc753a97c58e05b3b9d2) Updated deps, ts fixes and regenerated dist files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2c2d4002d6776f3edde608bd813c37d798d87e6b) Manually merged gentests improvements, fixes [#733](https://github.com/protobufjs/protobuf.js/issues/733)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e4a6b6f81fa492a63b12f0da0c381612deff1973) Make sure that util.Long is overridden by AMD loaders only if present, see [#730](https://github.com/protobufjs/protobuf.js/issues/730)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fff1eb297a728ed6d334c591e7d796636859aa9a) Coverage for util.isset and service as a namespace<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8401a47d030214a54b5ee30426ebc7a9d9c3773d) Shortened !== undefined && !== null to equivalent != null in static code<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e1dd1bc2667de73bb65d876162131be2a4d9fef4) With stubs in place, 'number|Long' return values can be just 'Long' instead, see [#718](https://github.com/protobufjs/protobuf.js/issues/718)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/404ba8e03a63f708a70a72f0208e0ca9826fe20b) Just alias as the actual ideal type when using stubs, see [#718](https://github.com/protobufjs/protobuf.js/issues/718)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/270cc94c7c4b8ad84d19498672bfc854b55130c9) General cleanup + regenerated dist/test files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/017161ce97ceef3b2d0ce648651a4636f187d78b) Simplified camel case regex, see [#714](https://github.com/protobufjs/protobuf.js/issues/714)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d410fd20f35d2a35eb314783b17b6570a40a99e8) Regenerated dist files and changelog for 6.7.0<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/88ca8f0d1eb334646ca2625c78e63fdd57221408) Retain alias order in static code for what it's worth, see [#712](https://github.com/protobufjs/protobuf.js/issues/712)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2a74fbf551e934b3212273e6a28ad65ac4436faf) Everything can be block- or line-style when parsing, see [#713](https://github.com/protobufjs/protobuf.js/issues/713)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/47bb95a31784b935b9ced52aa773b9d66236105e) Determine necessary aliases depending on config, see [#712](https://github.com/protobufjs/protobuf.js/issues/712)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/588ffd9b129869de0abcef1d69bfa18f2f25d8e1) Use more precise types for message-like plain objects<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/37b39c8d1a5307eea09aa24d7fd9233a8df5b7b6) Regenerated dist files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9c94813f9a5f1eb114d7c6112f7e87cb116fe9da) Regenerated relevant files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d7493efe1a86a60f6cdcf7976523e69523d3f7a3) Moved field comparer to util<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fe917652f88df17d4dbaae1cd74f470385342be2) Updated tests to use new simplified encoder logic<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b69173b4e7b514c40bb4a85b54ca5465492a235b) Updated path to tsd-jsdoc template used by pbts, see [#707](https://github.com/protobufjs/protobuf.js/issues/707)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/5041fad9defdb0bc8131560e92f3b454d8e45273) Additional restructuring for moving configuration files out of the root folder<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c0b7c9fa6309d345c4ce8e06fd86f27528f4ea66) Added codegen support for constructor functions, see [#700](https://github.com/protobufjs/protobuf.js/issues/700)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4573f9aabd7e8f883e530f4d0b055e5ec9b75219) Attempted to fix broken custom error test<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4b49f500fce156b164c757d8f17be2338f767c82) Trying out a more aggressive aproach for custom error subclasses<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/95cd64ee514dc60d10daac5180726ff39594e8e8) Moved a few things out of the root folder<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/db1030ed257f9699a0bcf3bad0bbe8acccf5d766) Coverage for encoder compat. / protocolerror<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/948a4caf5092453fa091ac7a594ccd1cc5b503d2) Updated dist and generated test files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3ead13e83ecdc8715fbab916f7ccaf3fbfdf59ed) Added tslint<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/364e7d457ed4c11328e609f600a57b7bc4888554) Exclude dist/ from codeclimate checks<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6e81fcb05f25386e3997399e6596e9d9414f0286) Also lint cli utilities<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e7e123aa0b6c05eb4156a761739e37c008a3cbc1) Cache any regexp instance (perf)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d89c45f8af0293fb34e6f12b37ceca49083e1faa) Use code climate badges<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e70fbe3492c37f009dbaccf910c1e0f81e8f0f44) Updated travis to pipe to codeclimate, coverage<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a7ab1036906bb7638193a9e991cb62c86108880a) More precise linter configuration<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/58688c178257051ceb2dfea8a63eb6be7dcf1cf1) Added codeclimate<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4b21e00adc6fae42e6a88deaeb0b7c077c6ca50e) Moved cli deps placeholder creation to post install script<br />
+
+## [6.6.5](https://github.com/protobufjs/protobuf.js/releases/tag/6.6.5)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/478ee51194878f24be8607e42e5259952607bd44) sfixed64 is not zig-zag encoded, see [#692](https://github.com/protobufjs/protobuf.js/issues/692)<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7a944538c89492abbed147915acea611f11c03a2) Added a placeholder to cli deps node_modules folder to make sure node can load from it<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/83142e420eb1167b2162063a092ae8d89c9dd4b2) Restructured a few failing tests<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/367d55523a3ae88f21d47aa96447ec3e943d4620) Traversal example + minimalistic documentation<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8eeffcbcd027c929e2a76accad588c61dfa2e37c) Added a custom getters/setters example for gRPC<br />
+
+## [6.6.4](https://github.com/protobufjs/protobuf.js/releases/tag/6.6.4)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/88eb7a603a21643d5012a374c7d246f4c27620f3) Made sure that LongBits ctor is always called with unsigned 32 bits + static codegen compat., fixes [#690](https://github.com/protobufjs/protobuf.js/issues/690)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/50e82fa7759be035a67c7818a1e3ebe0d6f453b6) Properly handle multiple ../.. in path.normalize, see [#688](https://github.com/protobufjs/protobuf.js/issues/688)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7c3506b3f0c5a08a887e97313828af0c21effc61) Post-merge, also tackles [#683](https://github.com/protobufjs/protobuf.js/issues/683) (packed option for repeated enum values)<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7f3f4600bcae6f2e4dadd5cdb055886193a539b7) Verify accepts non-null objects only, see [#685](https://github.com/protobufjs/protobuf.js/issues/685)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d65c22936183d04014d6a8eb880ae0ec33aeba6d) allow_alias enum option was not being honored. This case is now handled and a test case was added<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2ddb76b6e93174787a68f68fb28d26b8ece7cc56) Added an experimental --sparse option to limit pbjs output to actually referenced types within main files<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/33d14c97600ed954193301aecbf8492076dd0179) Added explicit hint on Uint8Array to initial example, see [#670](https://github.com/protobufjs/protobuf.js/issues/670)<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/cbd4c622912688b47658fea00fd53603049b5104) Ranges and names support for reserved fields, see [#676](https://github.com/protobufjs/protobuf.js/issues/676)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/487f8922d879955ba22f89b036f897b9753b0355) Updated depdendencies / rebuilt dist files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/37536e5fa7a15fbc851040e09beb465bc22d9cf3) Use ?: instead of |undefined in .d.ts files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f8b415a2fc2d1b1eff19333600a010bcaaebf890) Mark optional fields as possibly being undefined<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2ddb76b6e93174787a68f68fb28d26b8ece7cc56) Added a few more common google types from google/api, see [#433](https://github.com/protobufjs/protobuf.js/issues/433)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d246024f4c7d13ca970c91a757e2f47432a619df) Minor optimizations to dependencies, build process and tsd<br />
+
+## [6.6.3](https://github.com/protobufjs/protobuf.js/releases/tag/6.6.3)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0be01a14915e3e510038808fedbc67192a182d9b) Support node 4.2.0 to 4.4.7 buffers + travis case, see [#665](https://github.com/protobufjs/protobuf.js/issues/665)<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6a0920b2c32e7963741693f5a773b89f4b262688) Added ES6 syntax flag to pbjs, see [#667](https://github.com/protobufjs/protobuf.js/issues/667)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c365242bdc28a47f5c6ab91bae34c277d1044eb3) Reference Buffer for BufferReader/Writer, see [#668](https://github.com/protobufjs/protobuf.js/issues/668)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/43976072d13bb760a0689b54cc35bdea6817ca0d) Slightly shortened README<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e64cf65b09047755899ec2330ca0fc2f4d7932c2) Additional notes on the distinction of different use cases / distributions, see [#666](https://github.com/protobufjs/protobuf.js/issues/666)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/83758c99275c2bbd30f63ea1661284578f5c9d91) Extended README with additional information on JSON format<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fdc3102689e8a3e8345eee5ead07ba3c9c3fe80c) Added extended usage instructions for TypeScript and custom classes to README, see [#666](https://github.com/protobufjs/protobuf.js/issues/666)<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3701488cca6bc56ce6b7ad93c7b80e16de2571a7) Updated dist files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/579068a45e285c7d2c69b359716dd6870352f46f) Updated test cases to use new buffer util<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0be01a14915e3e510038808fedbc67192a182d9b) Added fetch test cases + some test cleanup<br />
+
+## [6.6.2](https://github.com/protobufjs/protobuf.js/releases/tag/6.6.2)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3aea1bf3d4920dc01603fda25b86e6436ae45ec2) Properly replace short vars when beautifying static code, see [#663](https://github.com/protobufjs/protobuf.js/issues/663)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b6cf228a82152f72f21b1b307983126395313470) Use custom prelude in order to exclude any module loader code from source (for webpack), see [#658](https://github.com/protobufjs/protobuf.js/issues/658)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2b12fb7db9d4eaa3b76b7198539946e97db684c4) Make sure to check optional inner messages for null when encoding, see [#658](https://github.com/protobufjs/protobuf.js/issues/658)<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/276a594771329da8334984771cb536de7322d5b4) Initial attempt on a backwards compatible fetch implementation with binary support, see [#661](https://github.com/protobufjs/protobuf.js/issues/661)<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2d81864fa5c4dac75913456d582e0bea9cf0dd80) Root#resolvePath skips files when returning null, see [#368](https://github.com/protobufjs/protobuf.js/issues/368)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/aab3ec1a757aff0f11402c3fb943c003f092c1af) Changes callback on failed response decode in rpc service to pass actual error instead of 'error' string<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9044178c052299670108f10621d6e9b3d56e8a40) Travis should exit with the respective error when running sauce tests<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/73721f12072d77263e72a3b27cd5cf9409db9f8b) Moved checks whether a test case is applicable to parent case<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3fcd88c3f9b1a084b06cab2d5881cb5bb895869d) Added eventemitter tests and updated micromodule dependencies (so far)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2db4305ca67d003d57aa14eb23f25eb6c3672034) Added lib/path tests and updated a few dependencies<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2b12fb7db9d4eaa3b76b7198539946e97db684c4) Moved micro modules to lib so they can have their own tests etc.<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b6dfa9f0a4c899b5c217d60d1c2bb835e06b2122) Updated travis<br />
+
+## [6.6.1](https://github.com/protobufjs/protobuf.js/releases/tag/6.6.1)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/039ac77b062ee6ebf4ec84a5e6c6ece221e63401) Properly set up reflection when using light build<br />
+
+## [6.6.0](https://github.com/protobufjs/protobuf.js/releases/tag/6.6.0) ([release](https://github.com/protobufjs/protobuf.js/releases/tag/6.6.0))
+
+### Breaking
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/cdfe6bfba27fa1a1d0e61887597ad4bb16d7e5ed) Inlined / refactored away .testJSON, see [#653](https://github.com/protobufjs/protobuf.js/issues/653)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6a483a529ef9345ed217a23394a136db0d9f7771) Refactored util.extend away<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/27b16351f3286468e539c2ab382de4b52667cf5e) Reflected and statically generated services use common utility, now work exactly the same<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/dca26badfb843a597f81e98738e2fda3f66c7341) fromObject now throws for entirely bogus values (repeated, map and inner message fields), fixes [#601](https://github.com/protobufjs/protobuf.js/issues/601)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4bff9c356ef5c10b4aa34d1921a3b513e03dbb3d) Cleaned up library distributions, now is full / light / minimal with proper browserify support for each<br />
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/301f7762ef724229cd1df51e496eed8cfd2f10eb) Do not randomly remove slashes from comments, fixes [#656](https://github.com/protobufjs/protobuf.js/issues/656)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ef7be352baaec26bdcdce01a71fbee47bbdeec15) Properly parse nested textformat options, also tackles [#655](https://github.com/protobufjs/protobuf.js/issues/655)<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b4f4f48f1949876ae92808b0a5ca5f2b29cc011c) Relieved the requirement to call .resolveAll() on roots in order to populate static code-compatible properties, see [#653](https://github.com/protobufjs/protobuf.js/issues/653)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/56c8ec4196d461383c3e1f271da02553d877ae81) Added a (highly experimental) debug build as a starting point for [#653](https://github.com/protobufjs/protobuf.js/issues/653)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c5d291f9bab045385c5938ba0f6cdf50a315461f) Full build depends on light build depends on minimal build, shares all relevant code<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/735da4315a98a6960f3b5089115e308548b91c07) Also reuse specified root in pbjs for JSON modules, see [#653](https://github.com/protobufjs/protobuf.js/issues/653)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3a056244d3acf339722d56549469a8df018e682e) Reuse specified root name in pbjs to be able to split definitions over multiple files more easily, see [#653](https://github.com/protobufjs/protobuf.js/issues/653)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/28ddf756ab83cc890761ef2bd84a0788d2ad040d) Improved pbjs/pbts examples, better covers reflection with definitions for static modules<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6f0b44aea6cf72d23042810f05a7cede85239eb3) Fixed centered formatting on npm<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/dd96dcdacb8eae94942f7016b8dc37a2569fe420) Various other minor improvements / assertions refactored away, see [#653](https://github.com/protobufjs/protobuf.js/issues/653)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3317a76fb56b9b31bb07ad672d6bdda94b79b6c3) Fixed some common reflection deopt sites, see [#653](https://github.com/protobufjs/protobuf.js/issues/653)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6a483a529ef9345ed217a23394a136db0d9f7771) Reflection performance pass, see [#653](https://github.com/protobufjs/protobuf.js/issues/653)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6a483a529ef9345ed217a23394a136db0d9f7771) Added TS definitions to alternative builds' index files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6a483a529ef9345ed217a23394a136db0d9f7771) Removed unnecessary prototype aliases, improves gzip ratio<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/641625fd64aca55b1163845e6787b58054ac36ec) Unified behaviour of and docs on Class constructor / Class.create<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7299929b37267af2100237d4f8b4ed8610b9f7e1) Statically generated services actually inherit from rpc.Service<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f4cf75e4e4192910b52dd5864a32ee138bd4e508) Do not try to run sauce tests for PRs<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/33da148e2b750ce06591c1c66ce4c46ccecc3c8f) Added utility to enable/disable debugging extensions to experimental debug build<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fdb1a729ae5f8ab762c51699bc4bb721102ef0c8) Fixed node 0.12 tests<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6bc5bb4a7649d6b91a5944a9ae20178d004c8856) Fixed coverage<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6f0b44aea6cf72d23042810f05a7cede85239eb3) Added a test case for [#652](https://github.com/protobufjs/protobuf.js/issues/652)<br />
+
+## [6.5.3](https://github.com/protobufjs/protobuf.js/releases/tag/6.5.3)
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/799d0303bf289bb720f2b27af59e44c3197f3fb7) In fromObject, check if object is already a runtime message, see [#652](https://github.com/protobufjs/protobuf.js/issues/652)<br />
+
+## [6.5.2](https://github.com/protobufjs/protobuf.js/releases/tag/6.5.2)
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8cff92fe3b7ddb1930371edb4937cd0db9216e52) Added coverage reporting<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/cbaaae99b4e39a859664df0e6d20f0491169f489) Added version scheme warning to everything CLI so that we don't need this overly explicit in README<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6877b3399f1a4c33568221bffb4e298b01b14439) Coverage progress, 100%<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/711a9eb55cb796ec1e51af7d56ef2ebbd5903063) Coverage progress<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e7526283ee4dd82231235afefbfad6af54ba8970) Attempted to fix badges once and for all<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/5aa296c901c2b460ee3be4530ede394e2a45e0ea) Coverage progress<br />
+
+## [6.5.1](https://github.com/protobufjs/protobuf.js/releases/tag/6.5.1)
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9719fd2fa8fd97899c54712a238091e8fd1c57b2) Reuse module paths when looking up cli dependencies, see [#648](https://github.com/protobufjs/protobuf.js/issues/648)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6302655d1304cf662f556be5d9fe7a016fcedc3c) Check actual module directories to determine if cli dependencies are present and bootstrap semver, see [#648](https://github.com/protobufjs/protobuf.js/issues/648)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/dfc7c4323bf98fb26ddcfcfbb6896a6d6e8450a4) Added a note on semver-incompatibility, see [#649](https://github.com/protobufjs/protobuf.js/issues/649)<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/49053ffa0ea8a4ba5ae048706dba1ab6f3bc803b) Coverage progress<br />
+
+## [6.5.0](https://github.com/protobufjs/protobuf.js/releases/tag/6.5.0) ([release](https://github.com/protobufjs/protobuf.js/releases/tag/6.5.0))
+
+### Breaking
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3946e0fefea415f52a16ea7a74109ff40eee9643) Initial upgrade of converters to real generated functions, see [#620](https://github.com/protobufjs/protobuf.js/issues/620)<br />
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/08cda241a3e095f3123f8a991bfd80aa3eae9400) An enum's default value present as a string looks up using typeDefault, not defaultValue which is an array if repeated<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c7e14b1d684aaba2080195cc83900288c5019bbc) Use common utility for virtual oneof getters and setters in both reflection and static code, see [#644](https://github.com/protobufjs/protobuf.js/issues/644)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/508984b7ff9529906be282375d36fdbada66b8e6) Properly use Type.toObject/Message.toObject within converters, see [#641](https://github.com/protobufjs/protobuf.js/issues/641)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/5bca18f2d32e8687986e23edade7c2aeb6b6bac1) Generate null/undefined assertion in fromObject if actually NOT an enum, see [#620](https://github.com/protobufjs/protobuf.js/issues/620)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/508984b7ff9529906be282375d36fdbada66b8e6) Replace ALL occurencies of types[%d].values in static code, see [#641](https://github.com/protobufjs/protobuf.js/issues/641)<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9b090bb1673aeb9b8f1d7162316fce4d7a3348f0) Switched to own property-aware encoders for compatibility, see [#639](https://github.com/protobufjs/protobuf.js/issues/639)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/340d6aa82ac17c4a761c681fa71d5a0955032c8b) Now also parses comments, sets them on reflected objects and re-uses them when generating static code, see [#640](https://github.com/protobufjs/protobuf.js/issues/640)<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3cb82628159db4d2aa721b63619b16aadc5f1981) Further improved generated static code style<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/cda5c5452fa0797f1e4c375471aef96f844711f1) Removed scoping iifes from generated static code<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/def7b45fb9b5e01028cfa3bf2ecd8272575feb4d) Removed even more clutter from generated static code<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/dbd19fd9d3a57d033aad1d7173f7f66db8f8db3e) Removed various clutter from generated static code<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1cc8a2460c7e161c9bc58fa441ec88e752df409c) Made sure that static target's replacement regexes don't match fields<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d4272dbf5d0b2577af8efb74a94d246e2e0d728e) Also accept (trailing) triple-slash comments for compatibility with protoc-gen-doc, see [#640](https://github.com/protobufjs/protobuf.js/issues/640)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0a3862b75fa60ef732e0cd36d623f025acc2fb45) Use semver to validate that CLI dependencies actually satisfy the required version, see [#637](https://github.com/protobufjs/protobuf.js/issues/637)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9e360ea6a74d41307483e51f18769df7f5b047b9) Added a hint on documenting .proto files for static code<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d2a97bb818474645cf7ce1832952b2c3c739b234) Documented internally used codegen partials for what it's worth<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/079388ca65dfd581d74188a6ae49cfa01b103809) Updated converter documentation<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/168e448dba723d98be05c55dd24769dfe3f43d35) Bundler provides useful stuff to uglify and a global var without extra bloat<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/32e0529387ef97182ad0b9ae135fd8b883ed66b4) Cleaned and categorized tests, coverage progress<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3325e86930a3cb70358c689cb3016c1be991628f) Properly removed builtins from bundle<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2c94b641fc5700c8781ac0b9fe796debac8d6893) Call hasOwnProperty builtin as late as possible decreasing the probability of having to call it at all (perf)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/818bcacde267be70a75e689f480a3caad6f80cf7) Slightly hardened codegen sprintf<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/818bcacde267be70a75e689f480a3caad6f80cf7) Significantly improved uint32 write performance<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b5daa272407cb31945fd38c34bbef7c9edd1db1c) Cleaned up test case data and removed unused files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c280a4a18c6d81c3468177b2ea58ae3bc4f25e73) Removed now useless trailing comment checks, see [#640](https://github.com/protobufjs/protobuf.js/issues/640)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/44167db494c49d9e4b561a66ad9ce2d8ed865a21) Ensured that pbjs' beautify does not break regular expressions in generated verify functions<br />
+
+## [6.4.6](https://github.com/protobufjs/protobuf.js/releases/tag/6.4.6)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e11012ce047e8b231ba7d8cc896b8e3a88bcb902) Case-sensitively test for legacy group definitions, fixes [#638](https://github.com/protobufjs/protobuf.js/issues/638)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7e57f4cdd284f886b936511b213a6468e4ddcdce) Properly parse text format options + simple test case, fixes [#636](https://github.com/protobufjs/protobuf.js/issues/636)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fe4d97bbc4d33ce94352dde62ddcd44ead02d7ad) Added SVG logo, see [#629](https://github.com/protobufjs/protobuf.js/issues/629)<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/57990f7ed8ad5c512c28ad040908cee23bbf2aa8) Also refactored Service and Type to inherit from NamespaceBase, see [#635](https://github.com/protobufjs/protobuf.js/issues/635)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fe4d97bbc4d33ce94352dde62ddcd44ead02d7ad) Moved TS-compatible Namespace features to a virtual NamespaceBase class, compiles with strictNullChecks by default now, see [#635](https://github.com/protobufjs/protobuf.js/issues/635)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fe4d97bbc4d33ce94352dde62ddcd44ead02d7ad) Minor codegen enhancements<br />
+
+## [6.4.5](https://github.com/protobufjs/protobuf.js/releases/tag/6.4.5)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1154ce0867306e810cf62a5b41bdb0b765aa8ff3) Properly handle empty/noop Writer#ldelim, fixes [#625](https://github.com/protobufjs/protobuf.js/issues/625)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f303049f92c53970619375653be46fbb4e3b7d78) Properly annotate map fields in pbjs, fixes [#624](https://github.com/protobufjs/protobuf.js/issues/624)<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4b786282a906387e071a5a28e4842a46df588c7d) Made sure that Writer#bytes is always able to handle plain arrays<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1e6a8d10f291a16631376dd85d5dd385937e6a55) Slightly restructured utility to better support static code default values<br />
+
+## [6.4.4](https://github.com/protobufjs/protobuf.js/releases/tag/6.4.4)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/26d68e36e438b590589e5beaec418c63b8f939cf) Dynamically resolve jsdoc when running pbts, fixes [#622](https://github.com/protobufjs/protobuf.js/issues/622)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/69c04d7d374e70337352cec9b445301cd7fe60d6) Explain 6.4.2 vs 6.4.3 in changelog<br />
+
+## [6.4.3](https://github.com/protobufjs/protobuf.js/releases/tag/6.4.4)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c2c39fc7cec5634ecd1fbaebbe199bf097269097) Fixed invalid definition of Field#packed property, also introduced decoder.compat mode (packed fields, on by default)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/11fb1a66ae31af675d0d9ce0240cd8e920ae75e7) Always decode packed/non-packed based on wire format only, see [#602](https://github.com/protobufjs/protobuf.js/issues/602)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c9a61e574f5a2b06f6b15b14c0c0ff56f8381d1f) Use full library for JSON modules and runtime dependency for static modules, fixes [#621](https://github.com/protobufjs/protobuf.js/issues/621)<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e88d13ca7ee971451b57d056f747215f37dfd3d7) Additional workarounds for on demand CLI dependencies, see [#618](https://github.com/protobufjs/protobuf.js/issues/618)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/44f6357557ab3d881310024342bcc1e0d336a20c) Revised automatic setup of cli dependencies, see [#618](https://github.com/protobufjs/protobuf.js/issues/618)<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e027a3c7855368837e477ce074ac65f191bf774a) Removed Android 4.0 test (no longer supported by sauce)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8ba3c5efd182bc80fc36f9d5fe5e2b615b358236) Removed some unused utility, slightly more efficient codegen, additional comments<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f22a34a071753bca416732ec4d01892263f543fb) Updated tests for new package.json layout<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f22a34a071753bca416732ec4d01892263f543fb) Added break/continue label support to codegen<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f2ffa0731aea7c431c59e452e0f74247d815a352) Updated dependencies, rebuilt dist files and changed logo to use an absolute url<br />
+
+6.4.2 had been accidentally published as 6.4.3.
+
+## [6.4.1](https://github.com/protobufjs/protobuf.js/releases/tag/6.4.1)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9035d4872e32d6402c8e4d8c915d4f24d5192ea9) Added more default value checks to converter, fixes [#616](https://github.com/protobufjs/protobuf.js/issues/616)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/62eef58aa3b002115ebded0fa58acc770cd4e4f4) Respect long defaults in converters<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e3170a160079a3a7a99997a2661cdf654cb69e24) Convert inner messages and undefined/null values more thoroughly, fixes [#615](https://github.com/protobufjs/protobuf.js/issues/615)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b52089efcb9827537012bebe83d1a15738e214f4) Always use first defined enum value as field default, fixes [#613](https://github.com/protobufjs/protobuf.js/issues/613)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/64f95f9fa1bbe42717d261aeec5c16d1a7aedcfb) Install correct 'tmp' dependency when running pbts without dev dependencies installed, fixes [#612](https://github.com/protobufjs/protobuf.js/issues/612)<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/cba46c389ed56737184e5bc2bcce07243d52e5ce) Generate named constructors for runtime messages, see [#588](https://github.com/protobufjs/protobuf.js/issues/588)<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ee20b81f9451c56dc106177bbf9758840b99d0f8) pbjs/pbts no longer generate any volatile headers, see [#614](https://github.com/protobufjs/protobuf.js/issues/614)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ec9d517d0b87ebe489f02097c2fc8005fae38904) Attempted to make broken shields less annoying<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/5cd4c2f2a94bc3c0f2c580040bce28dd42eaccec) Updated README<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0643f93f5c0d96ed0ece5b47f54993ac3a827f1b) Some cleanup and added a logo<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/169638382de9efe35a1079c5f2045c33b858059a) use $protobuf.Long<br />
+
+## [6.4.0](https://github.com/protobufjs/protobuf.js/releases/tag/6.4.0) ([release](https://github.com/protobufjs/protobuf.js/releases/tag/6.4.0))
+
+### Breaking
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a017bf8a2dbdb7f9e7ce4c026bb6845174feb3b1) Dropped IE8 support<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/39bc1031bb502f8b677b3736dd283736ea4d92c1) Removed now unused util.longNeq which was used by early static code<br />
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/5915ff972482e7db2a73629244ab8a93685b2e55) Do not swallow errors in loadSync, also accept negative enum values in Enum#add, fixes [#609](https://github.com/protobufjs/protobuf.js/issues/609)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fde56c0de69b480343931264a01a1ead1e3156ec) Improved bytes field support, also fixes [#606](https://github.com/protobufjs/protobuf.js/issues/606)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0c03f327115d57c4cd5eea3a9a1fad672ed6bd44) Fall back to browser Reader when passing an Uint8Array under node, fixes [#605](https://github.com/protobufjs/protobuf.js/issues/605)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7eb3d456370d7d66b0856e32b2d2602abf598516) Respect optional properties when writing interfaces in tsd-jsdoc, fixes [#598](https://github.com/protobufjs/protobuf.js/issues/598)<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/bcadffecb3a8b98fbbd34b45bae0e6af58f9c810) Instead of protobuf.parse.keepCase, fall back to protobuf.parse.defaults holding all possible defaults, see [#608](https://github.com/protobufjs/protobuf.js/issues/608)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a4d6a2af0d57a2e0cccf31e3462c8b2465239f8b) Added global ParseOptions#keepCase fallback as protobuf.parse.keepCase, see [#608](https://github.com/protobufjs/protobuf.js/issues/608)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a017bf8a2dbdb7f9e7ce4c026bb6845174feb3b1) Converters use code generation and support custom implementations<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/28ce07d9812f5e1743afef95a94532d2c9488a84) Be more verbose when throwing invalid wire type errors, see [#602](https://github.com/protobufjs/protobuf.js/issues/602)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/40074bb69c3ca4fcefe09d4cfe01f3a86844a7e8) Added an asJSON-option to always populate array fields, even if defaults=false, see [#597](https://github.com/protobufjs/protobuf.js/issues/597)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a7d23240a278aac0bf01767b6096d692c09ae1ce) Attempt to improve TypeScript support by using explicit exports<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/cec253fb9a177ac810ec96f4f87186506091fa37) Copy-pasted typescript definitions to micro modules, see [#599](https://github.com/protobufjs/protobuf.js/issues/599)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1f18453c7bfcce65c258fa98a3e3d4577d2e550f) Emit an error on resolveAll() if any extension fields cannot be resolved, see [#595](https://github.com/protobufjs/protobuf.js/issues/595) + test case<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/804739dbb75359b0034db0097fe82081e3870a53) Removed 'not recommend' label for --keep-case, see [#608](https://github.com/protobufjs/protobuf.js/issues/608)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9681854526f1813a6ef08becf130ef2fbc28b638) Added customizable linter configuration to pbjs<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9681854526f1813a6ef08becf130ef2fbc28b638) Added stdin support to pbjs and pbts<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/407223b5ceca3304bc65cb48888abfdc917d5800) Static code no longer uses IE8 support utility<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a017bf8a2dbdb7f9e7ce4c026bb6845174feb3b1) Generated static code now supports asJSON/from<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3c775535517b8385a1d3c1bf056f3da3b4266f8c) Added support for TypeScript enums to pbts<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0cda72a55a1f2567a5d981dc5d924e55b8070513) Added a few helpful comments to static code<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/24b293c297feff8bda5ee7a2f8f3f83d77c156d0) Slightly beautify statically generated code<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/65637ffce20099df97ffbcdce50faccc8e97c366) Do not wrap main definition as a module and export directly instead<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/65637ffce20099df97ffbcdce50faccc8e97c366) Generate prettier definitions with --no-comments<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/20d8a2dd93d3bbb6990594286f992e703fc4e334) Added variable arguments support to tsd-jsdoc<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8493dbd9a923693e943f710918937d83ae3c4572) Reference dependency imports as a module to prevent name collisions, see [#596](https://github.com/protobufjs/protobuf.js/issues/596)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/39a2ea361c50d7f4aaa0408a0d55bb13823b906c) Removed now unnecessary comment lines in generated static code<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a4e41b55471d83a8bf265c6641c3c6e0eee82e31) Added notes on CSP-restricted environments to README, see [#593](https://github.com/protobufjs/protobuf.js/issues/593)<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1a3effdad171ded0608e8da021ba8f9dd017f2ff) Added test case for asJSON with arrays=true, see [#597](https://github.com/protobufjs/protobuf.js/issues/597)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/751a90f509b68a5f410d1f1844ccff2fc1fc056a) Added a tape adapter to assert message equality accross browsers<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fde56c0de69b480343931264a01a1ead1e3156ec) Refactored some internal utility away<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/805291086f6212d1f108b3d8f36325cf1739c0bd) Reverted previous attempt on [#597](https://github.com/protobufjs/protobuf.js/issues/597)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c5160217ea95996375460c5403dfe37b913d392e) Minor tsd-jsdoc refactor<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/961dd03061fc2c43ab3bf22b3f9f5165504c1002) Removed unused sandbox files<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f625eb8b0762f8f5d35bcd5fc445e52b92d8e77d) Updated package.json of micro modules to reference types, see [#599](https://github.com/protobufjs/protobuf.js/issues/599)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/46ec8209b21cf9ff09ae8674e2a5bbc49fd4991b) Reference dependencies as imports in generated typescript definitions, see [#596](https://github.com/protobufjs/protobuf.js/issues/596)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3bab132b871798c7c50c60a4c14c2effdffa372e) Allow null values on optional long fields, see [#590](https://github.com/protobufjs/protobuf.js/issues/590)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/31da56c177f1e11ffe0072ad5f58a55e3f8008fd) Various jsdoc improvements and a workaround for d.ts generation, see [#592](https://github.com/protobufjs/protobuf.js/issues/592)<br />
+
+## [6.3.1](https://github.com/protobufjs/protobuf.js/releases/tag/6.3.1)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/95ed6e9e8268711db24f44f0d7e58dd278ddac4c) Empty inner messages are always present on the wire + test case + removed now unused Writer#ldelim parameter, see [#585](https://github.com/protobufjs/protobuf.js/issues/585)<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e8a4d5373b1a00cc6eafa5b201b91d0e250cc00b) Expose tsd-jsdoc's comments option to pbts as --no-comments, see [#587](https://github.com/protobufjs/protobuf.js/issues/587)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6fe099259b5985d873ba5bec88c049d7491a11cc) Increase child process max buffer when running jsdoc from pbts, see [#587](https://github.com/protobufjs/protobuf.js/issues/587)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3d84ecdb4788d71b5d3928e74db78e8e54695f0a) pbjs now generates more convenient dot-notation property accessors<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1e0ebc064e4f2566cebf525d526d0b701447bd6a) And fixed IE8 again (should probably just drop IE8 for good)<br />
+
+## [6.3.0](https://github.com/protobufjs/protobuf.js/releases/tag/6.3.0)
+
+### Breaking
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a97956b1322b6ee62d4fc9af885658cd5855e521) Moved camelCase/underScore away from util to where actually used<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c144e7386529b53235a4a5bdd8383bdb322f2825) Renamed asJSON option keys (enum to enums, long to longs) because enum is a reserved keyword<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/5b9ade428dca2df6a13277522f2916e22092a98b) Moved JSON/Message conversion to its own source file and added Message/Type.from + test case, see [#575](https://github.com/protobufjs/protobuf.js/issues/575)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0b0de2458a1ade1ccd4ceb789697be13290f856b) Relicensed the library and its components to BSD-3-Clause to match the official implementation (again)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/22a64c641d4897965035cc80e92667bd243f182f) Dropped support for browser buffer entirely (is an Uint8Array anyway), ensures performance and makes things simpler<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/22a64c641d4897965035cc80e92667bd243f182f) Removed dead parts of the Reader API<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/964f65a9dd94ae0a18b8be3d9a9c1b0b1fdf6424) Refactored BufferReader/Writer to their own files and removed unnecessary operations (node always has FloatXXArray and browser buffer uses ieee anyway)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/bfac0ea9afa3dbaf5caf79ddf0600c3c7772a538) Stripped out fallback encoder/decoder/verifier completely (even IE8 supports codegen), significantly reduces bundle size, can use static codegen elsewhere<br />
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c3023a2f51fc74547f6c6e53cf75feed60f3a25c) Actually concatenate mixed custom options when parsing<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0d66b839df0acec2aea0566d2c0bbcec46c3cd1d) Fixed a couple of issues with alternative browser builds<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/33706cdc201bc863774c4af6ac2c38ad96a276e6) Properly set long defaults on prototypes<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0ea2740f0774b4c5c349b9c303f3fb2c2743c37b) Fixed reference error in minimal runtime, see [#580](https://github.com/protobufjs/protobuf.js/issues/580)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/741b6d8fde84d9574676a729a29a428d99f0a0a0) Non-repeated empty messages are always present on the wire, see [#581](https://github.com/protobufjs/protobuf.js/issues/581)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7fac9d6a39bf42d316c1676082a2d0804bc55934) Properly check Buffer.prototype.set with node v4<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3ad8108eab57e2b061ee6f1fddf964abe3f4cbc7) Prevent NRE and properly annotate verify signature in tsd-jsdoc, fixed [#572](https://github.com/protobufjs/protobuf.js/issues/572)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6c2415d599847cbdadc17dee3cdf369fc9facade) Fix directly using Buffer instead of util.Buffer<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/19e906c2a15acc6178b3bba6b19c2f021e681176) Added filter type to Namespace#lookup, fixes [#569](https://github.com/protobufjs/protobuf.js/issues/569)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9c9a66bf393d9d6927f35a9c18abf5d1c31db912) Fixed parsing enum inner options, see [#565](https://github.com/protobufjs/protobuf.js/issues/565)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ea7ba8b83890084d61012cb5386dc11dadfb3908) Fixed release links in README files<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/442471363f99e67fa97044f234a47b3c9b929dfa) Added a noparse build for completeness<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/bfee1cc3624d0fa21f9553c2f6ce2fcf7fcc09b7) Now compresses .gz files using zopfli to make them useful beyond being just a reference<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/aed134aa1cd7edd801de77c736cf5efe6fa61cb0) Updated non-bundled google types folder with missing descriptors and added wrappers to core<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0b0de2458a1ade1ccd4ceb789697be13290f856b) Replaced the ieee754 implementation for old browsers with a faster, use-case specific one + simple test case<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/99ad9cc08721b834a197d4bbb67fa152d7ad79aa) Added .create to statically generated types and uppercase nested elements to reflection namespaces, see [#576](https://github.com/protobufjs/protobuf.js/issues/576)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/99ad9cc08721b834a197d4bbb67fa152d7ad79aa) Also added Namespace#getEnum for completeness, see [#576](https://github.com/protobufjs/protobuf.js/issues/576)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ef43acff547c0cd84cfb7a892fe94504a586e491) Added Namespace#getEnum and changed #lookupEnum to the same behavior, see [#576](https://github.com/protobufjs/protobuf.js/issues/576)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1fcfdfe21c1b321d975a8a96d133a452c9a9c0d8) Added a heap of coverage comments for usually unused code paths to open things up<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c234de7f0573ee30ed1ecb15aa82b74c0f994876) Added codegen test to determine if any ancient browsers don't actually support it<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fed2000e7e461efdb1c3a1a1aeefa8b255a7c20b) Added legacy groups support to pbjs, see [#568](https://github.com/protobufjs/protobuf.js/issues/568)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/974a1321da3614832aa0a5b2e7c923f66e4ba8ae) Initial support for legacy groups + test case, see [#568](https://github.com/protobufjs/protobuf.js/issues/568)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9c9a66bf393d9d6927f35a9c18abf5d1c31db912) Added asJSON bytes as Buffer, see [#566](https://github.com/protobufjs/protobuf.js/issues/566)<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c60cd397e902ae6851c017f2c298520b8336cbee) Annotated callback types in pbjs-generated services, see [#582](https://github.com/protobufjs/protobuf.js/issues/582)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3e7e4fc59e6d2d6c862410b4b427fbedccdb237b) Removed type/ns alias comment in static target to not confuse jsdoc unnecessarily<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/99ad9cc08721b834a197d4bbb67fa152d7ad79aa) Made pbjs use loadSync for deterministic outputs, see [#573](https://github.com/protobufjs/protobuf.js/issues/573)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4d1f5facfcaaf5f2ab6a70b12443ff1b66e7b94e) Updated documentation on runtime and noparse builds<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c59647a7542cbc4292248787e5f32bb99a9b8d46) Fixed an issue with the changelog generator skipping some commits<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/24f2c03af9f13f5404259866fdc8fed33bfaae25) Added notes on how to use pbjs and pbts programmatically<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3544576116146b209246d71c7f7a9ed687950b26) Manually sorted old changelog entries<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d5812571f335bae68f924aa1098519683a9f3e44) Initial changelog generator, see [#574](https://github.com/protobufjs/protobuf.js/issues/574)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ab3e236a967a032a98267a648f84d129fdb4d4a6) Added static/JSON module interchangeability to README<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7939a4bd8baca5f7e07530fc93f27911a6d91c6f) Updated README and bundler according to dynamic require calls<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/93e04f1db4a9ef3accff8d071c75be3d74c0cd4a) Added basic services test case<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b5a068f5b79b6f00c4b05d9ac458878650ffa09a) Just polyfill Buffer.from / .allocUnsafe for good<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4375a485789e14f7bf24bece819001154a03dca2) Added a test case to find out if all the fallbacks are just for IE8<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/deb2e82ed7eda41d065a09d120e91c0f7ecf1e6a) Commented out float assertions in float test including explanation<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d3ebd5745b024033fbc2410ecad4d4e02abd67db) Expose array implementation used with (older) browsers on util for tests<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b1b6a813c93da4c7459755186aa02ef2f3765c94) Updated test cases<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/99dc5faa7b39fdad8ebc102de4463f8deb7f48ff) Added assumptions to float test case<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/948ca2e3c5c62fedcd918d75539c261abf1a7347) Updated travis config to use C++11<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c59647a7542cbc4292248787e5f32bb99a9b8d46) Updated / added additional LICENSE files where appropriate<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/333f0221814be976874862dc83d0b216e07d4012) Integrated changelog into build process, now also has 'npm run make' for everything, see [#574](https://github.com/protobufjs/protobuf.js/issues/574)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ab3e236a967a032a98267a648f84d129fdb4d4a6) Minor optimizations through providing type-hints<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ab3e236a967a032a98267a648f84d129fdb4d4a6) Reverted shortened switch statements in verifier<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ab3e236a967a032a98267a648f84d129fdb4d4a6) Enums can't be map key types<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8ef6975b0bd372b79e9b638f43940424824e7176) Use custom require (now a micromodule) for all optional modules, see [#571](https://github.com/protobufjs/protobuf.js/issues/571)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e226f001e4e4633d64c52be4abc1915d7b7bd515) Support usage when size = 0<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/19e906c2a15acc6178b3bba6b19c2f021e681176) Reverted aliases frequently used in codegen for better gzip ratio<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/47b51ec95a540681cbed0bac1b2f02fc4cf0b73d) Shrinked bundle size - a bit<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f8451f0058fdf7a1fac15ffc529e4e899c6b343c) Can finally run with --trace-deopt again without crashes<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9c9a66bf393d9d6927f35a9c18abf5d1c31db912) Other minor optimizations<br />
+
+## [6.2.1](https://github.com/protobufjs/protobuf.js/releases/tag/6.2.1)
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1a6fdc9a11fb08506d09351f8e853384c2b8be25) Added ParseOptions to protobuf.parse and --keep-case for .proto sources to pbjs, see [#564](https://github.com/protobufjs/protobuf.js/issues/564)<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fc383d0721d83f66b2d941f0d9361621839327e9) Better TypeScript definition support for @property-annotated objects<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4531d75cddee9a99adcac814d52613116ba789f3) Can't just inline longNeq but can be simplified<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8f25377cf99036794ba13b160a5060f312d1a7e7) Array abuse and varint optimization<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/90b201209a03e8022ada0ab9182f338fa0813651) Updated dependencies<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f1110b0993ec86e0a4aee1735bd75b901952cb36) Other minor improvements to short ifs<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c079c900e2d61c63d5508eafacbd00163d377482) Reader/Writer example<br />
+
+## [6.2.0](https://github.com/protobufjs/protobuf.js/releases/tag/6.2.0)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9b7b92a4c7f8caa460d687778dc0628a74cdde37) Fixed reserved names re, also ensure valid service method names, see [#559](https://github.com/protobufjs/protobuf.js/issues/559)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a83425049c9a78c5607bc35e8089e08ce78a741e) Fix d.ts whitespace on empty lines, added tsd-jsdoc LICENSE<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/5f9bede280aa998afb7898e8d2718b4a229e8e6f) Fix asJSON defaults option, make it work for repeated fields.<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b0aef62191b65cbb305ece84a6652d76f98da259) Inlined any Reader/Writer#tag calls, also fixes [#556](https://github.com/protobufjs/protobuf.js/issues/556)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4d091d41caad9e63cd64003a08210b78878e01dd) Fix building default dist files with explicit runtime=false<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/096dfb686f88db38ed2d8111ed7aac36f8ba658a) Apply asJSON recursively<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/19c269f1dce1b35fa190f264896d0865a54a4fff) Ensure working reflection class names with minified builds<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9c769504e0ffa6cbe0b6f8cdc14f1231bed7ee34) Lazily resolve (some) cyclic dependencies, see [#560](https://github.com/protobufjs/protobuf.js/issues/560)<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/da07d8bbbede4175cc45ca46d883210c1082e295) Added protobuf.roots to minimal runtime, see [#554](https://github.com/protobufjs/protobuf.js/issues/554)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8f407a18607334185afcc85ee98dc1478322bd01) Repo now includes a restructured version of tsd-jsdoc with our changes incorporated for issues/prs, see [#550](https://github.com/protobufjs/protobuf.js/issues/550)<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1b5e4250415c6169eadb405561242f847d75044b) Updated pbjs arguments<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4750e3111b9fdb107d0fc811e99904fbcdbb6de1) Pipe tsd-jsdoc output (requires dcodeIO/tsd-jsdoc/master) and respect cwd, see [#550](https://github.com/protobufjs/protobuf.js/issues/550)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/75f4b6cb6325a3fc7cd8fed3de5dbe0b6b29c748) tsd-jsdoc progress<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/766171e4c8b6650ea9c6bc3e76c9c96973c2f546) README<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c33835cb1fe1872d823e94b0fff024dc624323e8) Added GH issue template<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6f9ffb6307476d48f45dc4f936744b82982d386b) Path micromodule, dependencies<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0b9b1d8505743995c5328daab1f1e124debc63bd) Test case for [#556](https://github.com/protobufjs/protobuf.js/issues/556)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/74b2c5c5d33a46c3751ebeadc9d934d4ccb8286c) Raw alloc benchmark<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fb74223b7273530d8baa53437ee96c65a387436d) Other minor optimizations<br />
+
+## [6.1.1](https://github.com/protobufjs/protobuf.js/releases/tag/6.1.1)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/baea920fa6bf5746e0a7888cdbb089cd5d94fc90) Properly encode/decode map kv pairs as repeated messages (codegen and fallback), see [#547](https://github.com/protobufjs/protobuf.js/issues/547)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/28a1d26f28daf855c949614ef485237c6bf316e5) Make genVerifyKey actually generate conditions for 32bit values and bool, fixes [#546](https://github.com/protobufjs/protobuf.js/issues/546)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3e9d8ea9a5cbb2e029b5c892714edd6926d2e5a7) Fix to generation of verify methods for bytes<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e7893675ccdf18f0fdaea8f9a054a6b5402b060e) Take special care of oneofs when encoding (i.e. when explicitly set to defaults), see [#542](https://github.com/protobufjs/protobuf.js/issues/542)<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/52cd8b5a891ec8e11611127c8cfa6b3a91ff78e3) Added Message#asJSON option for bytes conversion<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/01365ba9116ca1649b682635bb29814657c4133c) Added Namespace#lookupType and Namespace#lookupService (throw instead of returning null), see [#544](https://github.com/protobufjs/protobuf.js/issues/544)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a54fbc918ef6bd627113f05049ff704e07bf33b4) Provide prebuilt browser versions of the static runtime<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3783af7ca9187a1d9b1bb278ca69e0188c7e4c66) Initial pbts CLI for generating TypeScript definitions, see [#550](https://github.com/protobufjs/protobuf.js/issues/550)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b8bce03405196b1779727f246229fd9217b4303d) Refactored json/static-module targets to use common wrappers<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/691231fbc453a243f48a97bfb86794ab5718ef49) Refactor cli to support multiple built-in wrappers, added named roots instead of always using global.root and added additionally necessary eslint comments, see [#540](https://github.com/protobufjs/protobuf.js/issues/540)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e3e77d0c7dc973d3a5948a49d123bdaf8a048030) Annotate namespaces generated by static target, see [#550](https://github.com/protobufjs/protobuf.js/issues/550)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/aff21a71e6bd949647b1b7721ea4e1fe16bcd933) static target: Basic support for oneof fields, see [#542](https://github.com/protobufjs/protobuf.js/issues/542)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b6b00aa7b0cd35e0e8f3c16b322788e9942668d4) Fix to reflection documentation<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ed86f3acbeb6145be5f24dcd05efb287b539e61b) README on minimal runtime / available downloads<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d31590b82d8bafe6657bf877d403f01a034ab4ba) Notes on descriptors vs static modules<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ce41d0ef21cee2d918bdc5c3b542d3b7638b6ead) A lot of minor optimizations to performance and gzip ratio<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ecbb4a52fbab445e63bf23b91539e853efaefa47) Minimized base64 tables<br />
+
+## [6.1.0](https://github.com/protobufjs/protobuf.js/releases/tag/6.1.0)
+
+### Breaking
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a46cc4934b7e888ae80e06fd7fdf91e5bc7f54f5) Removed as-function overload for Reader/Writer, profiler stub, optimized version of Reader#int32<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7983ee0ba15dc5c1daad82a067616865051848c9) Refactored Prototype and inherits away, is now Class and Message for more intuitive documentation and type refs<br />
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/c3c70fe3a47fd4f7c85dc80e1af7d9403fe349cd) Fixed failing test case on node < 6<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/66be5983321dd06460382d045eb87ed72a186776) Fixed serialization order of sfixed64, fixes [#536](https://github.com/protobufjs/protobuf.js/issues/536)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7def340833f9f1cc41f4835bd0d62e203b54d9eb) Fixed serialization order of fixed64, fallback to parseInt with no long lib, see [#534](https://github.com/protobufjs/protobuf.js/issues/534)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/98a58d40ca7ee7afb1f76c5804e82619104644f6) Actually allow undefined as service method type, fixes [#528](https://github.com/protobufjs/protobuf.js/issues/528)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/38d867fc50a4d7eb1ca07525c9e4c71b8782443e) Do not skip optional delimiter after aggregate options, fixes [#520](https://github.com/protobufjs/protobuf.js/issues/520)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/67449db7c7416cbc59ad230c168cf6e6b6dba0c5) Verify empty base64 encoded strings for bytes fields, see [#535](https://github.com/protobufjs/protobuf.js/issues/535)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ef0fcb6d525c5aab13a39b4f393adf03f751c8c9) wrong spell role should be rule<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/55db92e21a26c04f524aeecb2316968c000e744d) decodeDelimited always forks if writer is specified, see [#531](https://github.com/protobufjs/protobuf.js/issues/531)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ebae1e18152617f11ac07827828f5740d4f2eb7e) Mimic spec-compliant behaviour in oneof getVirtual, see [#523](https://github.com/protobufjs/protobuf.js/issues/523)<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/a0398f5880c434ff88fd8d420ba07cc29c5d39d3) Initial base64 string support for bytes fields, see [#535](https://github.com/protobufjs/protobuf.js/issues/535)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6a6c00c3e1def5d35c7fcaa1bbb6ce4e0fe67544) Initial type-checking verifier, see [#526](https://github.com/protobufjs/protobuf.js/issues/526), added to bench out of competition<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3aa984e063cd73e4687102b4abd8adc16582dbc4) Initial loadSync (node only), see [#529](https://github.com/protobufjs/protobuf.js/issues/529)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f1370ff5b0db2ebb73b975a3d7c7bd5b901cbfac) Initial RPC service implementaion, see [#529](https://github.com/protobufjs/protobuf.js/issues/529)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/090d8eaf10704a811a73e1becd52f2307cbcad48) added 'defaults' option to Prototype#asJSON, see [#521](https://github.com/protobufjs/protobuf.js/issues/521)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7c28483d65cde148e61fe9993f1716960b39e049) Use Uint8Array pool in browsers, just like node does with buffers<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4157a0ec2e54c4d19794cb16edddcd8d4fbd3e76) Also validate map fields, see [#526](https://github.com/protobufjs/protobuf.js/issues/526) (this really needs some tests)<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0ce099bf4f4666fd00403a2839e6da628b8328a9) Added json-module target to pbjs, renamed static to static-module, see [#522](https://github.com/protobufjs/protobuf.js/issues/522)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1d99442fe65fcaa2f9e33cc0186ef1336057e0cf) updated internals and static target to use immutable objects on prototypes<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e6eaa91b9fe021b3356d4d7e42033a877bc45871) Added a couple of alternative signatures, protobuf.load returns promise or undefined, aliased Reader/Writer-as-function signature with Reader/Writer.create for typed dialects, see [#518](https://github.com/protobufjs/protobuf.js/issues/518)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9df6a3d4a654c3e122f97d9a594574c7bbb412da) Added variations for Root#load, see [#527](https://github.com/protobufjs/protobuf.js/issues/527)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/193e65c006a8df8e9b72e0f23ace14a94952ee36) Added benchmark and profile related information to README<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/228a2027de35238feb867cb0485c78c755c4d17d) Added service example to README, see [#529](https://github.com/protobufjs/protobuf.js/issues/529)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/1a8c720714bf867f1f0195b4690faefa4f65e66a) README on tests<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/014fb668dcf853874c67e3e0aeb7b488a149d35c) Update README/dist to reflect recent changes<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/11d844c010c5a22eff9d5824714fb67feca77b26) Minimal documentation for micromodules<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/47608dd8595b0df2b30dd18fef4b8207f73ed56a) Document all the callbacks, see [#527](https://github.com/protobufjs/protobuf.js/issues/527)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3891ab07bbe20cf84701605aa62453a6dbdb6af2) Documented streaming-rpc example a bit<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/5606cb1bc41bc90cb069de676650729186b38640) Removed the need for triple-slash references in .d.ts by providing a minimal Long interface, see [#527](https://github.com/protobufjs/protobuf.js/issues/527), see [#530](https://github.com/protobufjs/protobuf.js/issues/530)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/adf3cc3d340f8b2a596c892c64457b15e42a771b) Transition to micromodules<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f3a9589b74af6a1bf175f2b1994badf703d7abc4) Refactored argument order of utf8 for plausibility<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/14c207ed6e05a61e756fa4192efb2fa219734dd6) Restructured reusable micromodules<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/b510ba258986271f07007aebc5dcfea7cfd90cf4) Can't use Uint8Array#set on node < 6 buffers<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/78952a50ceee8e196b4f156eb01f7f693b5b8aac) Test case for [#531](https://github.com/protobufjs/protobuf.js/issues/531)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/954577c6b421f7d7f4905bcc32f57e4ebaf548da) Safer signaling for synchronous load, see [#529](https://github.com/protobufjs/protobuf.js/issues/529)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9ea3766ff1b8fb7ccad028f44efe27d3b019eeb7) Proper end of stream signaling to rpcImpl, see [#529](https://github.com/protobufjs/protobuf.js/issues/529)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/e4faf7fac9b34d4776f3c15dfef8d2ae54104567) Moved event emitter to util, also accepts listener context, see [#529](https://github.com/protobufjs/protobuf.js/issues/529)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9bdec62793ce77c954774cc19106bde4132f24fc) Probably the worst form of hiding require programmatically, see [#527](https://github.com/protobufjs/protobuf.js/issues/527)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4462d8b05d3aba37c865cf53e09b3199cf051a92) Attempt to hide require('fs') from webpack, see [#527](https://github.com/protobufjs/protobuf.js/issues/527)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/7c3bf8d32cbf831b251730b3876c35c901926300) Trying out jsdoc variations, see [#527](https://github.com/protobufjs/protobuf.js/issues/527)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/bb4059467287fefda8f966de575fd0f8f9690bd3) by the way, why not include the json->proto functionality into "util"?<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f1008e6ee53ee50358e19c10df8608e950be4be3) Update proto.js<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fc9014822d9cdeae8c6e454ccb66ee28f579826c) Automatic profile generation and processing<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/2a2f6dcab5beaaa98e55a005b3d02643c45504d6) Generalized buffer pool and moved it to util<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/53a16bf3ada4a60cc09757712e0046f3f2d9d094) Make shields visible on npm, yey<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/9004b9d0c5135a7f6df208ea658258bf2f9e6fc9) More shields, I love shields, and maybe a workaround for travis timing out when sauce takes forever<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/060a7916a2715a9e4cd4d05d7c331bec33e60b7e) Trying SauceLabs with higher concurrency<br />
+
+## [6.0.2](https://github.com/protobufjs/protobuf.js/releases/tag/6.0.2)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/23d664384900eb65e44910def45f04be996fbba1) Fix packable float/double see [#513](https://github.com/protobufjs/protobuf.js/issues/513)<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/54283d39c4c955b6a84f7f53d4940eec39e4df5e) Handle oneofs in prototype ctor, add non-ES5 fallbacks, test case<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/0ae66752362899b8407918a759b09938e82436e1) Be nice to AMD, allow reconfiguration of Reader/Writer interface<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/00f3574ef4ee8b237600e41839bf0066719c4469) Initial static codegen target for reference<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/81e36a7c14d89b487dfe7cfb2f8380fcdf0df392) pbjs static target services support<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4885b8239eb74c72e665787ea0ece3336e493d7f) pbjs static target progress, uses customizable wrapper template<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/ad5abe7bac7885ba4f68df7eeb800d2e3b81750b) Static pbjs target progress, now generates usable CommonJS code, see [#512](https://github.com/protobufjs/protobuf.js/issues/512)<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d9634d218849fb49ff5dfb4597bbb2c2d43bbf08) TypeScript example<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/fce8276193a5a9fabad5e5fbeb2ccd4f0f3294a9) Adjectives, notes on browserify<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/23d664384900eb65e44910def45f04be996fbba1) Refactor runtime util into separate file, reader/writer uses runtime util<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/f91c432a498bebc0adecef1562061b392611f51a) Also optimize reader with what we have learned<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d83f799519fe69808c88e83d9ad66c645d15e963) More (shameless) writer over-optimization<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/8a2dbc610a06fe3a1a2695a3ab032d073b77760d) Trading package size for float speed<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/95c5538cfaf1daf6b4990f6aa7599779aaacf99f) Skip defining getters and setters on IE8 entirely, automate defining fallbacks<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/09865d069303e795e475c82afe2b2267abaa59ea) Unified proto/reflection/classes/static encoding API to always return a writer<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/98d6ae186a48416e4ff3030987caed285f40a4f7) plain js utf8 is faster for short strings<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/79fbbf48b8e4dc9c41dcbdef2b73c5f2608b0318) improve TypeScript support. add simple test script.<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/96fa07adec8b0ae05e07c2c40383267f25f2fc92) Use long.js dependency in tests, reference types instead of paths in .d.ts see [#503](https://github.com/protobufjs/protobuf.js/issues/503)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/5785dee15d07fbcd14025a96686707173bd649a0) Restructured encoder / decoder to better support static code gen<br />
+
+## [6.0.1](https://github.com/protobufjs/protobuf.js/releases/tag/6.0.1)
+
+### Fixed
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/799c1c1a84b255d1831cc84c3d24e61b36fa2530) Add support for long strings, fixes [#509](https://github.com/protobufjs/protobuf.js/issues/509)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6e5fdb67cb34f90932e95a51370e1652acc55b4c) expose zero on LongBits, fixes [#508](https://github.com/protobufjs/protobuf.js/issues/508)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/aa922c07490f185c5f97cf28ebbd65200fc5e377) Fixed issues with Root.fromJSON/#addJSON, search global for Long<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/51fe45656b530efbba6dad92f92db2300aa18761) Properly exclude browserify's annoying _process, again, fixes [#502](https://github.com/protobufjs/protobuf.js/issues/502)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/3c16e462a28c36abbc8a176eab9ac2e10ba68597) Remember loaded files earlier to prevent race conditions, fixes [#501](https://github.com/protobufjs/protobuf.js/issues/501)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4012a00a0578185d92fb6e7d3babd059fee6d6ab) Allow negative enum ids even if super inefficient (encodes as 10 bytes), fixes [#499](https://github.com/protobufjs/protobuf.js/issues/499), fixes [#500](https://github.com/protobufjs/protobuf.js/issues/500)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/96dd8f1729ad72e29dbe08dd01bc0ba08446dbe6) set resolvedResponseType on resolve(), fixes [#497](https://github.com/protobufjs/protobuf.js/issues/497)<br />
+
+### New
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/d3ae961765e193ec11227d96d699463de346423f) Initial take on runtime services, see [#507](https://github.com/protobufjs/protobuf.js/issues/507)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/90cd46b3576ddb2d0a6fc6ae55da512db4be3acc) Include dist/ in npm package for frontend use<br />
+
+### CLI
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/4affa1b7c0544229fb5f0d3948df6d832f6feadb) pbjs proto target field options, language-level compliance with jspb test.proto<br />
+
+### Docs
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/6a06e95222d741c47a51bcec85cd20317de7c0b0) always use Uint8Array in docs for tsd, see [#503](https://github.com/protobufjs/protobuf.js/issues/503)<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/637698316e095fc35f62a304daaca22654974966) Notes on dist files<br />
+
+### Other
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/29ff3f10e367d6a2ae15fb4254f4073541559c65) Update eslint env<br />
+[:hash:](https://github.com/protobufjs/protobuf.js/commit/943be1749c7d37945c11d1ebffbed9112c528d9f) Browser field in package.json isn't required<br />
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..57b7e30
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,39 @@
+This license applies to all parts of protobuf.js except those files
+either explicitly including or referencing a different license or
+located in a directory containing a different LICENSE file.
+
+---
+
+Copyright (c) 2016, Daniel Wirtz  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 its author, 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
+
+---
+
+Code generated by the command line utilities is owned by the owner
+of the input file used when generating it. This code is not
+standalone and requires a support library to be linked with it. This
+support library is itself covered by the above license.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..28e0a64
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,13 @@
+name: "protobuf.js"
+description:
+    "Trusted types patched version of protobuf.js"
+
+third_party {
+  url {
+    type: GIT
+    value: "https://github.com/protobufjs/protobuf.js"
+  }
+  version: "7.2.2"
+  last_upgrade_date { year: 2023 month: 03 day: 24 }
+  license_type: NOTICE
+}
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b88c022
--- /dev/null
+++ b/README.md
@@ -0,0 +1,740 @@
+<h1><p align="center"><img alt="protobuf.js" src="https://github.com/dcodeIO/protobuf.js/raw/master/pbjs.png" width="120" height="104" /></p></h1>
+<p align="center"><a href="https://npmjs.org/package/protobufjs"><img src="https://img.shields.io/npm/v/protobufjs.svg" alt=""></a> <a href="https://travis-ci.org/dcodeIO/protobuf.js"><img src="https://travis-ci.org/dcodeIO/protobuf.js.svg?branch=master" alt=""></a> <a href="https://npmjs.org/package/protobufjs"><img src="https://img.shields.io/npm/dm/protobufjs.svg" alt=""></a> <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=dcode%40dcode.io&item_name=Open%20Source%20Software%20Donation&item_number=dcodeIO%2Fprotobuf.js"><img alt="donate ❤" src="https://img.shields.io/badge/donate-❤-ff2244.svg"></a></p>
+
+**Protocol Buffers** are a language-neutral, platform-neutral, extensible way of serializing structured data for use in communications protocols, data storage, and more, originally designed at Google ([see](https://developers.google.com/protocol-buffers/)).
+
+**protobuf.js** is a pure JavaScript implementation with [TypeScript](https://www.typescriptlang.org) support for [node.js](https://nodejs.org) and the browser. It's easy to use, blazingly fast and works out of the box with [.proto](https://developers.google.com/protocol-buffers/docs/proto) files!
+
+Contents
+--------
+
+* [Installation](#installation)<br />
+  How to include protobuf.js in your project.
+
+* [Usage](#usage)<br />
+  A brief introduction to using the toolset.
+
+  * [Valid Message](#valid-message)
+  * [Toolset](#toolset)<br />
+
+* [Examples](#examples)<br />
+  A few examples to get you started.
+
+  * [Using .proto files](#using-proto-files)
+  * [Using JSON descriptors](#using-json-descriptors)
+  * [Using reflection only](#using-reflection-only)
+  * [Using custom classes](#using-custom-classes)
+  * [Using services](#using-services)
+  * [Usage with TypeScript](#usage-with-typescript)<br />
+
+* [Additional documentation](#additional-documentation)<br />
+  A list of available documentation resources.
+
+* [Performance](#performance)<br />
+  A few internals and a benchmark on performance.
+
+* [Compatibility](#compatibility)<br />
+  Notes on compatibility regarding browsers and optional libraries.
+
+* [Building](#building)<br />
+  How to build the library and its components yourself.
+
+Installation
+---------------
+
+### node.js
+
+```
+$> npm install protobufjs [--save --save-prefix=~]
+```
+
+```js
+var protobuf = require("protobufjs");
+```
+
+The command line utility lives in the protobufjs-cli package and must be installed separately:
+
+```
+$> npm install protobufjs-cli [--save --save-prefix=~]
+```
+
+**Note** that this library's versioning scheme is not semver-compatible for historical reasons. For guaranteed backward compatibility, always depend on `~6.A.B` instead of `^6.A.B` (hence the `--save-prefix` above).
+
+### Browsers
+
+Development:
+
+```
+<script src="//cdn.jsdelivr.net/npm/protobufjs@7.X.X/dist/protobuf.js"></script>
+```
+
+Production:
+
+```
+<script src="//cdn.jsdelivr.net/npm/protobufjs@7.X.X/dist/protobuf.min.js"></script>
+```
+
+**Remember** to replace the version tag with the exact [release](https://github.com/protobufjs/protobuf.js/tags) your project depends upon.
+
+The library supports CommonJS and AMD loaders and also exports globally as `protobuf`.
+
+### Distributions
+
+Where bundle size is a factor, there are additional stripped-down versions of the [full library][dist-full] (~19kb gzipped) available that exclude certain functionality:
+
+* When working with JSON descriptors (i.e. generated by [pbjs](cli/README.md#pbjs-for-javascript)) and/or reflection only, see the [light library][dist-light] (~16kb gzipped) that excludes the parser. CommonJS entry point is:
+
+  ```js
+  var protobuf = require("protobufjs/light");
+  ```
+
+* When working with statically generated code only, see the [minimal library][dist-minimal] (~6.5kb gzipped) that also excludes reflection. CommonJS entry point is:
+
+  ```js
+  var protobuf = require("protobufjs/minimal");
+  ```
+
+| Distribution | Location
+|------------|-----------------------------------
+| Full | <https://cdn.jsdelivr.net/npm/protobufjs/dist/>
+| Light | <https://cdn.jsdelivr.net/npm/protobufjs/dist/light/>
+| Minimal | <https://cdn.jsdelivr.net/npm/protobufjs/dist/minimal/>
+
+Usage
+-----
+
+Because JavaScript is a dynamically typed language, protobuf.js introduces the concept of a **valid message** in order to provide the best possible [performance](#performance) (and, as a side product, proper typings):
+
+### Valid message
+
+> A valid message is an object (1) not missing any required fields and (2) exclusively composed of JS types understood by the wire format writer.
+
+There are two possible types of valid messages and the encoder is able to work with both of these for convenience:
+
+* **Message instances** (explicit instances of message classes with default values on their prototype) always (have to) satisfy the requirements of a valid message by design and
+* **Plain JavaScript objects** that just so happen to be composed in a way satisfying the requirements of a valid message as well.
+
+In a nutshell, the wire format writer understands the following types:
+
+| Field type | Expected JS type (create, encode) | Conversion (fromObject)
+|------------|-----------------------------------|------------------------
+| s-/u-/int32<br />s-/fixed32 | `number` (32 bit integer) | <code>value &#124; 0</code> if signed<br />`value >>> 0` if unsigned
+| s-/u-/int64<br />s-/fixed64 | `Long`-like (optimal)<br />`number` (53 bit integer) | `Long.fromValue(value)` with long.js<br />`parseInt(value, 10)` otherwise
+| float<br />double | `number` | `Number(value)`
+| bool | `boolean` | `Boolean(value)`
+| string | `string` | `String(value)`
+| bytes | `Uint8Array` (optimal)<br />`Buffer` (optimal under node)<br />`Array.<number>` (8 bit integers) | `base64.decode(value)` if a `string`<br />`Object` with non-zero `.length` is assumed to be buffer-like
+| enum | `number` (32 bit integer) | Looks up the numeric id if a `string`
+| message | Valid message | `Message.fromObject(value)`
+
+* Explicit `undefined` and `null` are considered as not set if the field is optional.
+* Repeated fields are `Array.<T>`.
+* Map fields are `Object.<string,T>` with the key being the string representation of the respective value or an 8 characters long binary hash string for `Long`-likes.
+* Types marked as *optimal* provide the best performance because no conversion step (i.e. number to low and high bits or base64 string to buffer) is required.
+
+### Toolset
+
+With that in mind and again for performance reasons, each message class provides a distinct set of methods with each method doing just one thing. This avoids unnecessary assertions / redundant operations where performance is a concern but also forces a user to perform verification (of plain JavaScript objects that *might* just so happen to be a valid message) explicitly where necessary - for example when dealing with user input.
+
+**Note** that `Message` below refers to any message class.
+
+* **Message.verify**(message: `Object`): `null|string`<br />
+  verifies that a **plain JavaScript object** satisfies the requirements of a valid message and thus can be encoded without issues. Instead of throwing, it returns the error message as a string, if any.
+
+  ```js
+  var payload = "invalid (not an object)";
+  var err = AwesomeMessage.verify(payload);
+  if (err)
+    throw Error(err);
+  ```
+
+* **Message.encode**(message: `Message|Object` [, writer: `Writer`]): `Writer`<br />
+  encodes a **message instance** or valid **plain JavaScript object**. This method does not implicitly verify the message and it's up to the user to make sure that the payload is a valid message.
+
+  ```js
+  var buffer = AwesomeMessage.encode(message).finish();
+  ```
+
+* **Message.encodeDelimited**(message: `Message|Object` [, writer: `Writer`]): `Writer`<br />
+  works like `Message.encode` but additionally prepends the length of the message as a varint.
+
+* **Message.decode**(reader: `Reader|Uint8Array`): `Message`<br />
+  decodes a buffer to a **message instance**. If required fields are missing, it throws a `util.ProtocolError` with an `instance` property set to the so far decoded message. If the wire format is invalid, it throws an `Error`.
+
+  ```js
+  try {
+    var decodedMessage = AwesomeMessage.decode(buffer);
+  } catch (e) {
+      if (e instanceof protobuf.util.ProtocolError) {
+        // e.instance holds the so far decoded message with missing required fields
+      } else {
+        // wire format is invalid
+      }
+  }
+  ```
+
+* **Message.decodeDelimited**(reader: `Reader|Uint8Array`): `Message`<br />
+  works like `Message.decode` but additionally reads the length of the message prepended as a varint.
+
+* **Message.create**(properties: `Object`): `Message`<br />
+  creates a new **message instance** from a set of properties that satisfy the requirements of a valid message. Where applicable, it is recommended to prefer `Message.create` over `Message.fromObject` because it doesn't perform possibly redundant conversion.
+
+  ```js
+  var message = AwesomeMessage.create({ awesomeField: "AwesomeString" });
+  ```
+
+* **Message.fromObject**(object: `Object`): `Message`<br />
+  converts any non-valid **plain JavaScript object** to a **message instance** using the conversion steps outlined within the table above.
+
+  ```js
+  var message = AwesomeMessage.fromObject({ awesomeField: 42 });
+  // converts awesomeField to a string
+  ```
+
+* **Message.toObject**(message: `Message` [, options: `ConversionOptions`]): `Object`<br />
+  converts a **message instance** to an arbitrary **plain JavaScript object** for interoperability with other libraries or storage. The resulting plain JavaScript object *might* still satisfy the requirements of a valid message depending on the actual conversion options specified, but most of the time it does not.
+
+  ```js
+  var object = AwesomeMessage.toObject(message, {
+    enums: String,  // enums as string names
+    longs: String,  // longs as strings (requires long.js)
+    bytes: String,  // bytes as base64 encoded strings
+    defaults: true, // includes default values
+    arrays: true,   // populates empty arrays (repeated fields) even if defaults=false
+    objects: true,  // populates empty objects (map fields) even if defaults=false
+    oneofs: true    // includes virtual oneof fields set to the present field's name
+  });
+  ```
+
+For reference, the following diagram aims to display relationships between the different methods and the concept of a valid message:
+
+<p align="center"><img alt="Toolset Diagram" src="https://protobufjs.github.io/protobuf.js/toolset.svg" /></p>
+
+> In other words: `verify` indicates that calling `create` or `encode` directly on the plain object will [result in a valid message respectively] succeed. `fromObject`, on the other hand, does conversion from a broader range of plain objects to create valid messages. ([ref](https://github.com/dcodeIO/protobuf.js/issues/748#issuecomment-291925749))
+
+Examples
+--------
+
+### Using .proto files
+
+It is possible to load existing .proto files using the full library, which parses and compiles the definitions to ready to use (reflection-based) message classes:
+
+```protobuf
+// awesome.proto
+package awesomepackage;
+syntax = "proto3";
+
+message AwesomeMessage {
+    string awesome_field = 1; // becomes awesomeField
+}
+```
+
+```js
+protobuf.load("awesome.proto", function(err, root) {
+    if (err)
+        throw err;
+
+    // Obtain a message type
+    var AwesomeMessage = root.lookupType("awesomepackage.AwesomeMessage");
+
+    // Exemplary payload
+    var payload = { awesomeField: "AwesomeString" };
+
+    // Verify the payload if necessary (i.e. when possibly incomplete or invalid)
+    var errMsg = AwesomeMessage.verify(payload);
+    if (errMsg)
+        throw Error(errMsg);
+
+    // Create a new message
+    var message = AwesomeMessage.create(payload); // or use .fromObject if conversion is necessary
+
+    // Encode a message to an Uint8Array (browser) or Buffer (node)
+    var buffer = AwesomeMessage.encode(message).finish();
+    // ... do something with buffer
+
+    // Decode an Uint8Array (browser) or Buffer (node) to a message
+    var message = AwesomeMessage.decode(buffer);
+    // ... do something with message
+
+    // If the application uses length-delimited buffers, there is also encodeDelimited and decodeDelimited.
+
+    // Maybe convert the message back to a plain object
+    var object = AwesomeMessage.toObject(message, {
+        longs: String,
+        enums: String,
+        bytes: String,
+        // see ConversionOptions
+    });
+});
+```
+
+Additionally, promise syntax can be used by omitting the callback, if preferred:
+
+```js
+protobuf.load("awesome.proto")
+    .then(function(root) {
+       ...
+    });
+```
+
+### Using JSON descriptors
+
+The library utilizes JSON descriptors that are equivalent to a .proto definition. For example, the following is identical to the .proto definition seen above:
+
+```json
+// awesome.json
+{
+  "nested": {
+    "awesomepackage": {
+      "nested": {
+        "AwesomeMessage": {
+          "fields": {
+            "awesomeField": {
+              "type": "string",
+              "id": 1
+            }
+          }
+        }
+      }
+    }
+  }
+}
+```
+
+JSON descriptors closely resemble the internal reflection structure:
+
+| Type (T)           | Extends            | Type-specific properties
+|--------------------|--------------------|-------------------------
+| *ReflectionObject* |                    | options
+| *Namespace*        | *ReflectionObject* | nested
+| Root               | *Namespace*        | **nested**
+| Type               | *Namespace*        | **fields**
+| Enum               | *ReflectionObject* | **values**
+| Field              | *ReflectionObject* | rule, **type**, **id**
+| MapField           | Field              | **keyType**
+| OneOf              | *ReflectionObject* | **oneof** (array of field names)
+| Service            | *Namespace*        | **methods**
+| Method             | *ReflectionObject* | type, **requestType**, **responseType**, requestStream, responseStream
+
+* **Bold properties** are required. *Italic types* are abstract.
+* `T.fromJSON(name, json)` creates the respective reflection object from a JSON descriptor
+* `T#toJSON()` creates a JSON descriptor from the respective reflection object (its name is used as the key within the parent)
+
+Exclusively using JSON descriptors instead of .proto files enables the use of just the light library (the parser isn't required in this case).
+
+A JSON descriptor can either be loaded the usual way:
+
+```js
+protobuf.load("awesome.json", function(err, root) {
+    if (err) throw err;
+
+    // Continue at "Obtain a message type" above
+});
+```
+
+Or it can be loaded inline:
+
+```js
+var jsonDescriptor = require("./awesome.json"); // exemplary for node
+
+var root = protobuf.Root.fromJSON(jsonDescriptor);
+
+// Continue at "Obtain a message type" above
+```
+
+### Using reflection only
+
+Both the full and the light library include full reflection support. One could, for example, define the .proto definitions seen in the examples above using just reflection:
+
+```js
+...
+var Root  = protobuf.Root,
+    Type  = protobuf.Type,
+    Field = protobuf.Field;
+
+var AwesomeMessage = new Type("AwesomeMessage").add(new Field("awesomeField", 1, "string"));
+
+var root = new Root().define("awesomepackage").add(AwesomeMessage);
+
+// Continue at "Create a new message" above
+...
+```
+
+Detailed information on the reflection structure is available within the [API documentation](#additional-documentation).
+
+### Using custom classes
+
+Message classes can also be extended with custom functionality and it is also possible to register a custom constructor with a reflected message type:
+
+```js
+...
+
+// Define a custom constructor
+function AwesomeMessage(properties) {
+    // custom initialization code
+    ...
+}
+
+// Register the custom constructor with its reflected type (*)
+root.lookupType("awesomepackage.AwesomeMessage").ctor = AwesomeMessage;
+
+// Define custom functionality
+AwesomeMessage.customStaticMethod = function() { ... };
+AwesomeMessage.prototype.customInstanceMethod = function() { ... };
+
+// Continue at "Create a new message" above
+```
+
+(*) Besides referencing its reflected type through `AwesomeMessage.$type` and `AwesomeMesage#$type`, the respective custom class is automatically populated with:
+
+* `AwesomeMessage.create`
+* `AwesomeMessage.encode` and `AwesomeMessage.encodeDelimited`
+* `AwesomeMessage.decode` and `AwesomeMessage.decodeDelimited`
+* `AwesomeMessage.verify`
+* `AwesomeMessage.fromObject`, `AwesomeMessage.toObject` and `AwesomeMessage#toJSON`
+
+Afterwards, decoded messages of this type are `instanceof AwesomeMessage`.
+
+Alternatively, it is also possible to reuse and extend the internal constructor if custom initialization code is not required:
+
+```js
+...
+
+// Reuse the internal constructor
+var AwesomeMessage = root.lookupType("awesomepackage.AwesomeMessage").ctor;
+
+// Define custom functionality
+AwesomeMessage.customStaticMethod = function() { ... };
+AwesomeMessage.prototype.customInstanceMethod = function() { ... };
+
+// Continue at "Create a new message" above
+```
+
+### Using services
+
+The library also supports consuming services but it doesn't make any assumptions about the actual transport channel. Instead, a user must provide a suitable RPC implementation, which is an asynchronous function that takes the reflected service method, the binary request and a node-style callback as its parameters:
+
+```js
+function rpcImpl(method, requestData, callback) {
+    // perform the request using an HTTP request or a WebSocket for example
+    var responseData = ...;
+    // and call the callback with the binary response afterwards:
+    callback(null, responseData);
+}
+```
+
+Below is a working example with a typescript implementation using grpc npm package.
+```ts
+const grpc = require('grpc')
+
+const Client = grpc.makeGenericClientConstructor({})
+const client = new Client(
+  grpcServerUrl,
+  grpc.credentials.createInsecure()
+)
+
+const rpcImpl = function(method, requestData, callback) {
+  client.makeUnaryRequest(
+    method.name,
+    arg => arg,
+    arg => arg,
+    requestData,
+    callback
+  )
+}
+```
+
+Example:
+
+```protobuf
+// greeter.proto
+syntax = "proto3";
+
+service Greeter {
+    rpc SayHello (HelloRequest) returns (HelloReply) {}
+}
+
+message HelloRequest {
+    string name = 1;
+}
+
+message HelloReply {
+    string message = 1;
+}
+```
+
+```js
+...
+var Greeter = root.lookup("Greeter");
+var greeter = Greeter.create(/* see above */ rpcImpl, /* request delimited? */ false, /* response delimited? */ false);
+
+greeter.sayHello({ name: 'you' }, function(err, response) {
+    console.log('Greeting:', response.message);
+});
+```
+
+Services also support promises:
+
+```js
+greeter.sayHello({ name: 'you' })
+    .then(function(response) {
+        console.log('Greeting:', response.message);
+    });
+```
+
+There is also an [example for streaming RPC](https://github.com/dcodeIO/protobuf.js/blob/master/examples/streaming-rpc.js).
+
+Note that the service API is meant for clients. Implementing a server-side endpoint pretty much always requires transport channel (i.e. http, websocket, etc.) specific code with the only common denominator being that it decodes and encodes messages.
+
+### Usage with TypeScript
+
+The library ships with its own [type definitions](https://github.com/dcodeIO/protobuf.js/blob/master/index.d.ts) and modern editors like [Visual Studio Code](https://code.visualstudio.com/) will automatically detect and use them for code completion.
+
+The npm package depends on [@types/node](https://www.npmjs.com/package/@types/node) because of `Buffer` and [@types/long](https://www.npmjs.com/package/@types/long) because of `Long`. If you are not building for node and/or not using long.js, it should be safe to exclude them manually.
+
+#### Using the JS API
+
+The API shown above works pretty much the same with TypeScript. However, because everything is typed, accessing fields on instances of dynamically generated message classes requires either using bracket-notation (i.e. `message["awesomeField"]`) or explicit casts. Alternatively, it is possible to use a [typings file generated for its static counterpart](#pbts-for-typescript).
+
+```ts
+import { load } from "protobufjs"; // respectively "./node_modules/protobufjs"
+
+load("awesome.proto", function(err, root) {
+  if (err)
+    throw err;
+
+  // example code
+  const AwesomeMessage = root.lookupType("awesomepackage.AwesomeMessage");
+
+  let message = AwesomeMessage.create({ awesomeField: "hello" });
+  console.log(`message = ${JSON.stringify(message)}`);
+
+  let buffer = AwesomeMessage.encode(message).finish();
+  console.log(`buffer = ${Array.prototype.toString.call(buffer)}`);
+
+  let decoded = AwesomeMessage.decode(buffer);
+  console.log(`decoded = ${JSON.stringify(decoded)}`);
+});
+```
+
+#### Using generated static code
+
+If you generated static code to `bundle.js` using the CLI and its type definitions to `bundle.d.ts`, then you can just do:
+
+```ts
+import { AwesomeMessage } from "./bundle.js";
+
+// example code
+let message = AwesomeMessage.create({ awesomeField: "hello" });
+let buffer  = AwesomeMessage.encode(message).finish();
+let decoded = AwesomeMessage.decode(buffer);
+```
+
+#### Using decorators
+
+The library also includes an early implementation of [decorators](https://www.typescriptlang.org/docs/handbook/decorators.html).
+
+**Note** that decorators are an experimental feature in TypeScript and that declaration order is important depending on the JS target. For example, `@Field.d(2, AwesomeArrayMessage)` requires that `AwesomeArrayMessage` has been defined earlier when targeting `ES5`.
+
+```ts
+import { Message, Type, Field, OneOf } from "protobufjs/light"; // respectively "./node_modules/protobufjs/light.js"
+
+export class AwesomeSubMessage extends Message<AwesomeSubMessage> {
+
+  @Field.d(1, "string")
+  public awesomeString: string;
+
+}
+
+export enum AwesomeEnum {
+  ONE = 1,
+  TWO = 2
+}
+
+@Type.d("SuperAwesomeMessage")
+export class AwesomeMessage extends Message<AwesomeMessage> {
+
+  @Field.d(1, "string", "optional", "awesome default string")
+  public awesomeField: string;
+
+  @Field.d(2, AwesomeSubMessage)
+  public awesomeSubMessage: AwesomeSubMessage;
+
+  @Field.d(3, AwesomeEnum, "optional", AwesomeEnum.ONE)
+  public awesomeEnum: AwesomeEnum;
+
+  @OneOf.d("awesomeSubMessage", "awesomeEnum")
+  public which: string;
+
+}
+
+// example code
+let message = new AwesomeMessage({ awesomeField: "hello" });
+let buffer  = AwesomeMessage.encode(message).finish();
+let decoded = AwesomeMessage.decode(buffer);
+```
+
+Supported decorators are:
+
+* **Type.d(typeName?: `string`)** &nbsp; *(optional)*<br />
+  annotates a class as a protobuf message type. If `typeName` is not specified, the constructor's runtime function name is used for the reflected type.
+
+* **Field.d&lt;T>(fieldId: `number`, fieldType: `string | Constructor<T>`, fieldRule?: `"optional" | "required" | "repeated"`, defaultValue?: `T`)**<br />
+  annotates a property as a protobuf field with the specified id and protobuf type.
+
+* **MapField.d&lt;T extends { [key: string]: any }>(fieldId: `number`, fieldKeyType: `string`, fieldValueType. `string | Constructor<{}>`)**<br />
+  annotates a property as a protobuf map field with the specified id, protobuf key and value type.
+
+* **OneOf.d&lt;T extends string>(...fieldNames: `string[]`)**<br />
+  annotates a property as a protobuf oneof covering the specified fields.
+
+Other notes:
+
+* Decorated types reside in `protobuf.roots["decorated"]` using a flat structure, so no duplicate names.
+* Enums are copied to a reflected enum with a generic name on decorator evaluation because referenced enum objects have no runtime name the decorator could use.
+* Default values must be specified as arguments to the decorator instead of using a property initializer for proper prototype behavior.
+* Property names on decorated classes must not be renamed on compile time (i.e. by a minifier) because decorators just receive the original field name as a string.
+
+**ProTip!** Not as pretty, but you can [use decorators in plain JavaScript](https://github.com/dcodeIO/protobuf.js/blob/master/examples/js-decorators.js) as well.
+
+Additional documentation
+------------------------
+
+#### Protocol Buffers
+* [Google's Developer Guide](https://developers.google.com/protocol-buffers/docs/overview)
+
+#### protobuf.js
+* [API Documentation](https://protobufjs.github.io/protobuf.js)
+* [CHANGELOG](https://github.com/dcodeIO/protobuf.js/blob/master/CHANGELOG.md)
+* [Frequently asked questions](https://github.com/dcodeIO/protobuf.js/wiki) on our wiki
+
+#### Community
+* [Questions and answers](http://stackoverflow.com/search?tab=newest&q=protobuf.js) on StackOverflow
+
+Performance
+-----------
+The package includes a benchmark that compares protobuf.js performance to native JSON (as far as this is possible) and [Google's JS implementation](https://github.com/google/protobuf/tree/master/js). On an i7-2600K running node 6.9.1 it yields:
+
+```
+benchmarking encoding performance ...
+
+protobuf.js (reflect) x 541,707 ops/sec ±1.13% (87 runs sampled)
+protobuf.js (static) x 548,134 ops/sec ±1.38% (89 runs sampled)
+JSON (string) x 318,076 ops/sec ±0.63% (93 runs sampled)
+JSON (buffer) x 179,165 ops/sec ±2.26% (91 runs sampled)
+google-protobuf x 74,406 ops/sec ±0.85% (86 runs sampled)
+
+   protobuf.js (static) was fastest
+  protobuf.js (reflect) was 0.9% ops/sec slower (factor 1.0)
+          JSON (string) was 41.5% ops/sec slower (factor 1.7)
+          JSON (buffer) was 67.6% ops/sec slower (factor 3.1)
+        google-protobuf was 86.4% ops/sec slower (factor 7.3)
+
+benchmarking decoding performance ...
+
+protobuf.js (reflect) x 1,383,981 ops/sec ±0.88% (93 runs sampled)
+protobuf.js (static) x 1,378,925 ops/sec ±0.81% (93 runs sampled)
+JSON (string) x 302,444 ops/sec ±0.81% (93 runs sampled)
+JSON (buffer) x 264,882 ops/sec ±0.81% (93 runs sampled)
+google-protobuf x 179,180 ops/sec ±0.64% (94 runs sampled)
+
+  protobuf.js (reflect) was fastest
+   protobuf.js (static) was 0.3% ops/sec slower (factor 1.0)
+          JSON (string) was 78.1% ops/sec slower (factor 4.6)
+          JSON (buffer) was 80.8% ops/sec slower (factor 5.2)
+        google-protobuf was 87.0% ops/sec slower (factor 7.7)
+
+benchmarking combined performance ...
+
+protobuf.js (reflect) x 275,900 ops/sec ±0.78% (90 runs sampled)
+protobuf.js (static) x 290,096 ops/sec ±0.96% (90 runs sampled)
+JSON (string) x 129,381 ops/sec ±0.77% (90 runs sampled)
+JSON (buffer) x 91,051 ops/sec ±0.94% (90 runs sampled)
+google-protobuf x 42,050 ops/sec ±0.85% (91 runs sampled)
+
+   protobuf.js (static) was fastest
+  protobuf.js (reflect) was 4.7% ops/sec slower (factor 1.0)
+          JSON (string) was 55.3% ops/sec slower (factor 2.2)
+          JSON (buffer) was 68.6% ops/sec slower (factor 3.2)
+        google-protobuf was 85.5% ops/sec slower (factor 6.9)
+```
+
+These results are achieved by
+
+* generating type-specific encoders, decoders, verifiers and converters at runtime
+* configuring the reader/writer interface according to the environment
+* using node-specific functionality where beneficial and, of course
+* avoiding unnecessary operations through splitting up [the toolset](#toolset).
+
+You can also run [the benchmark](https://github.com/dcodeIO/protobuf.js/blob/master/bench/index.js) ...
+
+```
+$> npm run bench
+```
+
+and [the profiler](https://github.com/dcodeIO/protobuf.js/blob/master/bench/prof.js) yourself (the latter requires a recent version of node):
+
+```
+$> npm run prof <encode|decode|encode-browser|decode-browser> [iterations=10000000]
+```
+
+Note that as of this writing, the benchmark suite performs significantly slower on node 7.2.0 compared to 6.9.1 because moths.
+
+Compatibility
+-------------
+
+* Works in all modern and not-so-modern browsers except IE8.
+* Because the internals of this package do not rely on `google/protobuf/descriptor.proto`, options are parsed and presented literally.
+* If typed arrays are not supported by the environment, plain arrays will be used instead.
+* Support for pre-ES5 environments (except IE8) can be achieved by [using a polyfill](https://github.com/dcodeIO/protobuf.js/blob/master/scripts/polyfill.js).
+* Support for [Content Security Policy](https://w3c.github.io/webappsec-csp/)-restricted environments (like Chrome extensions without [unsafe-eval](https://developer.chrome.com/extensions/contentSecurityPolicy#relaxing-eval)) can be achieved by generating and using static code instead.
+* If a proper way to work with 64 bit values (uint64, int64 etc.) is required, just install [long.js](https://github.com/dcodeIO/long.js) alongside this library. All 64 bit numbers will then be returned as a `Long` instance instead of a possibly unsafe JavaScript number ([see](https://github.com/dcodeIO/long.js)).
+* For descriptor.proto interoperability, see [ext/descriptor](https://github.com/dcodeIO/protobuf.js/tree/master/ext/descriptor)
+
+Building
+--------
+
+To build the library or its components yourself, clone it from GitHub and install the development dependencies:
+
+```
+$> git clone https://github.com/dcodeIO/protobuf.js.git
+$> cd protobuf.js
+$> npm install
+```
+
+Building the respective development and production versions with their respective source maps to `dist/`:
+
+```
+$> npm run build
+```
+
+Building the documentation to `docs/`:
+
+```
+$> npm run docs
+```
+
+Building the TypeScript definition to `index.d.ts`:
+
+```
+$> npm run types
+```
+
+### Browserify integration
+
+By default, protobuf.js integrates into any browserify build-process without requiring any optional modules. Hence:
+
+* If int64 support is required, explicitly require the `long` module somewhere in your project as it will be excluded otherwise. This assumes that a global `require` function is present that protobuf.js can call to obtain the long module.
+
+  If there is no global `require` function present after bundling, it's also possible to assign the long module programmatically:
+
+  ```js
+  var Long = ...;
+
+  protobuf.util.Long = Long;
+  protobuf.configure();
+  ```
+
+* If you have any special requirements, there is [the bundler](https://github.com/dcodeIO/protobuf.js/blob/master/scripts/bundle.js) for reference.
+
+**License:** [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/bench/data/bench.json b/bench/data/bench.json
new file mode 100644
index 0000000..038c0b8
--- /dev/null
+++ b/bench/data/bench.json
@@ -0,0 +1,21 @@
+{
+    "string" : "Lorem ipsum dolor sit amet.",
+    "uint32" : 9000,
+    "inner" : {
+        "int32" : 20161110,
+        "innerInner" : {
+            "long" : {
+                "low": 1051,
+                "high": 151234,
+                "unsigned": false
+            },
+            "enum" : 1,
+            "sint32": -42
+        },
+        "outer" : {
+            "bool" : [ true, false, false, true, false, false, true ],
+            "double": 204.8
+        }
+    },
+    "float": 0.25
+}
diff --git a/bench/data/bench.proto b/bench/data/bench.proto
new file mode 100644
index 0000000..eec499e
--- /dev/null
+++ b/bench/data/bench.proto
@@ -0,0 +1,40 @@
+syntax = "proto3";
+
+message Test {
+
+    string  string = 1;
+    uint32  uint32 = 2;
+    Inner   inner  = 3;
+    float   float  = 4; // make sure to set something that's fair to JSON
+
+    message Inner {
+
+        int32      int32      = 1;
+        InnerInner innerInner = 2;
+        Outer      outer      = 3;
+
+        message InnerInner {
+
+            int64  long   = 1;
+            Enum   enum   = 2;
+            sint32 sint32 = 3;
+        }
+    }
+
+    enum Enum {
+
+        ONE   = 0;
+        TWO   = 1;
+        THREE = 2;
+        FOUR  = 3;
+        FIVE  = 4;
+    }
+}
+
+message Outer {
+
+    repeated bool bool = 1;
+    double double = 2; // make sure to set something that's fair to JSON
+}
+
+// bytes cannot be used
diff --git a/bench/data/static_jspb.js b/bench/data/static_jspb.js
new file mode 100644
index 0000000..46cb726
--- /dev/null
+++ b/bench/data/static_jspb.js
@@ -0,0 +1,881 @@
+/*eslint-disable*/
+/**
+ * @fileoverview
+ * @enhanceable
+ * @public
+ */
+// GENERATED CODE -- DO NOT EDIT!
+
+var jspb = require('google-protobuf');
+var goog = jspb;
+var global = Function('return this')();
+
+goog.exportSymbol('proto.Outer', null, global);
+goog.exportSymbol('proto.Test', null, global);
+goog.exportSymbol('proto.Test.Enum', null, global);
+goog.exportSymbol('proto.Test.Inner', null, global);
+goog.exportSymbol('proto.Test.Inner.InnerInner', null, global);
+
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.Test = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.Test, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.Test.displayName = 'proto.Test';
+}
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto suitable for use in Soy templates.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.Test.prototype.toObject = function(opt_includeInstance) {
+  return proto.Test.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Whether to include the JSPB
+ *     instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.Test} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.Test.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    string: jspb.Message.getFieldWithDefault(msg, 1, ""),
+    uint32: jspb.Message.getFieldWithDefault(msg, 2, 0),
+    inner: (f = msg.getInner()) && proto.Test.Inner.toObject(includeInstance, f),
+    pb_float: +jspb.Message.getFieldWithDefault(msg, 4, 0.0)
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg;
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.Test}
+ */
+proto.Test.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.Test;
+  return proto.Test.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.Test} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.Test}
+ */
+proto.Test.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setString(value);
+      break;
+    case 2:
+      var value = /** @type {number} */ (reader.readUint32());
+      msg.setUint32(value);
+      break;
+    case 3:
+      var value = new proto.Test.Inner;
+      reader.readMessage(value,proto.Test.Inner.deserializeBinaryFromReader);
+      msg.setInner(value);
+      break;
+    case 4:
+      var value = /** @type {number} */ (reader.readFloat());
+      msg.setFloat(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.Test.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  proto.Test.serializeBinaryToWriter(this, writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the given message to binary data (in protobuf wire
+ * format), writing to the given BinaryWriter.
+ * @param {!proto.Test} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.Test.serializeBinaryToWriter = function(message, writer) {
+  var f = undefined;
+  f = message.getString();
+  if (f.length > 0) {
+    writer.writeString(
+      1,
+      f
+    );
+  }
+  f = message.getUint32();
+  if (f !== 0) {
+    writer.writeUint32(
+      2,
+      f
+    );
+  }
+  f = message.getInner();
+  if (f != null) {
+    writer.writeMessage(
+      3,
+      f,
+      proto.Test.Inner.serializeBinaryToWriter
+    );
+  }
+  f = message.getFloat();
+  if (f !== 0.0) {
+    writer.writeFloat(
+      4,
+      f
+    );
+  }
+};
+
+
+/**
+ * @enum {number}
+ */
+proto.Test.Enum = {
+  ONE: 0,
+  TWO: 1,
+  THREE: 2,
+  FOUR: 3,
+  FIVE: 4
+};
+
+
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.Test.Inner = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.Test.Inner, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.Test.Inner.displayName = 'proto.Test.Inner';
+}
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto suitable for use in Soy templates.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.Test.Inner.prototype.toObject = function(opt_includeInstance) {
+  return proto.Test.Inner.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Whether to include the JSPB
+ *     instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.Test.Inner} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.Test.Inner.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    int32: jspb.Message.getFieldWithDefault(msg, 1, 0),
+    innerinner: (f = msg.getInnerinner()) && proto.Test.Inner.InnerInner.toObject(includeInstance, f),
+    outer: (f = msg.getOuter()) && proto.Outer.toObject(includeInstance, f)
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg;
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.Test.Inner}
+ */
+proto.Test.Inner.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.Test.Inner;
+  return proto.Test.Inner.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.Test.Inner} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.Test.Inner}
+ */
+proto.Test.Inner.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {number} */ (reader.readInt32());
+      msg.setInt32(value);
+      break;
+    case 2:
+      var value = new proto.Test.Inner.InnerInner;
+      reader.readMessage(value,proto.Test.Inner.InnerInner.deserializeBinaryFromReader);
+      msg.setInnerinner(value);
+      break;
+    case 3:
+      var value = new proto.Outer;
+      reader.readMessage(value,proto.Outer.deserializeBinaryFromReader);
+      msg.setOuter(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.Test.Inner.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  proto.Test.Inner.serializeBinaryToWriter(this, writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the given message to binary data (in protobuf wire
+ * format), writing to the given BinaryWriter.
+ * @param {!proto.Test.Inner} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.Test.Inner.serializeBinaryToWriter = function(message, writer) {
+  var f = undefined;
+  f = message.getInt32();
+  if (f !== 0) {
+    writer.writeInt32(
+      1,
+      f
+    );
+  }
+  f = message.getInnerinner();
+  if (f != null) {
+    writer.writeMessage(
+      2,
+      f,
+      proto.Test.Inner.InnerInner.serializeBinaryToWriter
+    );
+  }
+  f = message.getOuter();
+  if (f != null) {
+    writer.writeMessage(
+      3,
+      f,
+      proto.Outer.serializeBinaryToWriter
+    );
+  }
+};
+
+
+
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.Test.Inner.InnerInner = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.Test.Inner.InnerInner, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.Test.Inner.InnerInner.displayName = 'proto.Test.Inner.InnerInner';
+}
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto suitable for use in Soy templates.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.Test.Inner.InnerInner.prototype.toObject = function(opt_includeInstance) {
+  return proto.Test.Inner.InnerInner.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Whether to include the JSPB
+ *     instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.Test.Inner.InnerInner} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.Test.Inner.InnerInner.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    pb_long: jspb.Message.getFieldWithDefault(msg, 1, 0),
+    pb_enum: jspb.Message.getFieldWithDefault(msg, 2, 0),
+    sint32: jspb.Message.getFieldWithDefault(msg, 3, 0)
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg;
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.Test.Inner.InnerInner}
+ */
+proto.Test.Inner.InnerInner.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.Test.Inner.InnerInner;
+  return proto.Test.Inner.InnerInner.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.Test.Inner.InnerInner} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.Test.Inner.InnerInner}
+ */
+proto.Test.Inner.InnerInner.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {number} */ (reader.readInt64());
+      msg.setLong(value);
+      break;
+    case 2:
+      var value = /** @type {!proto.Test.Enum} */ (reader.readEnum());
+      msg.setEnum(value);
+      break;
+    case 3:
+      var value = /** @type {number} */ (reader.readSint32());
+      msg.setSint32(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.Test.Inner.InnerInner.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  proto.Test.Inner.InnerInner.serializeBinaryToWriter(this, writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the given message to binary data (in protobuf wire
+ * format), writing to the given BinaryWriter.
+ * @param {!proto.Test.Inner.InnerInner} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.Test.Inner.InnerInner.serializeBinaryToWriter = function(message, writer) {
+  var f = undefined;
+  f = message.getLong();
+  if (f !== 0) {
+    writer.writeInt64(
+      1,
+      f
+    );
+  }
+  f = message.getEnum();
+  if (f !== 0.0) {
+    writer.writeEnum(
+      2,
+      f
+    );
+  }
+  f = message.getSint32();
+  if (f !== 0) {
+    writer.writeSint32(
+      3,
+      f
+    );
+  }
+};
+
+
+/**
+ * optional int64 long = 1;
+ * @return {number}
+ */
+proto.Test.Inner.InnerInner.prototype.getLong = function() {
+  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0));
+};
+
+
+/** @param {number} value */
+proto.Test.Inner.InnerInner.prototype.setLong = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+/**
+ * optional Enum enum = 2;
+ * @return {!proto.Test.Enum}
+ */
+proto.Test.Inner.InnerInner.prototype.getEnum = function() {
+  return /** @type {!proto.Test.Enum} */ (jspb.Message.getFieldWithDefault(this, 2, 0));
+};
+
+
+/** @param {!proto.Test.Enum} value */
+proto.Test.Inner.InnerInner.prototype.setEnum = function(value) {
+  jspb.Message.setField(this, 2, value);
+};
+
+
+/**
+ * optional sint32 sint32 = 3;
+ * @return {number}
+ */
+proto.Test.Inner.InnerInner.prototype.getSint32 = function() {
+  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0));
+};
+
+
+/** @param {number} value */
+proto.Test.Inner.InnerInner.prototype.setSint32 = function(value) {
+  jspb.Message.setField(this, 3, value);
+};
+
+
+/**
+ * optional int32 int32 = 1;
+ * @return {number}
+ */
+proto.Test.Inner.prototype.getInt32 = function() {
+  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0));
+};
+
+
+/** @param {number} value */
+proto.Test.Inner.prototype.setInt32 = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+/**
+ * optional InnerInner innerInner = 2;
+ * @return {?proto.Test.Inner.InnerInner}
+ */
+proto.Test.Inner.prototype.getInnerinner = function() {
+  return /** @type{?proto.Test.Inner.InnerInner} */ (
+    jspb.Message.getWrapperField(this, proto.Test.Inner.InnerInner, 2));
+};
+
+
+/** @param {?proto.Test.Inner.InnerInner|undefined} value */
+proto.Test.Inner.prototype.setInnerinner = function(value) {
+  jspb.Message.setWrapperField(this, 2, value);
+};
+
+
+proto.Test.Inner.prototype.clearInnerinner = function() {
+  this.setInnerinner(undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {!boolean}
+ */
+proto.Test.Inner.prototype.hasInnerinner = function() {
+  return jspb.Message.getField(this, 2) != null;
+};
+
+
+/**
+ * optional Outer outer = 3;
+ * @return {?proto.Outer}
+ */
+proto.Test.Inner.prototype.getOuter = function() {
+  return /** @type{?proto.Outer} */ (
+    jspb.Message.getWrapperField(this, proto.Outer, 3));
+};
+
+
+/** @param {?proto.Outer|undefined} value */
+proto.Test.Inner.prototype.setOuter = function(value) {
+  jspb.Message.setWrapperField(this, 3, value);
+};
+
+
+proto.Test.Inner.prototype.clearOuter = function() {
+  this.setOuter(undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {!boolean}
+ */
+proto.Test.Inner.prototype.hasOuter = function() {
+  return jspb.Message.getField(this, 3) != null;
+};
+
+
+/**
+ * optional string string = 1;
+ * @return {string}
+ */
+proto.Test.prototype.getString = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
+};
+
+
+/** @param {string} value */
+proto.Test.prototype.setString = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+/**
+ * optional uint32 uint32 = 2;
+ * @return {number}
+ */
+proto.Test.prototype.getUint32 = function() {
+  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0));
+};
+
+
+/** @param {number} value */
+proto.Test.prototype.setUint32 = function(value) {
+  jspb.Message.setField(this, 2, value);
+};
+
+
+/**
+ * optional Inner inner = 3;
+ * @return {?proto.Test.Inner}
+ */
+proto.Test.prototype.getInner = function() {
+  return /** @type{?proto.Test.Inner} */ (
+    jspb.Message.getWrapperField(this, proto.Test.Inner, 3));
+};
+
+
+/** @param {?proto.Test.Inner|undefined} value */
+proto.Test.prototype.setInner = function(value) {
+  jspb.Message.setWrapperField(this, 3, value);
+};
+
+
+proto.Test.prototype.clearInner = function() {
+  this.setInner(undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {!boolean}
+ */
+proto.Test.prototype.hasInner = function() {
+  return jspb.Message.getField(this, 3) != null;
+};
+
+
+/**
+ * optional float float = 4;
+ * @return {number}
+ */
+proto.Test.prototype.getFloat = function() {
+  return /** @type {number} */ (+jspb.Message.getFieldWithDefault(this, 4, 0.0));
+};
+
+
+/** @param {number} value */
+proto.Test.prototype.setFloat = function(value) {
+  jspb.Message.setField(this, 4, value);
+};
+
+
+
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.Outer = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, proto.Outer.repeatedFields_, null);
+};
+goog.inherits(proto.Outer, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.Outer.displayName = 'proto.Outer';
+}
+/**
+ * List of repeated fields within this message type.
+ * @private {!Array<number>}
+ * @const
+ */
+proto.Outer.repeatedFields_ = [1];
+
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto suitable for use in Soy templates.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.Outer.prototype.toObject = function(opt_includeInstance) {
+  return proto.Outer.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Whether to include the JSPB
+ *     instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.Outer} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.Outer.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    boolList: jspb.Message.getField(msg, 1),
+    pb_double: +jspb.Message.getFieldWithDefault(msg, 2, 0.0)
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg;
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.Outer}
+ */
+proto.Outer.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.Outer;
+  return proto.Outer.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.Outer} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.Outer}
+ */
+proto.Outer.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {!Array.<boolean>} */ (reader.readPackedBool());
+      msg.setBoolList(value);
+      break;
+    case 2:
+      var value = /** @type {number} */ (reader.readDouble());
+      msg.setDouble(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.Outer.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  proto.Outer.serializeBinaryToWriter(this, writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the given message to binary data (in protobuf wire
+ * format), writing to the given BinaryWriter.
+ * @param {!proto.Outer} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.Outer.serializeBinaryToWriter = function(message, writer) {
+  var f = undefined;
+  f = message.getBoolList();
+  if (f.length > 0) {
+    writer.writePackedBool(
+      1,
+      f
+    );
+  }
+  f = message.getDouble();
+  if (f !== 0.0) {
+    writer.writeDouble(
+      2,
+      f
+    );
+  }
+};
+
+
+/**
+ * repeated bool bool = 1;
+ * Note that Boolean fields may be set to 0/1 when serialized from a Java server.
+ * You should avoid comparisons like {@code val === true/false} in those cases.
+ * If you change this array by adding, removing or replacing elements, or if you
+ * replace the array itself, then you must call the setter to update it.
+ * @return {!Array.<boolean>}
+ */
+proto.Outer.prototype.getBoolList = function() {
+  return /** @type {!Array.<boolean>} */ (jspb.Message.getField(this, 1));
+};
+
+
+/** @param {!Array.<boolean>} value */
+proto.Outer.prototype.setBoolList = function(value) {
+  jspb.Message.setField(this, 1, value || []);
+};
+
+
+/**
+ * @param {!boolean} value
+ * @param {number=} opt_index
+ */
+proto.Outer.prototype.addBool = function(value, opt_index) {
+  jspb.Message.addToRepeatedField(this, 1, value, opt_index);
+};
+
+
+proto.Outer.prototype.clearBoolList = function() {
+  this.setBoolList([]);
+};
+
+
+/**
+ * optional double double = 2;
+ * @return {number}
+ */
+proto.Outer.prototype.getDouble = function() {
+  return /** @type {number} */ (+jspb.Message.getFieldWithDefault(this, 2, 0.0));
+};
+
+
+/** @param {number} value */
+proto.Outer.prototype.setDouble = function(value) {
+  jspb.Message.setField(this, 2, value);
+};
+
+
+goog.object.extend(exports, proto);
diff --git a/bench/data/static_pbjs.js b/bench/data/static_pbjs.js
new file mode 100644
index 0000000..b1bcfc8
--- /dev/null
+++ b/bench/data/static_pbjs.js
@@ -0,0 +1,240 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+"use strict";
+
+var $protobuf = require("../../minimal");
+
+var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+var $root = $protobuf.roots.test_bench || ($protobuf.roots.test_bench = {});
+
+$root.Test = (function() {
+
+    function Test(properties) {
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    Test.prototype.string = "";
+    Test.prototype.uint32 = 0;
+    Test.prototype.inner = null;
+    Test.prototype.float = 0;
+
+    Test.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.string != null && Object.hasOwnProperty.call(message, "string"))
+            writer.uint32(10).string(message.string);
+        if (message.uint32 != null && Object.hasOwnProperty.call(message, "uint32"))
+            writer.uint32(16).uint32(message.uint32);
+        if (message.inner != null && Object.hasOwnProperty.call(message, "inner"))
+            $root.Test.Inner.encode(message.inner, writer.uint32(26).fork()).ldelim();
+        if (message.float != null && Object.hasOwnProperty.call(message, "float"))
+            writer.uint32(37).float(message.float);
+        return writer;
+    };
+
+    Test.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Test();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 1:
+                message.string = reader.string();
+                break;
+            case 2:
+                message.uint32 = reader.uint32();
+                break;
+            case 3:
+                message.inner = $root.Test.Inner.decode(reader, reader.uint32());
+                break;
+            case 4:
+                message.float = reader.float();
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    Test.Inner = (function() {
+
+        function Inner(properties) {
+            if (properties)
+                for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                    if (properties[keys[i]] != null)
+                        this[keys[i]] = properties[keys[i]];
+        }
+
+        Inner.prototype.int32 = 0;
+        Inner.prototype.innerInner = null;
+        Inner.prototype.outer = null;
+
+        Inner.encode = function encode(message, writer) {
+            if (!writer)
+                writer = $Writer.create();
+            if (message.int32 != null && Object.hasOwnProperty.call(message, "int32"))
+                writer.uint32(8).int32(message.int32);
+            if (message.innerInner != null && Object.hasOwnProperty.call(message, "innerInner"))
+                $root.Test.Inner.InnerInner.encode(message.innerInner, writer.uint32(18).fork()).ldelim();
+            if (message.outer != null && Object.hasOwnProperty.call(message, "outer"))
+                $root.Outer.encode(message.outer, writer.uint32(26).fork()).ldelim();
+            return writer;
+        };
+
+        Inner.decode = function decode(reader, length) {
+            if (!(reader instanceof $Reader))
+                reader = $Reader.create(reader);
+            var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Test.Inner();
+            while (reader.pos < end) {
+                var tag = reader.uint32();
+                switch (tag >>> 3) {
+                case 1:
+                    message.int32 = reader.int32();
+                    break;
+                case 2:
+                    message.innerInner = $root.Test.Inner.InnerInner.decode(reader, reader.uint32());
+                    break;
+                case 3:
+                    message.outer = $root.Outer.decode(reader, reader.uint32());
+                    break;
+                default:
+                    reader.skipType(tag & 7);
+                    break;
+                }
+            }
+            return message;
+        };
+
+        Inner.InnerInner = (function() {
+
+            function InnerInner(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            InnerInner.prototype.long = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
+            InnerInner.prototype["enum"] = 0;
+            InnerInner.prototype.sint32 = 0;
+
+            InnerInner.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.long != null && Object.hasOwnProperty.call(message, "long"))
+                    writer.uint32(8).int64(message.long);
+                if (message["enum"] != null && Object.hasOwnProperty.call(message, "enum"))
+                    writer.uint32(16).int32(message["enum"]);
+                if (message.sint32 != null && Object.hasOwnProperty.call(message, "sint32"))
+                    writer.uint32(24).sint32(message.sint32);
+                return writer;
+            };
+
+            InnerInner.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Test.Inner.InnerInner();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.long = reader.int64();
+                        break;
+                    case 2:
+                        message["enum"] = reader.int32();
+                        break;
+                    case 3:
+                        message.sint32 = reader.sint32();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            return InnerInner;
+        })();
+
+        return Inner;
+    })();
+
+    Test.Enum = (function() {
+        var valuesById = {}, values = Object.create(valuesById);
+        values[valuesById[0] = "ONE"] = 0;
+        values[valuesById[1] = "TWO"] = 1;
+        values[valuesById[2] = "THREE"] = 2;
+        values[valuesById[3] = "FOUR"] = 3;
+        values[valuesById[4] = "FIVE"] = 4;
+        return values;
+    })();
+
+    return Test;
+})();
+
+$root.Outer = (function() {
+
+    function Outer(properties) {
+        this.bool = [];
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    Outer.prototype.bool = $util.emptyArray;
+    Outer.prototype.double = 0;
+
+    Outer.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.bool != null && message.bool.length) {
+            writer.uint32(10).fork();
+            for (var i = 0; i < message.bool.length; ++i)
+                writer.bool(message.bool[i]);
+            writer.ldelim();
+        }
+        if (message.double != null && Object.hasOwnProperty.call(message, "double"))
+            writer.uint32(17).double(message.double);
+        return writer;
+    };
+
+    Outer.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Outer();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 1:
+                if (!(message.bool && message.bool.length))
+                    message.bool = [];
+                if ((tag & 7) === 2) {
+                    var end2 = reader.uint32() + reader.pos;
+                    while (reader.pos < end2)
+                        message.bool.push(reader.bool());
+                } else
+                    message.bool.push(reader.bool());
+                break;
+            case 2:
+                message.double = reader.double();
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    return Outer;
+})();
+
+module.exports = $root;
diff --git a/bench/index.js b/bench/index.js
new file mode 100644
index 0000000..7a8a55f
--- /dev/null
+++ b/bench/index.js
@@ -0,0 +1,90 @@
+"use strict";
+
+// NOTE: This benchmark partly compares apples and oranges in that it measures protocol buffers,
+// which is purely a binary format, and JSON, which is purely a string format.
+//
+// This matters because strings aren't actually transfered over the network but must still be
+// converted to binary somewhere down the road. Because this can't be measured reliably, this
+// benchmark compares both pure string performance of JSON and additional binary conversion of the
+// same data using node buffers. Actual JSON performance on the network level should be somewhere
+// in between.
+
+var newSuite  = require("./suite"),
+    payload   = require("./data/bench.json");
+
+var Buffer_from = Buffer.from !== Uint8Array.from && Buffer.from || function(value, encoding) { return new Buffer(value, encoding); };
+
+// protobuf.js dynamic: load the proto and set up a buffer
+var pbjsCls = require("..").loadSync(require.resolve("./data/bench.proto")).resolveAll().lookup("Test");
+var pbjsMsg = payload; // alt: pbjsCls.fromObject(payload);
+var pbjsBuf = pbjsCls.encode(pbjsMsg).finish();
+
+// protobuf.js static: load the proto
+var pbjsStaticCls = require("./data/static_pbjs.js").Test;
+
+// JSON: set up a string and a buffer
+var jsonMsg = payload;
+var jsonStr = JSON.stringify(jsonMsg);
+var jsonBuf = Buffer_from(jsonStr, "utf8");
+
+// google-protobuf: load the proto, set up an Uint8Array and a message
+var jspbCls = require("./data/static_jspb.js").Test;
+var jspbBuf = new Uint8Array(Array.prototype.slice.call(pbjsBuf));
+var jspbMsg = jspbCls.deserializeBinary(jspbBuf);
+
+newSuite("encoding")
+
+.add("protobuf.js (reflect)", function() {
+    pbjsCls.encode(pbjsMsg).finish();
+})
+.add("protobuf.js (static)", function() {
+    pbjsStaticCls.encode(pbjsMsg).finish();
+})
+.add("JSON (string)", function() {
+    JSON.stringify(jsonMsg);
+})
+.add("JSON (buffer)", function() {
+    Buffer_from(JSON.stringify(jsonMsg), "utf8");
+})
+.add("google-protobuf", function() {
+    jspbMsg.serializeBinary();
+})
+.run();
+
+newSuite("decoding")
+
+.add("protobuf.js (reflect)", function() {
+    pbjsCls.decode(pbjsBuf); // no allocation overhead, if you wondered
+})
+.add("protobuf.js (static)", function() {
+    pbjsStaticCls.decode(pbjsBuf);
+})
+.add("JSON (string)", function() {
+    JSON.parse(jsonStr);
+})
+.add("JSON (buffer)", function() {
+    JSON.parse(jsonBuf.toString("utf8"));
+})
+.add("google-protobuf", function() {
+    jspbCls.deserializeBinary(jspbBuf);
+})
+.run();
+
+newSuite("combined")
+
+.add("protobuf.js (reflect)", function() {
+    pbjsCls.decode(pbjsCls.encode(pbjsMsg).finish());
+})
+.add("protobuf.js (static)", function() {
+    pbjsStaticCls.decode(pbjsStaticCls.encode(pbjsMsg).finish());
+})
+.add("JSON (string)", function() {
+    JSON.parse(JSON.stringify(jsonMsg));
+})
+.add("JSON (buffer)", function() {
+    JSON.parse(Buffer_from(JSON.stringify(jsonMsg), "utf8").toString("utf8"));
+})
+.add("google-protobuf", function() {
+    jspbCls.deserializeBinary(jspbMsg.serializeBinary());
+})
+.run();
diff --git a/bench/prof.js b/bench/prof.js
new file mode 100644
index 0000000..4c3497a
--- /dev/null
+++ b/bench/prof.js
@@ -0,0 +1,102 @@
+"use strict";
+
+var fs   = require("fs"),
+    path = require("path");
+
+// A profiling stub to measure encoding / decoding performance using benchmark data.
+
+var commands = ["encode", "decode", "encode-browser", "decode-browser", "fromjson"];
+if (commands.indexOf(process.argv[2]) < 0) { // 0: node, 1: prof.js
+    process.stderr.write("usage: " + path.basename(process.argv[1]) + " <" + commands.join("|") + "> [iterations=10000000]\n");
+    return;
+}
+
+// Spin up a node process with profiling enabled and process the generated log
+if (process.execArgv.indexOf("--prof") < 0) {
+    process.stdout.write("cleaning up old logs ...\n");
+    var child_process = require("child_process");
+    var logRe = /^isolate-[0-9A-F]+-v8\.log$/;
+    fs.readdirSync(process.cwd()).forEach(function readdirSync_it(file) {
+        if (logRe.test(file))
+            fs.unlink(file);
+    });
+    process.stdout.write("generating profile (may take a while) ...\n");
+    child_process.execSync("node --prof --trace-deopt " + process.execArgv.join(" ") + " " + process.argv.slice(1).join(" "), {
+        cwd: process.cwd(),
+        stdio: "inherit"
+    });
+    process.stdout.write("processing profile ...\n");
+    fs.readdirSync(process.cwd()).forEach(function readdirSync_it(file) {
+        if (logRe.test(file)) {
+            child_process.execSync("node --prof-process " + file, {
+                cwd: process.cwd(),
+                stdio: "inherit"
+            });
+            // fs.unlink(file);
+        }
+    });
+    process.stdout.write("done.\n");
+    return;
+}
+
+// Actual profiling code
+var protobuf = require("..");
+
+// protobuf.util.codegen.verbose = true;
+
+var root, json;
+
+if (process.argv[2] === "fromjson") {
+    json = require("../tests/data/test.json");
+    if (process.argv.indexOf("--resolve") < 0)
+        for (var k = 0; k < 10000; ++k)
+            protobuf.Root.fromJSON(json);
+    else
+        for (var l = 0; l < 10000; ++l)
+            protobuf.Root.fromJSON(json).resolveAll();
+    return;
+}
+
+var Test, data, count;
+
+if (process.argv.indexOf("--alt") < 0) {
+    root = protobuf.parse(fs.readFileSync(require.resolve("../bench/data/bench.proto")).toString("utf8")).root;
+    Test = root.lookup("Test");
+    json = JSON.stringify(root);
+    data = require("../bench/data/bench.json");
+    count = 10000000;
+    process.stdout.write("bench.proto");
+} else {
+    root = protobuf.parse(fs.readFileSync(require.resolve("../tests/data/mapbox/vector_tile.proto")).toString("utf8")).root;
+    Test = root.lookup("vector_tile.Tile");
+    data = Test.decode(fs.readFileSync(require.resolve("../tests/data/mapbox/vector_tile.bin")));
+    count = 1000;
+    process.stdout.write("vector_tile.proto");
+}
+
+if (process.argv.length > 3 && /^\d+$/.test(process.argv[3]))
+    count = parseInt(process.argv[3], 10);
+process.stdout.write(" x " + count + "\n");
+
+function setupBrowser() {
+    protobuf.Writer.create = function create_browser() { return new protobuf.Writer(); };
+    protobuf.Reader.create = function create_browser(buf) { return new protobuf.Reader(buf); };
+}
+
+switch (process.argv[2]) {
+    case "encode-browser":
+        setupBrowser();
+        // eslint-disable-line no-fallthrough
+    case "encode":
+        for (var i = 0; i < count; ++i)
+            Test.encode(data).finish();
+        break;
+    case "decode-browser":
+        setupBrowser();
+        // eslint-disable-line no-fallthrough
+    case "decode":
+        var buf = Test.encode(data).finish();
+        for (var j = 0; j < count; ++j)
+            Test.decode(buf);
+        break;
+}
diff --git a/bench/suite.js b/bench/suite.js
new file mode 100644
index 0000000..aa5cc7f
--- /dev/null
+++ b/bench/suite.js
@@ -0,0 +1,45 @@
+"use strict";
+module.exports = newSuite;
+
+var benchmark = require("benchmark"),
+    chalk     = require("chalk");
+
+var padSize = 23;
+
+function newSuite(name) {
+    var benches = [];
+    return new benchmark.Suite(name)
+    .on("add", function(event) {
+        benches.push(event.target);
+    })
+    .on("start", function() {
+        process.stdout.write(chalk.white.bold("benchmarking " + name + " performance ...") + "\n\n");
+    })
+    .on("cycle", function(event) {
+        process.stdout.write(String(event.target) + "\n");
+    })
+    .on("complete", function() {
+        if (benches.length > 1) {
+            benches.sort(function(a, b) { return getHz(b) - getHz(a); });
+            var fastest   = benches[0],
+                fastestHz = getHz(fastest);
+            process.stdout.write("\n" + chalk.white(pad(fastest.name, padSize)) + " was " + chalk.green("fastest") + "\n");
+            benches.slice(1).forEach(function(bench) {
+                var hz = getHz(bench);
+                var percent = 1 - hz / fastestHz;
+                process.stdout.write(chalk.white(pad(bench.name, padSize)) + " was " + chalk.red((percent * 100).toFixed(1) + "% ops/sec slower (factor " + (fastestHz / hz).toFixed(1) + ")") + "\n");
+            });
+        }
+        process.stdout.write("\n");
+    });
+}
+
+function getHz(bench) {
+    return 1 / (bench.stats.mean + bench.stats.moe);
+}
+
+function pad(str, len, l) {
+    while (str.length < len)
+        str = l ? str + " " : " " + str;
+    return str;
+}
diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md
new file mode 100644
index 0000000..732706d
--- /dev/null
+++ b/cli/CHANGELOG.md
@@ -0,0 +1,62 @@
+# Changelog
+
+## [1.1.1](https://github.com/protobufjs/protobuf.js/compare/protobufjs-cli-v1.1.0...protobufjs-cli-v1.1.1) (2023-02-02)
+
+
+### Bug Fixes
+
+* **cli:** fix relative path to Google pb files ([#1859](https://github.com/protobufjs/protobuf.js/issues/1859)) ([e42eea4](https://github.com/protobufjs/protobuf.js/commit/e42eea4868b11f4a07934804a56683321ed191e2))
+
+## [1.1.0](https://github.com/protobufjs/protobuf.js/compare/protobufjs-cli-v1.0.2...protobufjs-cli-v1.1.0) (2023-01-24)
+
+
+### Features
+
+* **cli:** generate static files at the granularity of proto messages ([#1840](https://github.com/protobufjs/protobuf.js/issues/1840)) ([32f2d6a](https://github.com/protobufjs/protobuf.js/commit/32f2d6a68b27997bd0f7619998695a9fa7a4fd70))
+
+## [1.0.2](https://github.com/protobufjs/protobuf.js/compare/protobufjs-cli-v1.0.1...protobufjs-cli-v1.0.2) (2022-09-09)
+
+
+### Bug Fixes
+
+* add import long to the generated .d.ts ([#1802](https://github.com/protobufjs/protobuf.js/issues/1802)) ([7c27b5a](https://github.com/protobufjs/protobuf.js/commit/7c27b5ad5d161c9f3711aa053ca704f8e1224e90))
+
+## [1.0.1](https://github.com/protobufjs/protobuf.js/compare/protobufjs-cli-v1.0.0...protobufjs-cli-v1.0.1) (2022-08-26)
+
+
+### Bug Fixes
+
+* **deps:** update dependency glob to v8 ([#1750](https://github.com/protobufjs/protobuf.js/issues/1750)) ([8303a64](https://github.com/protobufjs/protobuf.js/commit/8303a648bc12dcea5aa8e7efa042de39011857f9))
+* remove unused `@types/long` ([#1785](https://github.com/protobufjs/protobuf.js/issues/1785)) ([0f4af83](https://github.com/protobufjs/protobuf.js/commit/0f4af83e4ed3cef1ec035c2833e0b06cab0bd87f))
+* **types:** update type deps ([#1776](https://github.com/protobufjs/protobuf.js/issues/1776)) ([d87978b](https://github.com/protobufjs/protobuf.js/commit/d87978b8eb2a176676c58379a89206b94a6d926a))
+
+## [1.0.0](https://github.com/protobufjs/protobuf.js/compare/protobufjs-cli-v0.1.0...protobufjs-cli-v1.0.0) (2022-07-08)
+
+
+### ⚠ BREAKING CHANGES
+
+* drop support for Node 4, 6, 8, 10 (#1764)
+* move command line tool to a new package named protobufjs-cli (#1234)
+
+### Features
+
+* add --no-service option for pbjs static target ([#1577](https://github.com/protobufjs/protobuf.js/issues/1577)) ([d01394a](https://github.com/protobufjs/protobuf.js/commit/d01394a1463062824c066b653aad53c449752202))
+* add alt-comment CLI option ([#1692](https://github.com/protobufjs/protobuf.js/issues/1692)) ([7558ef0](https://github.com/protobufjs/protobuf.js/commit/7558ef0f93177978272f68f1710144a26b63e525))
+* add getTypeUrl method to generated code ([#1463](https://github.com/protobufjs/protobuf.js/issues/1463)) ([d13d5d5](https://github.com/protobufjs/protobuf.js/commit/d13d5d5688052e366aa2e9169f50dfca376b32cf))
+* add null-defaults option ([#1611](https://github.com/protobufjs/protobuf.js/issues/1611)) ([6e713ba](https://github.com/protobufjs/protobuf.js/commit/6e713baf54bd987ae52cbf92a4f2742c70201dc0))
+* add support for buffer configuration ([#1372](https://github.com/protobufjs/protobuf.js/issues/1372)) ([101aa1a](https://github.com/protobufjs/protobuf.js/commit/101aa1a4f148516fdc83a74f54a229f06e24a5de))
+* allow message.getTypeUrl provide custom typeUrlPrefix ([#1762](https://github.com/protobufjs/protobuf.js/issues/1762)) ([8aad1dd](https://github.com/protobufjs/protobuf.js/commit/8aad1dd994b1fc1f23bd71adf3a81b7a5616b210))
+* move command line tool to a new package named protobufjs-cli ([#1234](https://github.com/protobufjs/protobuf.js/issues/1234)) ([da34f43](https://github.com/protobufjs/protobuf.js/commit/da34f43ccd51ad97017e139f137521782f5ef119))
+* prepare initial publication of cli ([#1752](https://github.com/protobufjs/protobuf.js/issues/1752)) ([64811d5](https://github.com/protobufjs/protobuf.js/commit/64811d5878c31e4a86a39da5fec6aea35da22fcd))
+* proto3 optional support ([#1584](https://github.com/protobufjs/protobuf.js/issues/1584)) ([6c4d307](https://github.com/protobufjs/protobuf.js/commit/6c4d30716a9a756dcdc21d64f9c9d069315fc5b1))
+* update dependencies / general cleanup ([#1356](https://github.com/protobufjs/protobuf.js/issues/1356)) ([42f49b4](https://github.com/protobufjs/protobuf.js/commit/42f49b43f692c24c2bc1ae081b4d1ad9fa173cd7))
+
+
+### Bug Fixes
+
+* **deps:** patch minimatch vulnerability ([#1704](https://github.com/protobufjs/protobuf.js/issues/1704)) ([bac61b8](https://github.com/protobufjs/protobuf.js/commit/bac61b8c2757804bbb9c5fa0f8bc6a7bcf0bb374))
+* drop support for Node 4, 6, 8, 10 ([#1764](https://github.com/protobufjs/protobuf.js/issues/1764)) ([50370dd](https://github.com/protobufjs/protobuf.js/commit/50370dd7747a0986e83ddbe51c54b97033af5ead))
+* es6 export enum ([#1446](https://github.com/protobufjs/protobuf.js/issues/1446)) ([9f33784](https://github.com/protobufjs/protobuf.js/commit/9f33784350b1efc2e774bbfc087cbd2c47828748))
+* fromObject should not initialize oneof members ([#1597](https://github.com/protobufjs/protobuf.js/issues/1597)) ([90afe44](https://github.com/protobufjs/protobuf.js/commit/90afe4412de8070b0c0681e5905a6e0213072a85))
+* proper relative path to protobufjs in cli ([#1753](https://github.com/protobufjs/protobuf.js/issues/1753)) ([a1d6029](https://github.com/protobufjs/protobuf.js/commit/a1d60292ecb22fcf89c493c562ae07ab10ef49c9))
+* typo in pbjs help text ([#1552](https://github.com/protobufjs/protobuf.js/issues/1552)) ([7f46dbe](https://github.com/protobufjs/protobuf.js/commit/7f46dbeb538a6277035a896e1ab5e1a070e28681))
diff --git a/cli/LICENSE b/cli/LICENSE
new file mode 100644
index 0000000..e5f7a5c
--- /dev/null
+++ b/cli/LICENSE
@@ -0,0 +1,33 @@
+Copyright (c) 2016, Daniel Wirtz  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 its author, 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
+
+---
+
+Code generated by the command line utilities is owned by the owner
+of the input file used when generating it. This code is not
+standalone and requires a support library to be linked with it. This
+support library is itself covered by the above license.
diff --git a/cli/README.md b/cli/README.md
new file mode 100644
index 0000000..e7f1890
--- /dev/null
+++ b/cli/README.md
@@ -0,0 +1,173 @@
+protobufjs-cli
+==============
+[![npm](https://img.shields.io/npm/v/protobufjs-cli.svg)](https://www.npmjs.com/package/protobufjs-cli)
+
+Command line interface (CLI) for [protobuf.js](https://github.com/dcodeIO/protobuf.js).
+
+This can be used to translate between file formats and to generate static code as well as TypeScript definitions.
+
+* [pbjs for JavaScript](#pbjs-for-javascript)
+* [pbts for TypeScript](#pbts-for-typescript)
+* [Reflection vs. static code](#reflection-vs-static-code)
+* [Command line API](#command-line-api)<br />
+
+### pbjs for JavaScript
+
+```
+Translates between file formats and generates static code.
+
+  -t, --target     Specifies the target format. Also accepts a path to require a custom target.
+
+                   json          JSON representation
+                   json-module   JSON representation as a module
+                   proto2        Protocol Buffers, Version 2
+                   proto3        Protocol Buffers, Version 3
+                   static        Static code without reflection (non-functional on its own)
+                   static-module Static code without reflection as a module
+
+  -p, --path       Adds a directory to the include path.
+
+  -o, --out        Saves to a file instead of writing to stdout.
+
+  --sparse         Exports only those types referenced from a main file (experimental).
+
+  Module targets only:
+
+  -w, --wrap       Specifies the wrapper to use. Also accepts a path to require a custom wrapper.
+
+                   default   Default wrapper supporting both CommonJS and AMD
+                   commonjs  CommonJS wrapper
+                   amd       AMD wrapper
+                   es6       ES6 wrapper (implies --es6)
+                   closure   A closure adding to protobuf.roots where protobuf is a global
+
+  -r, --root       Specifies an alternative protobuf.roots name.
+
+  -l, --lint       Linter configuration. Defaults to protobuf.js-compatible rules:
+
+                   eslint-disable block-scoped-var, no-redeclare, no-control-regex, no-prototype-builtins
+
+  --es6            Enables ES6 syntax (const/let instead of var)
+
+  Proto sources only:
+
+  --keep-case      Keeps field casing instead of converting to camel case.
+
+  Static targets only:
+
+  --no-create      Does not generate create functions used for reflection compatibility.
+  --no-encode      Does not generate encode functions.
+  --no-decode      Does not generate decode functions.
+  --no-verify      Does not generate verify functions.
+  --no-convert     Does not generate convert functions like from/toObject
+  --no-delimited   Does not generate delimited encode/decode functions.
+  --no-beautify    Does not beautify generated code.
+  --no-comments    Does not output any JSDoc comments.
+  --no-service     Does not output service classes.
+
+  --force-long     Enforces the use of 'Long' for s-/u-/int64 and s-/fixed64 fields.
+  --force-number   Enforces the use of 'number' for s-/u-/int64 and s-/fixed64 fields.
+  --force-message  Enforces the use of message instances instead of plain objects.
+
+usage: pbjs [options] file1.proto file2.json ...  (or pipe)  other | pbjs [options] -
+```
+
+For production environments it is recommended to bundle all your .proto files to a single .json file, which minimizes the number of network requests and avoids any parser overhead (hint: works with just the **light** library):
+
+```
+$> pbjs -t json file1.proto file2.proto > bundle.json
+```
+
+Now, either include this file in your final bundle:
+
+```js
+var root = protobuf.Root.fromJSON(require("./bundle.json"));
+```
+
+or load it the usual way:
+
+```js
+protobuf.load("bundle.json", function(err, root) {
+    ...
+});
+```
+
+Generated static code, on the other hand, works with just the **minimal** library. For example
+
+```
+$> pbjs -t static-module -w commonjs -o compiled.js file1.proto file2.proto
+```
+
+will generate static code for definitions within `file1.proto` and `file2.proto` to a CommonJS module `compiled.js`.
+
+**ProTip!** Documenting your .proto files with `/** ... */`-blocks or (trailing) `/// ...` lines translates to generated static code.
+
+
+### pbts for TypeScript
+
+```
+Generates TypeScript definitions from annotated JavaScript files.
+
+  -o, --out       Saves to a file instead of writing to stdout.
+
+  -g, --global    Name of the global object in browser environments, if any.
+
+  --no-comments   Does not output any JSDoc comments.
+
+  Internal flags:
+
+  -n, --name      Wraps everything in a module of the specified name.
+
+  -m, --main      Whether building the main library without any imports.
+
+usage: pbts [options] file1.js file2.js ...  (or)  other | pbts [options] -
+```
+
+Picking up on the example above, the following not only generates static code to a CommonJS module `compiled.js` but also its respective TypeScript definitions to `compiled.d.ts`:
+
+```
+$> pbjs -t static-module -w commonjs -o compiled.js file1.proto file2.proto
+$> pbts -o compiled.d.ts compiled.js
+```
+
+Additionally, TypeScript definitions of static modules are compatible with their reflection-based counterparts (i.e. as exported by JSON modules), as long as the following conditions are met:
+
+1. Instead of using `new SomeMessage(...)`, always use `SomeMessage.create(...)` because reflection objects do not provide a constructor.
+2. Types, services and enums must start with an uppercase letter to become available as properties of the reflected types as well (i.e. to be able to use `MyMessage.MyEnum` instead of `root.lookup("MyMessage.MyEnum")`).
+
+For example, the following generates a JSON module `bundle.js` and a `bundle.d.ts`, but no static code:
+
+```
+$> pbjs -t json-module -w commonjs -o bundle.js file1.proto file2.proto
+$> pbjs -t static-module file1.proto file2.proto | pbts -o bundle.d.ts -
+```
+
+### Reflection vs. static code
+
+While using .proto files directly requires the full library respectively pure reflection/JSON the light library, pretty much all code but the relatively short descriptors is shared.
+
+Static code, on the other hand, requires just the minimal library, but generates additional source code without any reflection features. This also implies that there is a break-even point where statically generated code becomes larger than descriptor-based code once the amount of code generated exceeds the size of the full respectively light library.
+
+There is no significant difference performance-wise as the code generated statically is pretty much the same as generated at runtime and both are largely interchangeable as seen in the previous section.
+
+| Source | Library | Advantages | Tradeoffs
+|--------|---------|------------|-----------
+| .proto | full    | Easily editable<br />Interoperability with other libraries<br />No compile step | Some parsing and possibly network overhead
+| JSON   | light   | Easily editable<br />No parsing overhead<br />Single bundle (no network overhead) | protobuf.js specific<br />Has a compile step
+| static | minimal | Works where `eval` access is restricted<br />Fully documented<br />Small footprint for small protos | Can be hard to edit<br />No reflection<br />Has a compile step
+
+### Command line API
+
+Both utilities can be used programmatically by providing command line arguments and a callback to their respective `main` functions:
+
+```js
+var pbjs = require("protobufjs-cli/pbjs"); // or require("protobufjs-cli").pbjs / .pbts
+
+pbjs.main([ "--target", "json-module", "path/to/myproto.proto" ], function(err, output) {
+    if (err)
+        throw err;
+    // do something with output
+});
+```
+
+**License:** [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/cli/bin/pbjs b/cli/bin/pbjs
new file mode 100644
index 0000000..9bfedb3
--- /dev/null
+++ b/cli/bin/pbjs
@@ -0,0 +1,6 @@
+#!/usr/bin/env node
+var path = require("path"),
+    cli  = require(path.join(__dirname, "..", "pbjs.js"));
+var ret  = cli.main(process.argv.slice(2));
+if (typeof ret === 'number')
+    process.exit(ret);
diff --git a/cli/bin/pbts b/cli/bin/pbts
new file mode 100644
index 0000000..48d392c
--- /dev/null
+++ b/cli/bin/pbts
@@ -0,0 +1,6 @@
+#!/usr/bin/env node
+var path = require("path"),
+    cli  = require(path.join(__dirname, "..", "pbts.js"));
+var ret  = cli.main(process.argv.slice(2));
+if (typeof ret === 'number')
+    process.exit(ret);
diff --git a/cli/index.d.ts b/cli/index.d.ts
new file mode 100644
index 0000000..09c2026
--- /dev/null
+++ b/cli/index.d.ts
@@ -0,0 +1,3 @@
+import * as pbjs from "./pbjs.js";
+import * as pbts from "./pbts.js";
+export { pbjs, pbts };
diff --git a/cli/index.js b/cli/index.js
new file mode 100644
index 0000000..c565aa6
--- /dev/null
+++ b/cli/index.js
@@ -0,0 +1,3 @@
+"use strict";
+exports.pbjs = require("./pbjs");
+exports.pbts = require("./pbts");
diff --git a/cli/lib/tsd-jsdoc.json b/cli/lib/tsd-jsdoc.json
new file mode 100644
index 0000000..b5fe1d9
--- /dev/null
+++ b/cli/lib/tsd-jsdoc.json
@@ -0,0 +1,18 @@
+{
+    "tags": {
+        "allowUnknownTags": false
+    },
+    "plugins": [
+        "./tsd-jsdoc/plugin"
+    ],
+    "opts": {
+        "encoding"      : "utf8",
+        "recurse"       : true,
+        "lenient"       : true,
+        "template"      : "./tsd-jsdoc",
+
+        "private"       : false,
+        "comments"      : true,
+        "destination"   : false
+    }
+}
diff --git a/cli/lib/tsd-jsdoc/LICENSE b/cli/lib/tsd-jsdoc/LICENSE
new file mode 100644
index 0000000..e5aebc9
--- /dev/null
+++ b/cli/lib/tsd-jsdoc/LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2016 Chad Engler
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/cli/lib/tsd-jsdoc/README.md b/cli/lib/tsd-jsdoc/README.md
new file mode 100644
index 0000000..beed748
--- /dev/null
+++ b/cli/lib/tsd-jsdoc/README.md
@@ -0,0 +1,23 @@
+protobuf.js fork of tsd-jsdoc
+=============================
+
+This is a modified version of [tsd-jsdoc](https://github.com/englercj/tsd-jsdoc) v1.0.1 for use with protobuf.js, parked here so we can process issues and pull requests. The ultimate goal is to switch back to the a recent version of tsd-jsdoc once it meets our needs.
+
+Options
+-------
+
+* **module: `string`**<br />
+  Wraps everything in a module of the specified name.
+
+* **private: `boolean`**<br />
+  Includes private members when set to `true`.
+
+* **comments: `boolean`**<br />
+  Skips comments when explicitly set to `false`.
+
+* **destination: `string|boolean`**<br />
+  Saves to the specified destination file or to console when set to `false`.
+
+Setting options on the command line
+-----------------------------------
+Providing `-q, --query <queryString>` on the command line will set respectively override existing options. Example: `-q module=protobufjs`
diff --git a/cli/lib/tsd-jsdoc/plugin.js b/cli/lib/tsd-jsdoc/plugin.js
new file mode 100644
index 0000000..1bf4f42
--- /dev/null
+++ b/cli/lib/tsd-jsdoc/plugin.js
@@ -0,0 +1,21 @@
+"use strict";
+exports.defineTags = function(dictionary) {
+
+    dictionary.defineTag("template", {
+        mustHaveValue: true,
+        canHaveType: false,
+        canHaveName: false,
+        onTagged: function(doclet, tag) {
+            (doclet.templates || (doclet.templates = [])).push(tag.text);
+        }
+    });
+
+    dictionary.defineTag("tstype", {
+        mustHaveValue: true,
+        canHaveType: false,
+        canHaveName: false,
+        onTagged: function(doclet, tag) {
+            doclet.tsType = tag.text;
+        }
+    });
+};
diff --git a/cli/lib/tsd-jsdoc/publish.js b/cli/lib/tsd-jsdoc/publish.js
new file mode 100644
index 0000000..3846a99
--- /dev/null
+++ b/cli/lib/tsd-jsdoc/publish.js
@@ -0,0 +1,705 @@
+"use strict";
+
+var fs = require("fs");
+
+// output stream
+var out = null;
+
+// documentation data
+var data = null;
+
+// already handled objects, by name
+var seen = {};
+
+// indentation level
+var indent = 0;
+
+// whether indent has been written for the current line yet
+var indentWritten = false;
+
+// provided options
+var options = {};
+
+// queued interfaces
+var queuedInterfaces = [];
+
+// whether writing the first line
+var firstLine = true;
+
+// JSDoc hook
+exports.publish = function publish(taffy, opts) {
+    options = opts || {};
+
+    // query overrides options
+    if (options.query)
+        Object.keys(options.query).forEach(function(key) {
+            if (key !== "query")
+                switch (options[key] = options.query[key]) {
+                    case "true":
+                        options[key] = true;
+                        break;
+                    case "false":
+                        options[key] = false;
+                        break;
+                    case "null":
+                        options[key] = null;
+                        break;
+                }
+        });
+
+    // remove undocumented
+    taffy({ undocumented: true }).remove();
+    taffy({ ignore: true }).remove();
+    taffy({ inherited: true }).remove();
+
+    // remove private
+    if (!options.private)
+        taffy({ access: "private" }).remove();
+
+    // setup output
+    out = options.destination
+        ? fs.createWriteStream(options.destination)
+        : process.stdout;
+
+    try {
+        // setup environment
+        data = taffy().get();
+        indent = 0;
+        indentWritten = false;
+        firstLine = true;
+
+        // wrap everything in a module if configured
+        if (options.module) {
+            writeln("export = ", options.module, ";");
+            writeln();
+            writeln("declare namespace ", options.module, " {");
+            writeln();
+            ++indent;
+        }
+
+        // handle all
+        getChildrenOf(undefined).forEach(function(child) {
+            handleElement(child, null);
+        });
+
+        // process queued
+        while (queuedInterfaces.length) {
+            var element = queuedInterfaces.shift();
+            begin(element);
+            writeInterface(element);
+            writeln(";");
+        }
+
+        // end wrap
+        if (options.module) {
+            --indent;
+            writeln("}");
+        }
+
+        // close file output
+        if (out !== process.stdout)
+            out.end();
+
+    } finally {
+        // gc environment objects
+        out = data = null;
+        seen = options = {};
+        queuedInterfaces = [];
+    }
+};
+
+//
+// Utility
+//
+
+// writes one or multiple strings
+function write() {
+    var s = Array.prototype.slice.call(arguments).join("");
+    if (!indentWritten) {
+        for (var i = 0; i < indent; ++i)
+            s = "    " + s;
+        indentWritten = true;
+    }
+    out.write(s);
+    firstLine = false;
+}
+
+// writes zero or multiple strings, followed by a new line
+function writeln() {
+    var s = Array.prototype.slice.call(arguments).join("");
+    if (s.length)
+        write(s, "\n");
+    else if (!firstLine)
+        out.write("\n");
+    indentWritten = false;
+}
+
+var keepTags = [
+    "param",
+    "returns",
+    "throws",
+    "see"
+];
+
+// parses a comment into text and tags
+function parseComment(comment) {
+    var lines = comment.replace(/^ *\/\*\* *|^ *\*\/| *\*\/ *$|^ *\* */mg, "").trim().split(/\r?\n|\r/g); // property.description has just "\r" ?!
+    var desc;
+    var text = [];
+    var tags = null;
+    for (var i = 0; i < lines.length; ++i) {
+        var match = /^@(\w+)\b/.exec(lines[i]);
+        if (match) {
+            if (!tags) {
+                tags = [];
+                desc = text;
+            }
+            text = [];
+            tags.push({ name: match[1], text: text });
+            lines[i] = lines[i].substring(match[1].length + 1).trim();
+        }
+        if (lines[i].length || text.length)
+            text.push(lines[i]);
+    }
+    return {
+        text: desc || text,
+        tags: tags || []
+    };
+}
+
+// writes a comment
+function writeComment(comment, otherwiseNewline) {
+    if (!comment || options.comments === false) {
+        if (otherwiseNewline)
+            writeln();
+        return;
+    }
+    if (typeof comment !== "object")
+        comment = parseComment(comment);
+    comment.tags = comment.tags.filter(function(tag) {
+        return keepTags.indexOf(tag.name) > -1 && (tag.name !== "returns" || tag.text[0] !== "{undefined}");
+    });
+    writeln();
+    if (!comment.tags.length && comment.text.length < 2) {
+        writeln("/** " + comment.text[0] + " */");
+        return;
+    }
+    writeln("/**");
+    comment.text.forEach(function(line) {
+        if (line.length)
+            writeln(" * ", line);
+        else
+            writeln(" *");
+    });
+    comment.tags.forEach(function(tag) {
+        var started = false;
+        if (tag.text.length) {
+            tag.text.forEach(function(line, i) {
+                if (i > 0)
+                    write(" * ");
+                else if (tag.name !== "throws")
+                    line = line.replace(/^\{[^\s]*} ?/, "");
+                if (!line.length)
+                    return;
+                if (!started) {
+                    write(" * @", tag.name, " ");
+                    started = true;
+                }
+                writeln(line);
+            });
+        }
+    });
+    writeln(" */");
+}
+
+// recursively replaces all occurencies of re's match
+function replaceRecursive(name, re, fn) {
+    var found;
+
+    function replacer() {
+        found = true;
+        return fn.apply(null, arguments);
+    }
+
+    do {
+        found = false;
+        name = name.replace(re, replacer);
+    } while (found);
+    return name;
+}
+
+// tests if an element is considered to be a class or class-like
+function isClassLike(element) {
+    return isClass(element) || isInterface(element);
+}
+
+// tests if an element is considered to be a class
+function isClass(element) {
+    return element && element.kind === "class";
+}
+
+// tests if an element is considered to be an interface
+function isInterface(element) {
+    return element && (element.kind === "interface" || element.kind === "mixin");
+}
+
+// tests if an element is considered to be a namespace
+function isNamespace(element) {
+    return element && (element.kind === "namespace" || element.kind === "module");
+}
+
+// gets all children of the specified parent
+function getChildrenOf(parent) {
+    var memberof = parent ? parent.longname : undefined;
+    return data.filter(function(element) {
+        return element.memberof === memberof;
+    });
+}
+
+// gets the literal type of an element
+function getTypeOf(element) {
+    if (element.tsType)
+        return element.tsType.replace(/\r?\n|\r/g, "\n");
+    var name = "any";
+    var type = element.type;
+    if (type && type.names && type.names.length) {
+        if (type.names.length === 1)
+            name = element.type.names[0].trim();
+        else
+            name = "(" + element.type.names.join("|") + ")";
+    } else
+        return name;
+
+    // Replace catchalls with any
+    name = name.replace(/\*|\bmixed\b/g, "any");
+
+    // Ensure upper case Object for map expressions below
+    name = name.replace(/\bobject\b/g, "Object");
+
+    // Correct Something.<Something> to Something<Something>
+    name = replaceRecursive(name, /\b(?!Object|Array)([\w$]+)\.<([^>]*)>/gi, function($0, $1, $2) {
+        return $1 + "<" + $2 + ">";
+    });
+
+    // Replace Array.<string> with string[]
+    name = replaceRecursive(name, /\bArray\.?<([^>]*)>/gi, function($0, $1) {
+        return $1 + "[]";
+    });
+
+    // Replace Object.<string,number> with { [k: string]: number }
+    name = replaceRecursive(name, /\bObject\.?<([^,]*), *([^>]*)>/gi, function($0, $1, $2) {
+        return "{ [k: " + $1 + "]: " + $2 + " }";
+    });
+
+    // Replace functions (there are no signatures) with Function
+    name = name.replace(/\bfunction(?:\(\))?\b/g, "Function");
+
+    // Convert plain Object back to just object
+    name = name.replace(/\b(Object\b(?!\.))/g, function($0, $1) {
+        return $1.toLowerCase();
+    });
+
+    return name;
+}
+
+// begins writing the definition of the specified element
+function begin(element, is_interface) {
+    if (!seen[element.longname]) {
+        if (isClass(element)) {
+            var comment = parseComment(element.comment);
+            var classdesc = comment.tags.find(function(tag) { return tag.name === "classdesc"; });
+            if (classdesc) {
+                comment.text = classdesc.text;
+                comment.tags = [];
+            }
+            writeComment(comment, true);
+        } else
+            writeComment(element.comment, is_interface || isClassLike(element) || isNamespace(element) || element.isEnum || element.scope === "global");
+        seen[element.longname] = element;
+    } else
+        writeln();
+    // ????: something changed in JSDoc 3.6.0? so that @exports + @enum does
+    // no longer yield a 'global' scope, but is some sort of unscoped module
+    // element now. The additional condition added below works around this.
+    if ((element.scope === "global" || element.isEnum && element.scope === undefined) && !options.module)
+        write("export ");
+}
+
+// writes the function signature describing element
+function writeFunctionSignature(element, isConstructor, isTypeDef) {
+    write("(");
+
+    var params = {};
+
+    // this type
+    if (element.this)
+        params["this"] = {
+            type: element.this.replace(/^{|}$/g, ""),
+            optional: false
+        };
+
+    // parameter types
+    if (element.params)
+        element.params.forEach(function(param) {
+            var path = param.name.split(/\./g);
+            if (path.length === 1)
+                params[param.name] = {
+                    type: getTypeOf(param),
+                    variable: param.variable === true,
+                    optional: param.optional === true,
+                    defaultValue: param.defaultvalue // Not used yet (TODO)
+                };
+            else // Property syntax (TODO)
+                params[path[0]].type = "{ [k: string]: any }";
+        });
+
+    var paramNames = Object.keys(params);
+    paramNames.forEach(function(name, i) {
+        var param = params[name];
+        var type = param.type;
+        if (param.variable) {
+            name = "..." + name;
+            type = param.type.charAt(0) === "(" ? "any[]" : param.type + "[]";
+        }
+        write(name, !param.variable && param.optional ? "?: " : ": ", type);
+        if (i < paramNames.length - 1)
+            write(", ");
+    });
+
+    write(")");
+
+    // return type
+    if (!isConstructor) {
+        write(isTypeDef ? " => " : ": ");
+        var typeName;
+        if (element.returns && element.returns.length && (typeName = getTypeOf(element.returns[0])) !== "undefined")
+            write(typeName);
+        else
+            write("void");
+    }
+}
+
+// writes (a typedef as) an interface
+function writeInterface(element) {
+    write("interface ", element.name);
+    writeInterfaceBody(element);
+    writeln();
+}
+
+function writeInterfaceBody(element) {
+    writeln("{");
+    ++indent;
+    if (element.tsType)
+        writeln(element.tsType.replace(/\r?\n|\r/g, "\n"));
+    else if (element.properties && element.properties.length)
+        element.properties.forEach(writeProperty);
+    --indent;
+    write("}");
+}
+
+function writeProperty(property, declare) {
+    writeComment(property.description);
+    if (declare)
+        write("let ");
+    write(property.name);
+    if (property.optional)
+        write("?");
+    writeln(": ", getTypeOf(property), ";");
+}
+
+//
+// Handlers
+//
+
+// handles a single element of any understood type
+function handleElement(element, parent) {
+    if (element.scope === "inner")
+        return false;
+
+    if (element.optional !== true && element.type && element.type.names && element.type.names.length) {
+        for (var i = 0; i < element.type.names.length; i++) {
+            if (element.type.names[i].toLowerCase() === "undefined") {
+                // This element is actually optional. Set optional to true and
+                // remove the 'undefined' type
+                element.optional = true;
+                element.type.names.splice(i, 1);
+                i--;
+            }
+        }
+    }
+
+    if (seen[element.longname])
+        return true;
+    if (isClassLike(element))
+        handleClass(element, parent);
+    else switch (element.kind) {
+        case "module":
+            if (element.isEnum) {
+                handleEnum(element, parent);
+                break;
+            }
+            // eslint-disable-line no-fallthrough
+        case "namespace":
+            handleNamespace(element, parent);
+            break;
+        case "constant":
+        case "member":
+            handleMember(element, parent);
+            break;
+        case "function":
+            handleFunction(element, parent);
+            break;
+        case "typedef":
+            handleTypeDef(element, parent);
+            break;
+        case "package":
+            break;
+    }
+    seen[element.longname] = element;
+    return true;
+}
+
+// handles (just) a namespace
+function handleNamespace(element/*, parent*/) {
+    var children = getChildrenOf(element);
+    if (!children.length)
+        return;
+    var first = true;
+    if (element.properties)
+        element.properties.forEach(function(property) {
+            if (!/^[$\w]+$/.test(property.name)) // incompatible in namespace
+                return;
+            if (first) {
+                begin(element);
+                writeln("namespace ", element.name, " {");
+                ++indent;
+                first = false;
+            }
+            writeProperty(property, true);
+        });
+    children.forEach(function(child) {
+        if (child.scope === "inner" || seen[child.longname])
+            return;
+        if (first) {
+            begin(element);
+            writeln("namespace ", element.name, " {");
+            ++indent;
+            first = false;
+        }
+        handleElement(child, element);
+    });
+    if (!first) {
+        --indent;
+        writeln("}");
+    }
+}
+
+// a filter function to remove any module references
+function notAModuleReference(ref) {
+    return ref.indexOf("module:") === -1;
+}
+
+// handles a class or class-like
+function handleClass(element, parent) {
+    var is_interface = isInterface(element);
+    begin(element, is_interface);
+    if (is_interface)
+        write("interface ");
+    else {
+        if (element.virtual)
+            write("abstract ");
+        write("class ");
+    }
+    write(element.name);
+    if (element.templates && element.templates.length)
+        write("<", element.templates.join(", "), ">");
+    write(" ");
+
+    // extended classes
+    if (element.augments) {
+        var augments = element.augments.filter(notAModuleReference);
+        if (augments.length)
+            write("extends ", augments[0], " ");
+    }
+
+    // implemented interfaces
+    var impls = [];
+    if (element.implements)
+        Array.prototype.push.apply(impls, element.implements);
+    if (element.mixes)
+        Array.prototype.push.apply(impls, element.mixes);
+    impls = impls.filter(notAModuleReference);
+    if (impls.length)
+        write("implements ", impls.join(", "), " ");
+
+    writeln("{");
+    ++indent;
+
+    if (element.tsType)
+        writeln(element.tsType.replace(/\r?\n|\r/g, "\n"));
+
+    // constructor
+    if (!is_interface && !element.virtual)
+        handleFunction(element, parent, true);
+
+    // properties
+    if (is_interface && element.properties)
+        element.properties.forEach(function(property) {
+            writeProperty(property);
+        });
+
+    // class-compatible members
+    var incompatible = [];
+    getChildrenOf(element).forEach(function(child) {
+        if (isClassLike(child) || child.kind === "module" || child.kind === "typedef" || child.isEnum) {
+            incompatible.push(child);
+            return;
+        }
+        handleElement(child, element);
+    });
+
+    --indent;
+    writeln("}");
+
+    // class-incompatible members
+    if (incompatible.length) {
+        writeln();
+        if (element.scope === "global" && !options.module)
+            write("export ");
+        writeln("namespace ", element.name, " {");
+        ++indent;
+        incompatible.forEach(function(child) {
+            handleElement(child, element);
+        });
+        --indent;
+        writeln("}");
+    }
+}
+
+// handles an enum
+function handleEnum(element) {
+    begin(element);
+
+    var stringEnum = false;
+    element.properties.forEach(function(property) {
+        if (isNaN(property.defaultvalue)) {
+            stringEnum = true;
+        }
+    });
+    if (stringEnum) {
+        writeln("type ", element.name, " =");
+        ++indent;
+        element.properties.forEach(function(property, i) {
+            write(i === 0 ? "" : "| ", JSON.stringify(property.defaultvalue));
+        });
+        --indent;
+        writeln(";");
+    } else {
+        writeln("enum ", element.name, " {");
+        ++indent;
+        element.properties.forEach(function(property, i) {
+            write(property.name);
+            if (property.defaultvalue !== undefined)
+                write(" = ", JSON.stringify(property.defaultvalue));
+            if (i < element.properties.length - 1)
+                writeln(",");
+            else
+                writeln();
+        });
+        --indent;
+        writeln("}");
+    }
+}
+
+// handles a namespace or class member
+function handleMember(element, parent) {
+    if (element.isEnum) {
+        handleEnum(element);
+        return;
+    }
+    begin(element);
+
+    var inClass = isClassLike(parent);
+    if (inClass) {
+        write(element.access || "public", " ");
+        if (element.scope === "static")
+            write("static ");
+        if (element.readonly)
+            write("readonly ");
+    } else
+        write(element.kind === "constant" ? "const " : "let ");
+
+    write(element.name);
+    if (element.optional)
+        write("?");
+    write(": ");
+
+    if (element.type && element.type.names && /^Object\b/i.test(element.type.names[0]) && element.properties) {
+        writeln("{");
+        ++indent;
+        element.properties.forEach(function(property, i) {
+            writeln(JSON.stringify(property.name), ": ", getTypeOf(property), i < element.properties.length - 1 ? "," : "");
+        });
+        --indent;
+        writeln("};");
+    } else
+        writeln(getTypeOf(element), ";");
+}
+
+// handles a function or method
+function handleFunction(element, parent, isConstructor) {
+    var insideClass = true;
+    if (isConstructor) {
+        writeComment(element.comment);
+        write("constructor");
+    } else {
+        begin(element);
+        insideClass = isClassLike(parent);
+        if (insideClass) {
+            write(element.access || "public", " ");
+            if (element.scope === "static")
+                write("static ");
+        } else
+            write("function ");
+        write(element.name);
+        if (element.templates && element.templates.length)
+            write("<", element.templates.join(", "), ">");
+    }
+    writeFunctionSignature(element, isConstructor, false);
+    writeln(";");
+    if (!insideClass)
+        handleNamespace(element);
+}
+
+// handles a type definition (not a real type)
+function handleTypeDef(element, parent) {
+    if (isInterface(element)) {
+        if (isClassLike(parent))
+            queuedInterfaces.push(element);
+        else {
+            begin(element);
+            writeInterface(element);
+        }
+    } else {
+        writeComment(element.comment, true);
+        write("type ", element.name);
+        if (element.templates && element.templates.length)
+            write("<", element.templates.join(", "), ">");
+        write(" = ");
+        if (element.tsType)
+            write(element.tsType.replace(/\r?\n|\r/g, "\n"));
+        else {
+            var type = getTypeOf(element);
+            if (element.type && element.type.names.length === 1 && element.type.names[0] === "function")
+                writeFunctionSignature(element, false, true);
+            else if (type === "object") {
+                if (element.properties && element.properties.length)
+                    writeInterfaceBody(element);
+                else
+                    write("{}");
+            } else
+                write(type);
+        }
+        writeln(";");
+    }
+}
diff --git a/cli/package-lock.json b/cli/package-lock.json
new file mode 100644
index 0000000..ff70068
--- /dev/null
+++ b/cli/package-lock.json
@@ -0,0 +1,1297 @@
+{
+  "name": "protobufjs-cli",
+  "version": "1.1.1",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "protobufjs-cli",
+      "version": "1.1.1",
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "chalk": "^4.0.0",
+        "escodegen": "^1.13.0",
+        "espree": "^9.0.0",
+        "estraverse": "^5.1.0",
+        "glob": "^8.0.0",
+        "jsdoc": "^4.0.0",
+        "minimist": "^1.2.0",
+        "semver": "^7.1.2",
+        "tmp": "^0.2.1",
+        "uglify-js": "^3.7.7"
+      },
+      "bin": {
+        "pbjs": "bin/pbjs",
+        "pbts": "bin/pbts"
+      },
+      "devDependencies": {
+        "protobufjs": "file:.."
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "protobufjs": "^7.0.0"
+      }
+    },
+    "..": {
+      "name": "protobufjs",
+      "version": "7.1.2",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/node": ">=13.7.0",
+        "long": "^5.0.0"
+      },
+      "devDependencies": {
+        "benchmark": "^2.1.4",
+        "browserify": "^17.0.0",
+        "browserify-wrap": "^1.0.2",
+        "bundle-collapser": "^1.3.0",
+        "chalk": "^4.0.0",
+        "escodegen": "^1.13.0",
+        "eslint": "^8.15.0",
+        "espree": "^9.0.0",
+        "estraverse": "^5.1.0",
+        "gh-pages": "^4.0.0",
+        "git-raw-commits": "^2.0.3",
+        "git-semver-tags": "^4.0.0",
+        "google-protobuf": "^3.11.3",
+        "gulp": "^4.0.2",
+        "gulp-header": "^2.0.9",
+        "gulp-if": "^3.0.0",
+        "gulp-sourcemaps": "^3.0.0",
+        "gulp-uglify": "^3.0.2",
+        "jaguarjs-jsdoc": "github:dcodeIO/jaguarjs-jsdoc",
+        "jsdoc": "^4.0.0",
+        "minimist": "^1.2.0",
+        "nyc": "^15.0.0",
+        "reflect-metadata": "^0.1.13",
+        "tape": "^5.0.0",
+        "tslint": "^6.0.0",
+        "typescript": "^3.7.5",
+        "uglify-js": "^3.7.7",
+        "vinyl-buffer": "^1.0.1",
+        "vinyl-fs": "^3.0.3",
+        "vinyl-source-stream": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.13.tgz",
+      "integrity": "sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==",
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jsdoc/salty": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.1.tgz",
+      "integrity": "sha512-JXwylDNSHa549N9uceDYu8D4GMXwSo3H8CCPYEQqxhhHpxD28+lRl2b3bS/caaPj5w1YD3SWtrficJNTnUjGpg==",
+      "dependencies": {
+        "lodash": "^4.17.21"
+      },
+      "engines": {
+        "node": ">=v12.0.0"
+      }
+    },
+    "node_modules/@types/linkify-it": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz",
+      "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA=="
+    },
+    "node_modules/@types/markdown-it": {
+      "version": "12.2.3",
+      "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz",
+      "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==",
+      "dependencies": {
+        "@types/linkify-it": "*",
+        "@types/mdurl": "*"
+      }
+    },
+    "node_modules/@types/mdurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz",
+      "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA=="
+    },
+    "node_modules/acorn": {
+      "version": "8.8.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
+      "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+    },
+    "node_modules/bluebird": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+      "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
+    },
+    "node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/catharsis": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
+      "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==",
+      "dependencies": {
+        "lodash": "^4.17.15"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+    },
+    "node_modules/deep-is": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
+    },
+    "node_modules/entities": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+      "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+      "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/escodegen": {
+      "version": "1.14.3",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
+      "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
+      "dependencies": {
+        "esprima": "^4.0.1",
+        "estraverse": "^4.2.0",
+        "esutils": "^2.0.2",
+        "optionator": "^0.8.1"
+      },
+      "bin": {
+        "escodegen": "bin/escodegen.js",
+        "esgenerate": "bin/esgenerate.js"
+      },
+      "engines": {
+        "node": ">=4.0"
+      },
+      "optionalDependencies": {
+        "source-map": "~0.6.1"
+      }
+    },
+    "node_modules/escodegen/node_modules/estraverse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/eslint-visitor-keys": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+      "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/espree": {
+      "version": "9.4.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz",
+      "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==",
+      "dependencies": {
+        "acorn": "^8.8.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "bin": {
+        "esparse": "bin/esparse.js",
+        "esvalidate": "bin/esvalidate.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+    },
+    "node_modules/glob": {
+      "version": "8.0.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz",
+      "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^5.0.1",
+        "once": "^1.3.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.10",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "node_modules/js2xmlparser": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz",
+      "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==",
+      "dependencies": {
+        "xmlcreate": "^2.0.4"
+      }
+    },
+    "node_modules/jsdoc": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.0.tgz",
+      "integrity": "sha512-tzTgkklbWKrlaQL2+e3NNgLcZu3NaK2vsHRx7tyHQ+H5jcB9Gx0txSd2eJWlMC/xU1+7LQu4s58Ry0RkuaEQVg==",
+      "dependencies": {
+        "@babel/parser": "^7.9.4",
+        "@jsdoc/salty": "^0.2.1",
+        "@types/markdown-it": "^12.2.3",
+        "bluebird": "^3.7.2",
+        "catharsis": "^0.9.0",
+        "escape-string-regexp": "^2.0.0",
+        "js2xmlparser": "^4.0.2",
+        "klaw": "^3.0.0",
+        "markdown-it": "^12.3.2",
+        "markdown-it-anchor": "^8.4.1",
+        "marked": "^4.0.10",
+        "mkdirp": "^1.0.4",
+        "requizzle": "^0.2.3",
+        "strip-json-comments": "^3.1.0",
+        "underscore": "~1.13.2"
+      },
+      "bin": {
+        "jsdoc": "jsdoc.js"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/klaw": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz",
+      "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==",
+      "dependencies": {
+        "graceful-fs": "^4.1.9"
+      }
+    },
+    "node_modules/levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
+      "dependencies": {
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/linkify-it": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+      "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+      "dependencies": {
+        "uc.micro": "^1.0.1"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+    },
+    "node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/markdown-it": {
+      "version": "12.3.2",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+      "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
+      "dependencies": {
+        "argparse": "^2.0.1",
+        "entities": "~2.1.0",
+        "linkify-it": "^3.0.1",
+        "mdurl": "^1.0.1",
+        "uc.micro": "^1.0.5"
+      },
+      "bin": {
+        "markdown-it": "bin/markdown-it.js"
+      }
+    },
+    "node_modules/markdown-it-anchor": {
+      "version": "8.6.4",
+      "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.4.tgz",
+      "integrity": "sha512-Ul4YVYZNxMJYALpKtu+ZRdrryYt/GlQ5CK+4l1bp/gWXOG2QWElt6AqF3Mih/wfUKdZbNAZVXGR73/n6U/8img==",
+      "peerDependencies": {
+        "@types/markdown-it": "*",
+        "markdown-it": "*"
+      }
+    },
+    "node_modules/marked": {
+      "version": "4.0.19",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.19.tgz",
+      "integrity": "sha512-rgQF/OxOiLcvgUAj1Q1tAf4Bgxn5h5JZTp04Fx4XUkVhs7B+7YA9JEWJhJpoO8eJt8MkZMwqLCNeNqj1bCREZQ==",
+      "bin": {
+        "marked": "bin/marked.js"
+      },
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/mdurl": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+      "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
+    },
+    "node_modules/minimatch": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
+      "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+      "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
+    },
+    "node_modules/mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/optionator": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+      "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+      "dependencies": {
+        "deep-is": "~0.1.3",
+        "fast-levenshtein": "~2.0.6",
+        "levn": "~0.3.0",
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2",
+        "word-wrap": "~1.2.3"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/protobufjs": {
+      "resolved": "..",
+      "link": true
+    },
+    "node_modules/requizzle": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz",
+      "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==",
+      "dependencies": {
+        "lodash": "^4.17.14"
+      }
+    },
+    "node_modules/rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/rimraf/node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/rimraf/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/rimraf/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/semver": {
+      "version": "7.3.7",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "optional": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/tmp": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+      "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+      "dependencies": {
+        "rimraf": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8.17.0"
+      }
+    },
+    "node_modules/type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
+      "dependencies": {
+        "prelude-ls": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/uc.micro": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+      "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
+    },
+    "node_modules/uglify-js": {
+      "version": "3.17.0",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz",
+      "integrity": "sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg==",
+      "bin": {
+        "uglifyjs": "bin/uglifyjs"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/underscore": {
+      "version": "1.13.4",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz",
+      "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ=="
+    },
+    "node_modules/word-wrap": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+    },
+    "node_modules/xmlcreate": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz",
+      "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg=="
+    },
+    "node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+    }
+  },
+  "dependencies": {
+    "@babel/parser": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.13.tgz",
+      "integrity": "sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg=="
+    },
+    "@jsdoc/salty": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.1.tgz",
+      "integrity": "sha512-JXwylDNSHa549N9uceDYu8D4GMXwSo3H8CCPYEQqxhhHpxD28+lRl2b3bS/caaPj5w1YD3SWtrficJNTnUjGpg==",
+      "requires": {
+        "lodash": "^4.17.21"
+      }
+    },
+    "@types/linkify-it": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz",
+      "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA=="
+    },
+    "@types/markdown-it": {
+      "version": "12.2.3",
+      "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz",
+      "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==",
+      "requires": {
+        "@types/linkify-it": "*",
+        "@types/mdurl": "*"
+      }
+    },
+    "@types/mdurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz",
+      "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA=="
+    },
+    "acorn": {
+      "version": "8.8.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
+      "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w=="
+    },
+    "acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "requires": {}
+    },
+    "ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "requires": {
+        "color-convert": "^2.0.1"
+      }
+    },
+    "argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+    },
+    "balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+    },
+    "bluebird": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+      "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
+    },
+    "brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "requires": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "catharsis": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
+      "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==",
+      "requires": {
+        "lodash": "^4.17.15"
+      }
+    },
+    "chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "requires": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      }
+    },
+    "color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "requires": {
+        "color-name": "~1.1.4"
+      }
+    },
+    "color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+    },
+    "deep-is": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
+    },
+    "entities": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+      "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w=="
+    },
+    "escape-string-regexp": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+      "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="
+    },
+    "escodegen": {
+      "version": "1.14.3",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
+      "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
+      "requires": {
+        "esprima": "^4.0.1",
+        "estraverse": "^4.2.0",
+        "esutils": "^2.0.2",
+        "optionator": "^0.8.1",
+        "source-map": "~0.6.1"
+      },
+      "dependencies": {
+        "estraverse": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+          "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
+        }
+      }
+    },
+    "eslint-visitor-keys": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+      "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA=="
+    },
+    "espree": {
+      "version": "9.4.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz",
+      "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==",
+      "requires": {
+        "acorn": "^8.8.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.3.0"
+      }
+    },
+    "esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
+    },
+    "estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="
+    },
+    "esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
+    },
+    "fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+    },
+    "glob": {
+      "version": "8.0.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz",
+      "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==",
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^5.0.1",
+        "once": "^1.3.0"
+      }
+    },
+    "graceful-fs": {
+      "version": "4.2.10",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
+    },
+    "has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "js2xmlparser": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz",
+      "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==",
+      "requires": {
+        "xmlcreate": "^2.0.4"
+      }
+    },
+    "jsdoc": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.0.tgz",
+      "integrity": "sha512-tzTgkklbWKrlaQL2+e3NNgLcZu3NaK2vsHRx7tyHQ+H5jcB9Gx0txSd2eJWlMC/xU1+7LQu4s58Ry0RkuaEQVg==",
+      "requires": {
+        "@babel/parser": "^7.9.4",
+        "@jsdoc/salty": "^0.2.1",
+        "@types/markdown-it": "^12.2.3",
+        "bluebird": "^3.7.2",
+        "catharsis": "^0.9.0",
+        "escape-string-regexp": "^2.0.0",
+        "js2xmlparser": "^4.0.2",
+        "klaw": "^3.0.0",
+        "markdown-it": "^12.3.2",
+        "markdown-it-anchor": "^8.4.1",
+        "marked": "^4.0.10",
+        "mkdirp": "^1.0.4",
+        "requizzle": "^0.2.3",
+        "strip-json-comments": "^3.1.0",
+        "underscore": "~1.13.2"
+      }
+    },
+    "klaw": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz",
+      "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==",
+      "requires": {
+        "graceful-fs": "^4.1.9"
+      }
+    },
+    "levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
+      "requires": {
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2"
+      }
+    },
+    "linkify-it": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+      "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+      "requires": {
+        "uc.micro": "^1.0.1"
+      }
+    },
+    "lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+    },
+    "lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "requires": {
+        "yallist": "^4.0.0"
+      }
+    },
+    "markdown-it": {
+      "version": "12.3.2",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+      "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
+      "requires": {
+        "argparse": "^2.0.1",
+        "entities": "~2.1.0",
+        "linkify-it": "^3.0.1",
+        "mdurl": "^1.0.1",
+        "uc.micro": "^1.0.5"
+      }
+    },
+    "markdown-it-anchor": {
+      "version": "8.6.4",
+      "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.4.tgz",
+      "integrity": "sha512-Ul4YVYZNxMJYALpKtu+ZRdrryYt/GlQ5CK+4l1bp/gWXOG2QWElt6AqF3Mih/wfUKdZbNAZVXGR73/n6U/8img==",
+      "requires": {}
+    },
+    "marked": {
+      "version": "4.0.19",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.19.tgz",
+      "integrity": "sha512-rgQF/OxOiLcvgUAj1Q1tAf4Bgxn5h5JZTp04Fx4XUkVhs7B+7YA9JEWJhJpoO8eJt8MkZMwqLCNeNqj1bCREZQ=="
+    },
+    "mdurl": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+      "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
+    },
+    "minimatch": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
+      "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
+      "requires": {
+        "brace-expansion": "^2.0.1"
+      }
+    },
+    "minimist": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+      "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
+    },
+    "mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "optionator": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+      "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+      "requires": {
+        "deep-is": "~0.1.3",
+        "fast-levenshtein": "~2.0.6",
+        "levn": "~0.3.0",
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2",
+        "word-wrap": "~1.2.3"
+      }
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
+    },
+    "prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w=="
+    },
+    "protobufjs": {
+      "version": "file:..",
+      "requires": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/node": ">=13.7.0",
+        "benchmark": "^2.1.4",
+        "browserify": "^17.0.0",
+        "browserify-wrap": "^1.0.2",
+        "bundle-collapser": "^1.3.0",
+        "chalk": "^4.0.0",
+        "escodegen": "^1.13.0",
+        "eslint": "^8.15.0",
+        "espree": "^9.0.0",
+        "estraverse": "^5.1.0",
+        "gh-pages": "^4.0.0",
+        "git-raw-commits": "^2.0.3",
+        "git-semver-tags": "^4.0.0",
+        "google-protobuf": "^3.11.3",
+        "gulp": "^4.0.2",
+        "gulp-header": "^2.0.9",
+        "gulp-if": "^3.0.0",
+        "gulp-sourcemaps": "^3.0.0",
+        "gulp-uglify": "^3.0.2",
+        "jaguarjs-jsdoc": "github:dcodeIO/jaguarjs-jsdoc",
+        "jsdoc": "^4.0.0",
+        "long": "^5.0.0",
+        "minimist": "^1.2.0",
+        "nyc": "^15.0.0",
+        "reflect-metadata": "^0.1.13",
+        "tape": "^5.0.0",
+        "tslint": "^6.0.0",
+        "typescript": "^3.7.5",
+        "uglify-js": "^3.7.7",
+        "vinyl-buffer": "^1.0.1",
+        "vinyl-fs": "^3.0.3",
+        "vinyl-source-stream": "^2.0.0"
+      }
+    },
+    "requizzle": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz",
+      "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==",
+      "requires": {
+        "lodash": "^4.17.14"
+      }
+    },
+    "rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "requires": {
+        "glob": "^7.1.3"
+      },
+      "dependencies": {
+        "brace-expansion": {
+          "version": "1.1.11",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+          "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+          "requires": {
+            "balanced-match": "^1.0.0",
+            "concat-map": "0.0.1"
+          }
+        },
+        "glob": {
+          "version": "7.2.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+          "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.1.1",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "minimatch": {
+          "version": "3.1.2",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+          "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        }
+      }
+    },
+    "semver": {
+      "version": "7.3.7",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+      "requires": {
+        "lru-cache": "^6.0.0"
+      }
+    },
+    "source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "optional": true
+    },
+    "strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
+    },
+    "supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "requires": {
+        "has-flag": "^4.0.0"
+      }
+    },
+    "tmp": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+      "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+      "requires": {
+        "rimraf": "^3.0.0"
+      }
+    },
+    "type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
+      "requires": {
+        "prelude-ls": "~1.1.2"
+      }
+    },
+    "uc.micro": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+      "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
+    },
+    "uglify-js": {
+      "version": "3.17.0",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz",
+      "integrity": "sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg=="
+    },
+    "underscore": {
+      "version": "1.13.4",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz",
+      "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ=="
+    },
+    "word-wrap": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+    },
+    "xmlcreate": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz",
+      "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg=="
+    },
+    "yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+    }
+  }
+}
diff --git a/cli/package.json b/cli/package.json
new file mode 100644
index 0000000..448f853
--- /dev/null
+++ b/cli/package.json
@@ -0,0 +1,38 @@
+{
+  "name": "protobufjs-cli",
+  "description": "Translates between file formats and generates static code as well as TypeScript definitions.",
+  "version": "1.1.1",
+  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/protobufjs/protobuf.js.git"
+  },
+  "engines": {
+    "node": ">=12.0.0"
+  },
+  "license": "BSD-3-Clause",
+  "main": "index.js",
+  "types": "index.d.ts",
+  "bin": {
+    "pbjs": "bin/pbjs",
+    "pbts": "bin/pbts"
+  },
+  "peerDependencies": {
+    "protobufjs": "^7.0.0"
+  },
+  "dependencies": {
+    "chalk": "^4.0.0",
+    "escodegen": "^1.13.0",
+    "espree": "^9.0.0",
+    "estraverse": "^5.1.0",
+    "glob": "^8.0.0",
+    "jsdoc": "^4.0.0",
+    "minimist": "^1.2.0",
+    "semver": "^7.1.2",
+    "tmp": "^0.2.1",
+    "uglify-js": "^3.7.7"
+  },
+  "devDependencies": {
+    "protobufjs": "file:.."
+  }
+}
diff --git a/cli/pbjs.d.ts b/cli/pbjs.d.ts
new file mode 100644
index 0000000..ead1f3c
--- /dev/null
+++ b/cli/pbjs.d.ts
@@ -0,0 +1,9 @@
+type pbjsCallback = (err: Error|null, output?: string) => void;
+
+/**
+ * Runs pbjs programmatically.
+ * @param {string[]} args Command line arguments
+ * @param {function(?Error, string=)} [callback] Optional completion callback
+ * @returns {number|undefined} Exit code, if known
+ */
+export function main(args: string[], callback?: pbjsCallback): number|undefined;
diff --git a/cli/pbjs.js b/cli/pbjs.js
new file mode 100644
index 0000000..150a2b6
--- /dev/null
+++ b/cli/pbjs.js
@@ -0,0 +1,351 @@
+"use strict";
+var path     = require("path"),
+    fs       = require("fs"),
+    minimist = require("minimist"),
+    chalk    = require("chalk"),
+    pkg      = require("./package.json"),
+    util     = require("./util"),
+    glob     = require("glob"),
+    protobuf = require("protobufjs");
+
+var targets  = util.requireAll("./targets");
+
+/**
+ * Runs pbjs programmatically.
+ * @param {string[]} args Command line arguments
+ * @param {function(?Error, string=)} [callback] Optional completion callback
+ * @returns {number|undefined} Exit code, if known
+ */
+exports.main = function main(args, callback) {
+    var lintDefault = "eslint-disable " + [
+        "block-scoped-var",
+        "id-length",
+        "no-control-regex",
+        "no-magic-numbers",
+        "no-prototype-builtins",
+        "no-redeclare",
+        "no-shadow",
+        "no-var",
+        "sort-vars"
+    ].join(", ");
+    var argv = minimist(args, {
+        alias: {
+            target: "t",
+            out: "o",
+            path: "p",
+            wrap: "w",
+            root: "r",
+            lint: "l",
+            // backward compatibility:
+            "force-long": "strict-long",
+            "force-message": "strict-message"
+        },
+        string: [ "target", "out", "path", "wrap", "dependency", "root", "lint", "filter" ],
+        boolean: [ "create", "encode", "decode", "verify", "convert", "delimited", "typeurl", "beautify", "comments", "service", "es6", "sparse", "keep-case", "alt-comment", "force-long", "force-number", "force-enum-string", "force-message", "null-defaults" ],
+        default: {
+            target: "json",
+            create: true,
+            encode: true,
+            decode: true,
+            verify: true,
+            convert: true,
+            delimited: true,
+            typeurl: true,
+            beautify: true,
+            comments: true,
+            service: true,
+            es6: null,
+            lint: lintDefault,
+            "keep-case": false,
+            "alt-comment": false,
+            "force-long": false,
+            "force-number": false,
+            "force-enum-string": false,
+            "force-message": false,
+            "null-defaults": false,
+        }
+    });
+
+    var target = targets[argv.target],
+        files  = argv._,
+        paths  = typeof argv.path === "string" ? [ argv.path ] : argv.path || [];
+
+    // alias hyphen args in camel case
+    Object.keys(argv).forEach(function(key) {
+        var camelKey = key.replace(/-([a-z])/g, function($0, $1) { return $1.toUpperCase(); });
+        if (camelKey !== key)
+            argv[camelKey] = argv[key];
+    });
+
+    // protobuf.js package directory contains additional, otherwise non-bundled google types
+    paths.push(path.relative(process.cwd(), path.join(__dirname, "../protobufjs")) || ".");
+
+    if (!files.length) {
+        var descs = Object.keys(targets).filter(function(key) { return !targets[key].private; }).map(function(key) {
+            return "                   " + util.pad(key, 14, true) + targets[key].description;
+        });
+        if (callback)
+            callback(Error("usage")); // eslint-disable-line callback-return
+        else
+            process.stderr.write([
+                "protobuf.js v" + pkg.version + " CLI for JavaScript",
+                "",
+                chalk.bold.white("Translates between file formats and generates static code."),
+                "",
+                "  -t, --target     Specifies the target format. Also accepts a path to require a custom target.",
+                "",
+                descs.join("\n"),
+                "",
+                "  -p, --path       Adds a directory to the include path.",
+                "",
+                "  --filter         Set up a filter to configure only those messages you need and their dependencies to compile, this will effectively reduce the final file size",
+                "                   Set A json file path, Example of file content: {\"messageNames\":[\"mypackage.messageName1\", \"messageName2\"] } ",
+                "",
+                "  -o, --out        Saves to a file instead of writing to stdout.",
+                "",
+                "  --sparse         Exports only those types referenced from a main file (experimental).",
+                "",
+                chalk.bold.gray("  Module targets only:"),
+                "",
+                "  -w, --wrap       Specifies the wrapper to use. Also accepts a path to require a custom wrapper.",
+                "",
+                "                   default   Default wrapper supporting both CommonJS and AMD",
+                "                   commonjs  CommonJS wrapper",
+                "                   amd       AMD wrapper",
+                "                   es6       ES6 wrapper (implies --es6)",
+                "                   closure   A closure adding to protobuf.roots where protobuf is a global",
+                "",
+                "  --dependency     Specifies which version of protobuf to require. Accepts any valid module id",
+                "",
+                "  -r, --root       Specifies an alternative protobuf.roots name.",
+                "",
+                "  -l, --lint       Linter configuration. Defaults to protobuf.js-compatible rules:",
+                "",
+                "                   " + lintDefault,
+                "",
+                "  --es6            Enables ES6 syntax (const/let instead of var)",
+                "",
+                chalk.bold.gray("  Proto sources only:"),
+                "",
+                "  --keep-case      Keeps field casing instead of converting to camel case.",
+                "  --alt-comment    Turns on an alternate comment parsing mode that preserves more comments.",
+                "",
+                chalk.bold.gray("  Static targets only:"),
+                "",
+                "  --no-create      Does not generate create functions used for reflection compatibility.",
+                "  --no-encode      Does not generate encode functions.",
+                "  --no-decode      Does not generate decode functions.",
+                "  --no-verify      Does not generate verify functions.",
+                "  --no-convert     Does not generate convert functions like from/toObject",
+                "  --no-delimited   Does not generate delimited encode/decode functions.",
+                "  --no-typeurl     Does not generate getTypeUrl function.",
+                "  --no-beautify    Does not beautify generated code.",
+                "  --no-comments    Does not output any JSDoc comments.",
+                "  --no-service     Does not output service classes.",
+                "",
+                "  --force-long     Enforces the use of 'Long' for s-/u-/int64 and s-/fixed64 fields.",
+                "  --force-number   Enforces the use of 'number' for s-/u-/int64 and s-/fixed64 fields.",
+                "  --force-message  Enforces the use of message instances instead of plain objects.",
+                "",
+                "  --null-defaults  Default value for optional fields is null instead of zero value.",
+                "",
+                "usage: " + chalk.bold.green("pbjs") + " [options] file1.proto file2.json ..." + chalk.gray("  (or pipe)  ") + "other | " + chalk.bold.green("pbjs") + " [options] -",
+                ""
+            ].join("\n"));
+        return 1;
+    }
+
+    if (typeof argv["strict-long"] === "boolean")
+        argv["force-long"] = argv["strict-long"];
+
+    // Resolve glob expressions
+    for (var i = 0; i < files.length;) {
+        if (glob.hasMagic(files[i])) {
+            var matches = glob.sync(files[i]);
+            Array.prototype.splice.apply(files, [i, 1].concat(matches));
+            i += matches.length;
+        } else
+            ++i;
+    }
+
+    // Require custom target
+    if (!target)
+        target = require(path.resolve(process.cwd(), argv.target));
+
+    var root = new protobuf.Root();
+
+    var mainFiles = [];
+
+    // Search include paths when resolving imports
+    root.resolvePath = function pbjsResolvePath(origin, target) {
+        var normOrigin = protobuf.util.path.normalize(origin),
+            normTarget = protobuf.util.path.normalize(target);
+        if (!normOrigin)
+            mainFiles.push(normTarget);
+
+        var resolved = protobuf.util.path.resolve(normOrigin, normTarget, true);
+        var idx = resolved.lastIndexOf("google/protobuf/");
+        if (idx > -1) {
+            var altname = resolved.substring(idx);
+            if (altname in protobuf.common)
+                resolved = altname;
+        }
+
+        if (fs.existsSync(resolved))
+            return resolved;
+
+        for (var i = 0; i < paths.length; ++i) {
+            var iresolved = protobuf.util.path.resolve(paths[i] + "/", target);
+            if (fs.existsSync(iresolved))
+                return iresolved;
+        }
+
+        return resolved;
+    };
+
+    // `--wrap es6` implies `--es6` but not the other way around. You can still use e.g. `--es6 --wrap commonjs`
+    if (argv.wrap === "es6") {
+        argv.es6 = true;
+    }
+
+    var parseOptions = {
+        "keepCase": argv["keep-case"] || false,
+        "alternateCommentMode": argv["alt-comment"] || false,
+    };
+
+    // Read from stdin
+    if (files.length === 1 && files[0] === "-") {
+        var data = [];
+        process.stdin.on("data", function(chunk) {
+            data.push(chunk);
+        });
+        process.stdin.on("end", function() {
+            var source = Buffer.concat(data).toString("utf8");
+            try {
+                if (source.charAt(0) !== "{") {
+                    protobuf.parse.filename = "-";
+                    protobuf.parse(source, root, parseOptions);
+                } else {
+                    var json = JSON.parse(source);
+                    root.setOptions(json.options).addJSON(json);
+                }
+                callTarget();
+            } catch (err) {
+                if (callback) {
+                    callback(err);
+                    return;
+                }
+                throw err;
+            }
+        });
+
+    // Load from disk
+    } else {
+        try {
+            root.loadSync(files, parseOptions).resolveAll(); // sync is deterministic while async is not
+            if (argv.sparse)
+                sparsify(root);
+            callTarget();
+        } catch (err) {
+            if (callback) {
+                callback(err);
+                return undefined;
+            }
+            throw err;
+        }
+    }
+
+    function markReferenced(tobj) {
+        tobj.referenced = true;
+        // also mark a type's fields and oneofs
+        if (tobj.fieldsArray)
+            tobj.fieldsArray.forEach(function(fobj) {
+                fobj.referenced = true;
+            });
+        if (tobj.oneofsArray)
+            tobj.oneofsArray.forEach(function(oobj) {
+                oobj.referenced = true;
+            });
+        // also mark an extension field's extended type, but not its (other) fields
+        if (tobj.extensionField)
+            tobj.extensionField.parent.referenced = true;
+    }
+
+    function sparsify(root) {
+
+        // 1. mark directly or indirectly referenced objects
+        util.traverse(root, function(obj) {
+            if (!obj.filename)
+                return;
+            if (mainFiles.indexOf(obj.filename) > -1)
+                util.traverseResolved(obj, markReferenced);
+        });
+
+        // 2. empty unreferenced objects
+        util.traverse(root, function(obj) {
+            var parent = obj.parent;
+            if (!parent || obj.referenced) // root or referenced
+                return;
+            // remove unreferenced namespaces
+            if (obj instanceof protobuf.Namespace) {
+                var hasReferenced = false;
+                util.traverse(obj, function(iobj) {
+                    if (iobj.referenced)
+                        hasReferenced = true;
+                });
+                if (hasReferenced) { // replace with plain namespace if a namespace subclass
+                    if (obj instanceof protobuf.Type || obj instanceof protobuf.Service) {
+                        var robj = new protobuf.Namespace(obj.name, obj.options);
+                        robj.nested = obj.nested;
+                        parent.add(robj);
+                    }
+                } else // remove completely if nothing inside is referenced
+                    parent.remove(obj);
+
+            // remove everything else unreferenced
+            } else if (!(obj instanceof protobuf.Namespace))
+                parent.remove(obj);
+        });
+
+        // 3. validate that everything is fine
+        root.resolveAll();
+    }
+
+    function filterMessage() {
+        if (argv.filter) {
+            // This is a piece of degradable logic
+            try {
+                const needMessage = JSON.parse(fs.readFileSync(argv.filter));
+                util.filterMessage(root, needMessage);
+            } catch (error) {
+                process.stderr.write(`The filter not work, please check whether the file is correct: ${error.message}\n`);
+            }
+        }
+    }
+
+    function callTarget() {
+        filterMessage();
+        target(root, argv, function targetCallback(err, output) {
+            if (err) {
+                if (callback)
+                    return callback(err);
+                throw err;
+            }
+            try {
+                if (argv.out)
+                    fs.writeFileSync(argv.out, output, { encoding: "utf8" });
+                else if (!callback)
+                    process.stdout.write(output, "utf8");
+                return callback
+                    ? callback(null, output)
+                    : undefined;
+            } catch (err) {
+                if (callback)
+                    return callback(err);
+                throw err;
+            }
+        });
+    }
+
+    return undefined;
+};
diff --git a/cli/pbts.d.ts b/cli/pbts.d.ts
new file mode 100644
index 0000000..35db28c
--- /dev/null
+++ b/cli/pbts.d.ts
@@ -0,0 +1,9 @@
+type pbtsCallback = (err: Error|null, output?: string) => void;
+
+/**
+ * Runs pbts programmatically.
+ * @param {string[]} args Command line arguments
+ * @param {function(?Error, string=)} [callback] Optional completion callback
+ * @returns {number|undefined} Exit code, if known
+ */
+export function main(args: string[], callback?: pbtsCallback): number|undefined;
diff --git a/cli/pbts.js b/cli/pbts.js
new file mode 100644
index 0000000..ffaf0c6
--- /dev/null
+++ b/cli/pbts.js
@@ -0,0 +1,195 @@
+"use strict";
+var child_process = require("child_process"),
+    path     = require("path"),
+    fs       = require("fs"),
+    pkg      = require("./package.json"),
+    minimist = require("minimist"),
+    chalk    = require("chalk"),
+    glob     = require("glob"),
+    tmp      = require("tmp");
+
+/**
+ * Runs pbts programmatically.
+ * @param {string[]} args Command line arguments
+ * @param {function(?Error, string=)} [callback] Optional completion callback
+ * @returns {number|undefined} Exit code, if known
+ */
+exports.main = function(args, callback) {
+    var argv = minimist(args, {
+        alias: {
+            name: "n",
+            out : "o",
+            main: "m",
+            global: "g",
+            import: "i"
+        },
+        string: [ "name", "out", "global", "import" ],
+        boolean: [ "comments", "main" ],
+        default: {
+            comments: true,
+            main: false
+        }
+    });
+
+    var files  = argv._;
+
+    if (!files.length) {
+        if (callback)
+            callback(Error("usage")); // eslint-disable-line callback-return
+        else
+            process.stderr.write([
+                "protobuf.js v" + pkg.version + " CLI for TypeScript",
+                "",
+                chalk.bold.white("Generates TypeScript definitions from annotated JavaScript files."),
+                "",
+                "  -o, --out       Saves to a file instead of writing to stdout.",
+                "",
+                "  -g, --global    Name of the global object in browser environments, if any.",
+                "",
+                "  -i, --import    Comma delimited list of imports. Local names will equal camelCase of the basename.",
+                "",
+                "  --no-comments   Does not output any JSDoc comments.",
+                "",
+                chalk.bold.gray("  Internal flags:"),
+                "",
+                "  -n, --name      Wraps everything in a module of the specified name.",
+                "",
+                "  -m, --main      Whether building the main library without any imports.",
+                "",
+                "usage: " + chalk.bold.green("pbts") + " [options] file1.js file2.js ..." + chalk.bold.gray("  (or)  ") + "other | " + chalk.bold.green("pbts") + " [options] -",
+                ""
+            ].join("\n"));
+        return 1;
+    }
+
+    // Resolve glob expressions
+    for (var i = 0; i < files.length;) {
+        if (glob.hasMagic(files[i])) {
+            var matches = glob.sync(files[i]);
+            Array.prototype.splice.apply(files, [i, 1].concat(matches));
+            i += matches.length;
+        } else
+            ++i;
+    }
+
+    var cleanup = [];
+
+    // Read from stdin (to a temporary file)
+    if (files.length === 1 && files[0] === "-") {
+        var data = [];
+        process.stdin.on("data", function(chunk) {
+            data.push(chunk);
+        });
+        process.stdin.on("end", function() {
+            files[0] = tmp.tmpNameSync() + ".js";
+            fs.writeFileSync(files[0], Buffer.concat(data));
+            cleanup.push(files[0]);
+            callJsdoc();
+        });
+
+    // Load from disk
+    } else {
+        callJsdoc();
+    }
+
+    function callJsdoc() {
+
+        // There is no proper API for jsdoc, so this executes the CLI and pipes the output
+        var basedir = path.join(__dirname, ".");
+        var moduleName = argv.name || "null";
+        var nodePath = process.execPath;
+        var cmd = "\"" + nodePath + "\" \"" + require.resolve("jsdoc/jsdoc.js") + "\" -c \"" + path.join(basedir, "lib", "tsd-jsdoc.json") + "\" -q \"module=" + encodeURIComponent(moduleName) + "&comments=" + Boolean(argv.comments) + "\" " + files.map(function(file) { return "\"" + file + "\""; }).join(" ");
+        var child = child_process.exec(cmd, {
+            cwd: process.cwd(),
+            argv0: "node",
+            stdio: "pipe",
+            maxBuffer: 1 << 24 // 16mb
+        });
+        var out = [];
+        var ended = false;
+        var closed = false;
+        child.stdout.on("data", function(data) {
+            out.push(data);
+        });
+        child.stdout.on("end", function() {
+            if (closed) finish();
+            else ended = true;
+        });
+        child.stderr.pipe(process.stderr);
+        child.on("close", function(code) {
+            // clean up temporary files, no matter what
+            try { cleanup.forEach(fs.unlinkSync); } catch(e) {/**/} cleanup = [];
+
+            if (code) {
+                out = out.join("").replace(/\s*JSDoc \d+\.\d+\.\d+ [^$]+/, "");
+                process.stderr.write(out);
+                var err = Error("code " + code);
+                if (callback)
+                    return callback(err);
+                throw err;
+            }
+
+            if (ended) return finish();
+            closed = true;
+            return undefined;
+        });
+
+        function getImportName(importItem) {
+            return path.basename(importItem, ".js").replace(/([-_~.+]\w)/g, function(match) {
+                return match[1].toUpperCase();
+            });
+        }
+
+        function finish() {
+            var output = [];
+            if (argv.main)
+                output.push(
+                    "// DO NOT EDIT! This is a generated file. Edit the JSDoc in src/*.js instead and run 'npm run build:types'.",
+                    ""
+                );
+            if (argv.global)
+                output.push(
+                    "export as namespace " + argv.global + ";",
+                    ""
+                );
+
+            if (!argv.main) {
+                // Ensure we have a usable array of imports
+                var importArray = typeof argv.import === "string" ? argv.import.split(",") : argv.import || [];
+
+                // Build an object of imports and paths
+                var imports = {
+                    $protobuf: "protobufjs"
+                };
+                importArray.forEach(function(importItem) {
+                    imports[getImportName(importItem)] = importItem;
+                });
+
+                // Write out the imports
+                Object.keys(imports).forEach(function(key) {
+                    output.push("import * as " + key + " from \"" + imports[key] + "\";");
+                });
+
+                output.push("import Long = require(\"long\");");
+            }
+
+            output = output.join("\n") + "\n" + out.join("");
+
+            try {
+                if (argv.out)
+                    fs.writeFileSync(argv.out, output, { encoding: "utf8" });
+                else if (!callback)
+                    process.stdout.write(output, "utf8");
+                return callback
+                    ? callback(null, output)
+                    : undefined;
+            } catch (err) {
+                if (callback)
+                    return callback(err);
+                throw err;
+            }
+        }
+    }
+
+    return undefined;
+};
diff --git a/cli/scripts/prepublish.js b/cli/scripts/prepublish.js
new file mode 100644
index 0000000..dc38f75
--- /dev/null
+++ b/cli/scripts/prepublish.js
@@ -0,0 +1,13 @@
+"use strict";
+
+var path = require("path"),
+    fs   = require("fs");
+
+// ensure LF on bin files
+[
+    path.join(__dirname, "..", "bin", "pbjs"),
+    path.join(__dirname, "..", "bin", "pbts")
+]
+.forEach(function(file) {
+    fs.writeFileSync(file, fs.readFileSync(file).toString("utf8").replace(/\r?\n/g, "\n"), "utf8");
+});
diff --git a/cli/targets/json-module.js b/cli/targets/json-module.js
new file mode 100644
index 0000000..b879026
--- /dev/null
+++ b/cli/targets/json-module.js
@@ -0,0 +1,38 @@
+"use strict";
+module.exports = json_module;
+
+var util = require("../util");
+
+var protobuf = require("protobufjs");
+
+json_module.description = "JSON representation as a module";
+
+function jsonSafeProp(json) {
+    return json.replace(/^( +)"(\w+)":/mg, function($0, $1, $2) {
+        return protobuf.util.safeProp($2).charAt(0) === "."
+            ? $1 + $2 + ":"
+            : $0;
+    });
+}
+
+function json_module(root, options, callback) {
+    try {
+        var rootProp = protobuf.util.safeProp(options.root || "default");
+        var output = [
+            (options.es6 ? "const" : "var") + " $root = ($protobuf.roots" + rootProp + " || ($protobuf.roots" + rootProp + " = new $protobuf.Root()))\n"
+        ];
+        if (root.options) {
+            var optionsJson = jsonSafeProp(JSON.stringify(root.options, null, 2));
+            output.push(".setOptions(" + optionsJson + ")\n");
+        }
+        var json = jsonSafeProp(JSON.stringify(root.nested, null, 2).trim());
+        output.push(".addJSON(" + json + ");");
+        output = util.wrap(output.join(""), protobuf.util.merge({ dependency: "protobufjs/light" }, options));
+        process.nextTick(function() {
+            callback(null, output);
+        });
+    } catch (e) {
+        return callback(e);
+    }
+    return undefined;
+}
diff --git a/cli/targets/json.js b/cli/targets/json.js
new file mode 100644
index 0000000..7025372
--- /dev/null
+++ b/cli/targets/json.js
@@ -0,0 +1,8 @@
+"use strict";
+module.exports = json_target;
+
+json_target.description = "JSON representation";
+
+function json_target(root, options, callback) {
+    callback(null, JSON.stringify(root, null, 2));
+}
diff --git a/cli/targets/proto.js b/cli/targets/proto.js
new file mode 100644
index 0000000..74abd5a
--- /dev/null
+++ b/cli/targets/proto.js
@@ -0,0 +1,326 @@
+"use strict";
+module.exports = proto_target;
+
+proto_target.private = true;
+
+var protobuf = require("protobufjs");
+
+var Namespace  = protobuf.Namespace,
+    Enum       = protobuf.Enum,
+    Type       = protobuf.Type,
+    Field      = protobuf.Field,
+    OneOf      = protobuf.OneOf,
+    Service    = protobuf.Service,
+    Method     = protobuf.Method,
+    types      = protobuf.types,
+    util       = protobuf.util;
+
+function underScore(str) {
+    return str.substring(0,1)
+         + str.substring(1)
+               .replace(/([A-Z])(?=[a-z]|$)/g, function($0, $1) { return "_" + $1.toLowerCase(); });
+}
+
+var out = [];
+var indent = 0;
+var first = false;
+var syntax = 3;
+
+function proto_target(root, options, callback) {
+    if (options) {
+        switch (options.syntax) {
+            case undefined:
+            case "proto3":
+            case "3":
+                syntax = 3;
+                break;
+            case "proto2":
+            case "2":
+                syntax = 2;
+                break;
+            default:
+                return callback(Error("invalid syntax: " + options.syntax));
+        }
+    }
+    indent = 0;
+    first = false;
+    try {
+        buildRoot(root);
+        return callback(null, out.join("\n"));
+    } catch (err) {
+        return callback(err);
+    } finally {
+        out = [];
+        syntax = 3;
+    }
+}
+
+function push(line) {
+    if (line === "")
+        out.push("");
+    else {
+        var ind = "";
+        for (var i = 0; i < indent; ++i)
+            ind += "    ";
+        out.push(ind + line);
+    }
+}
+
+function escape(str) {
+    return str.replace(/[\\"']/g, "\\$&")
+              .replace(/\r/g, "\\r")
+              .replace(/\n/g, "\\n")
+              .replace(/\u0000/g, "\\0"); // eslint-disable-line no-control-regex
+}
+
+function value(v) {
+    switch (typeof v) {
+        case "boolean":
+            return v ? "true" : "false";
+        case "number":
+            return v.toString();
+        default:
+            return "\"" + escape(String(v)) + "\"";
+    }
+}
+
+function buildRoot(root) {
+    root.resolveAll();
+    var pkg = [];
+    var ptr = root;
+    var repeat = true;
+    do {
+        var nested = ptr.nestedArray;
+        if (nested.length === 1 && nested[0] instanceof Namespace && !(nested[0] instanceof Type || nested[0] instanceof Service)) {
+            ptr = nested[0];
+            if (ptr !== root)
+                pkg.push(ptr.name);
+        } else
+            repeat = false;
+    } while (repeat);
+    out.push("syntax = \"proto" + syntax + "\";");
+    if (pkg.length)
+        out.push("", "package " + pkg.join(".") + ";");
+
+    buildOptions(ptr);
+    ptr.nestedArray.forEach(build);
+}
+
+function build(object) {
+    if (object instanceof Enum)
+        buildEnum(object);
+    else if (object instanceof Type)
+        buildType(object);
+    else if (object instanceof Field)
+        buildField(object);
+    else if (object instanceof OneOf)
+        buildOneOf(object);
+    else if (object instanceof Service)
+        buildService(object);
+    else if (object instanceof Method)
+        buildMethod(object);
+    else
+        buildNamespace(object);
+}
+
+function buildNamespace(namespace) { // just a namespace, not a type etc.
+    push("");
+    push("message " + namespace.name + " {");
+    ++indent;
+    buildOptions(namespace);
+    consolidateExtends(namespace.nestedArray).remaining.forEach(build);
+    --indent;
+    push("}");
+}
+
+function buildEnum(enm) {
+    push("");
+    push("enum " + enm.name + " {");
+    buildOptions(enm);
+    ++indent; first = true;
+    Object.keys(enm.values).forEach(function(name) {
+        var val = enm.values[name];
+        if (first) {
+            push("");
+            first = false;
+        }
+        push(name + " = " + val + ";");
+    });
+    --indent; first = false;
+    push("}");
+}
+
+function buildRanges(keyword, ranges) {
+    if (ranges && ranges.length) {
+        var parts = [];
+        ranges.forEach(function(range) {
+            if (typeof range === "string")
+                parts.push("\"" + escape(range) + "\"");
+            else if (range[0] === range[1])
+                parts.push(range[0]);
+            else
+                parts.push(range[0] + " to " + (range[1] === 0x1FFFFFFF ? "max" : range[1]));
+        });
+        push("");
+        push(keyword + " " + parts.join(", ") + ";");
+    }
+}
+
+function buildType(type) {
+    if (type.group)
+        return; // built with the sister-field
+    push("");
+    push("message " + type.name + " {");
+    ++indent;
+    buildOptions(type);
+    type.oneofsArray.forEach(build);
+    first = true;
+    type.fieldsArray.forEach(build);
+    consolidateExtends(type.nestedArray).remaining.forEach(build);
+    buildRanges("extensions", type.extensions);
+    buildRanges("reserved", type.reserved);
+    --indent;
+    push("}");
+}
+
+function buildField(field, passExtend) {
+    if (field.partOf || field.declaringField || field.extend !== undefined && !passExtend)
+        return;
+    if (first) {
+        first = false;
+        push("");
+    }
+    if (field.resolvedType && field.resolvedType.group) {
+        buildGroup(field);
+        return;
+    }
+    var sb = [];
+    if (field.map)
+        sb.push("map<" + field.keyType + ", " + field.type + ">");
+    else if (field.repeated)
+        sb.push("repeated", field.type);
+    else if (syntax === 2 || field.parent.group)
+        sb.push(field.required ? "required" : "optional", field.type);
+    else
+        sb.push(field.type);
+    sb.push(underScore(field.name), "=", field.id);
+    var opts = buildFieldOptions(field);
+    if (opts)
+        sb.push(opts);
+    push(sb.join(" ") + ";");
+}
+
+function buildGroup(field) {
+    push(field.rule + " group " + field.resolvedType.name + " = " + field.id + " {");
+    ++indent;
+    buildOptions(field.resolvedType);
+    first = true;
+    field.resolvedType.fieldsArray.forEach(function(field) {
+        buildField(field);
+    });
+    --indent;
+    push("}");
+}
+
+function buildFieldOptions(field) {
+    var keys;
+    if (!field.options || !(keys = Object.keys(field.options)).length)
+        return null;
+    var sb = [];
+    keys.forEach(function(key) {
+        var val = field.options[key];
+        var wireType = types.packed[field.resolvedType instanceof Enum ? "int32" : field.type];
+        switch (key) {
+            case "packed":
+                val = Boolean(val);
+                // skip when not packable or syntax default
+                if (wireType === undefined || syntax === 3 === val)
+                    return;
+                break;
+            case "default":
+                if (syntax === 3)
+                    return;
+                // skip default (resolved) default values
+                if (field.long && !util.longNeq(field.defaultValue, types.defaults[field.type]) || !field.long && field.defaultValue === types.defaults[field.type])
+                    return;
+                // enum defaults specified as strings are type references and not enclosed in quotes
+                if (field.resolvedType instanceof Enum)
+                    break;
+                // otherwise fallthrough
+            default:
+                val = value(val);
+                break;
+        }
+        sb.push(key + "=" + val);
+    });
+    return sb.length
+        ? "[" + sb.join(", ") + "]"
+        : null;
+}
+
+function consolidateExtends(nested) {
+    var ext = {};
+    nested = nested.filter(function(obj) {
+        if (!(obj instanceof Field) || obj.extend === undefined)
+            return true;
+        (ext[obj.extend] || (ext[obj.extend] = [])).push(obj);
+        return false;
+    });
+    Object.keys(ext).forEach(function(extend) {
+        push("");
+        push("extend " + extend + " {");
+        ++indent; first = true;
+        ext[extend].forEach(function(field) {
+            buildField(field, true);
+        });
+        --indent;
+        push("}");
+    });
+    return {
+        remaining: nested
+    };
+}
+
+function buildOneOf(oneof) {
+    push("");
+    push("oneof " + underScore(oneof.name) + " {");
+    ++indent; first = true;
+    oneof.oneof.forEach(function(fieldName) {
+        var field = oneof.parent.get(fieldName);
+        if (first) {
+            first = false;
+            push("");
+        }
+        var opts = buildFieldOptions(field);
+        push(field.type + " " + underScore(field.name) + " = " + field.id + (opts ? " " + opts : "") + ";");
+    });
+    --indent;
+    push("}");
+}
+
+function buildService(service) {
+    push("service " + service.name + " {");
+    ++indent;
+    service.methodsArray.forEach(build);
+    consolidateExtends(service.nestedArray).remaining.forEach(build);
+    --indent;
+    push("}");
+}
+
+function buildMethod(method) {
+    push(method.type + " " + method.name + " (" + (method.requestStream ? "stream " : "") + method.requestType + ") returns (" + (method.responseStream ? "stream " : "") + method.responseType + ");");
+}
+
+function buildOptions(object) {
+    if (!object.options)
+        return;
+    first = true;
+    Object.keys(object.options).forEach(function(key) {
+        if (first) {
+            first = false;
+            push("");
+        }
+        var val = object.options[key];
+        push("option " + key + " = " + JSON.stringify(val) + ";");
+    });
+}
diff --git a/cli/targets/proto2.js b/cli/targets/proto2.js
new file mode 100644
index 0000000..b349f57
--- /dev/null
+++ b/cli/targets/proto2.js
@@ -0,0 +1,10 @@
+"use strict";
+module.exports = proto2_target;
+
+var protobuf = require("protobufjs");
+
+proto2_target.description = "Protocol Buffers, Version 2";
+
+function proto2_target(root, options, callback) {
+    require("./proto")(root, protobuf.util.merge(options, { syntax: "proto2" }), callback);
+}
diff --git a/cli/targets/proto3.js b/cli/targets/proto3.js
new file mode 100644
index 0000000..397b567
--- /dev/null
+++ b/cli/targets/proto3.js
@@ -0,0 +1,10 @@
+"use strict";
+module.exports = proto3_target;
+
+var protobuf = require("protobufjs");
+
+proto3_target.description = "Protocol Buffers, Version 3";
+
+function proto3_target(root, options, callback) {
+    require("./proto")(root, protobuf.util.merge(options, { syntax: "proto3" }), callback);
+}
diff --git a/cli/targets/static-module.js b/cli/targets/static-module.js
new file mode 100644
index 0000000..7d16c2f
--- /dev/null
+++ b/cli/targets/static-module.js
@@ -0,0 +1,28 @@
+"use strict";
+module.exports = static_module_target;
+
+// - The default wrapper supports AMD, CommonJS and the global scope (as window.root), in this order.
+// - You can specify a custom wrapper with the --wrap argument.
+// - CommonJS modules depend on the minimal build for reduced package size with browserify.
+// - AMD and global scope depend on the full library for now.
+
+var util          = require("../util"),
+    protobuf      = require("protobufjs");
+
+static_module_target.description = "Static code without reflection as a module";
+
+function static_module_target(root, options, callback) {
+    require("./static")(root, options, function(err, output) {
+        if (err) {
+            callback(err);
+            return;
+        }
+        try {
+            output = util.wrap(output, protobuf.util.merge({ dependency: "protobufjs/minimal" }, options));
+        } catch (e) {
+            callback(e);
+            return;
+        }
+        callback(null, output);
+    });
+}
diff --git a/cli/targets/static.js b/cli/targets/static.js
new file mode 100644
index 0000000..c130d90
--- /dev/null
+++ b/cli/targets/static.js
@@ -0,0 +1,733 @@
+"use strict";
+module.exports = static_target;
+
+var UglifyJS   = require("uglify-js"),
+    espree     = require("espree"),
+    escodegen  = require("escodegen"),
+    estraverse = require("estraverse"),
+    protobuf   = require("protobufjs");
+
+var Type      = protobuf.Type,
+    Service   = protobuf.Service,
+    Enum      = protobuf.Enum,
+    Namespace = protobuf.Namespace,
+    util      = protobuf.util;
+
+var out = [];
+var indent = 0;
+var config = {};
+
+static_target.description = "Static code without reflection (non-functional on its own)";
+
+function static_target(root, options, callback) {
+    config = options;
+    try {
+        var aliases = [];
+        if (config.decode)
+            aliases.push("Reader");
+        if (config.encode)
+            aliases.push("Writer");
+        aliases.push("util");
+        if (aliases.length) {
+            if (config.comments)
+                push("// Common aliases");
+            push((config.es6 ? "const " : "var ") + aliases.map(function(name) { return "$" + name + " = $protobuf." + name; }).join(", ") + ";");
+            push("");
+        }
+        if (config.comments) {
+            if (root.comment) {
+                pushComment("@fileoverview " + root.comment);
+                push("");
+            }
+            push("// Exported root namespace");
+        }
+        var rootProp = util.safeProp(config.root || "default");
+        push((config.es6 ? "const" : "var") + " $root = $protobuf.roots" + rootProp + " || ($protobuf.roots" + rootProp + " = {});");
+        buildNamespace(null, root);
+        return callback(null, out.join("\n"));
+    } catch (err) {
+        return callback(err);
+    } finally {
+        out = [];
+        indent = 0;
+        config = {};
+    }
+}
+
+function push(line) {
+    if (line === "")
+        return out.push("");
+    var ind = "";
+    for (var i = 0; i < indent; ++i)
+        ind += "    ";
+    return out.push(ind + line);
+}
+
+function pushComment(lines) {
+    if (!config.comments)
+        return;
+    var split = [];
+    for (var i = 0; i < lines.length; ++i)
+        if (lines[i] != null && lines[i].substring(0, 8) !== "@exclude")
+            Array.prototype.push.apply(split, lines[i].split(/\r?\n/g));
+    push("/**");
+    split.forEach(function(line) {
+        if (line === null)
+            return;
+        push(" * " + line.replace(/\*\//g, "* /"));
+    });
+    push(" */");
+}
+
+function exportName(object, asInterface) {
+    if (asInterface) {
+        if (object.__interfaceName)
+            return object.__interfaceName;
+    } else if (object.__exportName)
+        return object.__exportName;
+    var parts = object.fullName.substring(1).split("."),
+        i = 0;
+    while (i < parts.length)
+        parts[i] = escapeName(parts[i++]);
+    if (asInterface)
+        parts[i - 1] = "I" + parts[i - 1];
+    return object[asInterface ? "__interfaceName" : "__exportName"] = parts.join(".");
+}
+
+function escapeName(name) {
+    if (!name)
+        return "$root";
+    return util.isReserved(name) ? name + "_" : name;
+}
+
+function aOrAn(name) {
+    return ((/^[hH](?:ou|on|ei)/.test(name) || /^[aeiouAEIOU][a-z]/.test(name)) && !/^us/i.test(name)
+        ? "an "
+        : "a ") + name;
+}
+
+function buildNamespace(ref, ns) {
+    if (!ns)
+        return;
+
+    if (ns instanceof Service && !config.service)
+        return;
+
+    if (ns.name !== "") {
+        push("");
+        if (!ref && config.es6)
+            push("export const " + escapeName(ns.name) + " = " + escapeName(ref) + "." + escapeName(ns.name) + " = (() => {");
+        else
+            push(escapeName(ref) + "." + escapeName(ns.name) + " = (function() {");
+        ++indent;
+    }
+
+    if (ns instanceof Type) {
+        buildType(undefined, ns);
+    } else if (ns instanceof Service)
+        buildService(undefined, ns);
+    else if (ns.name !== "") {
+        push("");
+        pushComment([
+            ns.comment || "Namespace " + ns.name + ".",
+            ns.parent instanceof protobuf.Root ? "@exports " + escapeName(ns.name) : "@memberof " + exportName(ns.parent),
+            "@namespace"
+        ]);
+        push((config.es6 ? "const" : "var") + " " + escapeName(ns.name) + " = {};");
+    }
+
+    ns.nestedArray.forEach(function(nested) {
+        if (nested instanceof Enum)
+            buildEnum(ns.name, nested);
+        else if (nested instanceof Namespace)
+            buildNamespace(ns.name, nested);
+    });
+    if (ns.name !== "") {
+        push("");
+        push("return " + escapeName(ns.name) + ";");
+        --indent;
+        push("})();");
+    }
+}
+
+var reduceableBlockStatements = {
+    IfStatement: true,
+    ForStatement: true,
+    WhileStatement: true
+};
+
+var shortVars = {
+    "r": "reader",
+    "w": "writer",
+    "m": "message",
+    "t": "tag",
+    "l": "length",
+    "c": "end", "c2": "end2",
+    "k": "key",
+    "ks": "keys", "ks2": "keys2",
+    "e": "error",
+    "f": "impl",
+    "o": "options",
+    "d": "object",
+    "n": "long",
+    "p": "properties"
+};
+
+function beautifyCode(code) {
+    // Add semicolons
+    code = UglifyJS.minify(code, {
+        compress: false,
+        mangle: false,
+        output: { beautify: true }
+    }).code;
+    // Properly beautify
+    var ast = espree.parse(code);
+    estraverse.replace(ast, {
+        enter: function(node, parent) {
+            // rename short vars
+            if (node.type === "Identifier" && (parent.property !== node || parent.computed) && shortVars[node.name])
+                return {
+                    "type": "Identifier",
+                    "name": shortVars[node.name]
+                };
+            // replace var with let if es6
+            if (config.es6 && node.type === "VariableDeclaration" && node.kind === "var") {
+                node.kind = "let";
+                return undefined;
+            }
+            // remove braces around block statements with a single child
+            if (node.type === "BlockStatement" && reduceableBlockStatements[parent.type] && node.body.length === 1)
+                return node.body[0];
+            return undefined;
+        }
+    });
+    code = escodegen.generate(ast, {
+        format: {
+            newline: "\n",
+            quotes: "double"
+        }
+    });
+    // Add id, wireType comments
+    if (config.comments)
+        code = code.replace(/\.uint32\((\d+)\)/g, function($0, $1) {
+            var id = $1 >>> 3,
+                wireType = $1 & 7;
+            return ".uint32(/* id " + id + ", wireType " + wireType + " =*/" + $1 + ")";
+        });
+    return code;
+}
+
+var renameVars = {
+    "Writer": "$Writer",
+    "Reader": "$Reader",
+    "util": "$util"
+};
+
+function buildFunction(type, functionName, gen, scope) {
+    var code = gen.toString(functionName)
+        .replace(/((?!\.)types\[\d+])(\.values)/g, "$1"); // enums: use types[N] instead of reflected types[N].values
+
+    var ast = espree.parse(code);
+    /* eslint-disable no-extra-parens */
+    estraverse.replace(ast, {
+        enter: function(node, parent) {
+            // rename vars
+            if (
+                node.type === "Identifier" && renameVars[node.name]
+                && (
+                    (parent.type === "MemberExpression" && parent.object === node)
+                 || (parent.type === "BinaryExpression" && parent.right === node)
+                )
+            )
+                return {
+                    "type": "Identifier",
+                    "name": renameVars[node.name]
+                };
+            // replace this.ctor with the actual ctor
+            if (
+                node.type === "MemberExpression"
+             && node.object.type === "ThisExpression"
+             && node.property.type === "Identifier" && node.property.name === "ctor"
+            )
+                return {
+                    "type": "Identifier",
+                    "name": "$root" + type.fullName
+                };
+            // replace types[N] with the field's actual type
+            if (
+                node.type === "MemberExpression"
+             && node.object.type === "Identifier" && node.object.name === "types"
+             && node.property.type === "Literal"
+            )
+                return {
+                    "type": "Identifier",
+                    "name": "$root" + type.fieldsArray[node.property.value].resolvedType.fullName
+                };
+            return undefined;
+        }
+    });
+    /* eslint-enable no-extra-parens */
+    code = escodegen.generate(ast, {
+        format: {
+            newline: "\n",
+            quotes: "double"
+        }
+    });
+
+    if (config.beautify)
+        code = beautifyCode(code);
+
+    code = code.replace(/ {4}/g, "\t");
+
+    var hasScope = scope && Object.keys(scope).length,
+        isCtor = functionName === type.name;
+
+    if (hasScope) // remove unused scope vars
+        Object.keys(scope).forEach(function(key) {
+            if (!new RegExp("\\b(" + key + ")\\b", "g").test(code))
+                delete scope[key];
+        });
+
+    var lines = code.split(/\n/g);
+    if (isCtor) // constructor
+        push(lines[0]);
+    else if (hasScope) // enclose in an iife
+        push(escapeName(type.name) + "." + escapeName(functionName) + " = (function(" + Object.keys(scope).map(escapeName).join(", ") + ") { return " + lines[0]);
+    else
+        push(escapeName(type.name) + "." + escapeName(functionName) + " = " + lines[0]);
+    lines.slice(1, lines.length - 1).forEach(function(line) {
+        var prev = indent;
+        var i = 0;
+        while (line.charAt(i++) === "\t")
+            ++indent;
+        push(line.trim());
+        indent = prev;
+    });
+    if (isCtor)
+        push("}");
+    else if (hasScope)
+        push("};})(" + Object.keys(scope).map(function(key) { return scope[key]; }).join(", ") + ");");
+    else
+        push("};");
+}
+
+function toJsType(field) {
+    var type;
+
+    switch (field.type) {
+        case "double":
+        case "float":
+        case "int32":
+        case "uint32":
+        case "sint32":
+        case "fixed32":
+        case "sfixed32":
+            type = "number";
+            break;
+        case "int64":
+        case "uint64":
+        case "sint64":
+        case "fixed64":
+        case "sfixed64":
+            type = config.forceLong ? "Long" : config.forceNumber ? "number" : "number|Long";
+            break;
+        case "bool":
+            type = "boolean";
+            break;
+        case "string":
+            type = "string";
+            break;
+        case "bytes":
+            type = "Uint8Array";
+            break;
+        default:
+            if (field.resolve().resolvedType)
+                type = exportName(field.resolvedType, !(field.resolvedType instanceof protobuf.Enum || config.forceMessage));
+            else
+                type = "*"; // should not happen
+            break;
+    }
+    if (field.map)
+        return "Object.<string," + type + ">";
+    if (field.repeated)
+        return "Array.<" + type + ">";
+    return type;
+}
+
+function buildType(ref, type) {
+
+    if (config.comments) {
+        var typeDef = [
+            "Properties of " + aOrAn(type.name) + ".",
+            type.parent instanceof protobuf.Root ? "@exports " + escapeName("I" + type.name) : "@memberof " + exportName(type.parent),
+            "@interface " + escapeName("I" + type.name)
+        ];
+        type.fieldsArray.forEach(function(field) {
+            var prop = util.safeProp(field.name); // either .name or ["name"]
+            prop = prop.substring(1, prop.charAt(0) === "[" ? prop.length - 1 : prop.length);
+            var jsType = toJsType(field);
+            if (field.optional)
+                jsType = jsType + "|null";
+            typeDef.push("@property {" + jsType + "} " + (field.optional ? "[" + prop + "]" : prop) + " " + (field.comment || type.name + " " + field.name));
+        });
+        push("");
+        pushComment(typeDef);
+    }
+
+    // constructor
+    push("");
+    pushComment([
+        "Constructs a new " + type.name + ".",
+        type.parent instanceof protobuf.Root ? "@exports " + escapeName(type.name) : "@memberof " + exportName(type.parent),
+        "@classdesc " + (type.comment || "Represents " + aOrAn(type.name) + "."),
+        config.comments ? "@implements " + escapeName("I" + type.name) : null,
+        "@constructor",
+        "@param {" + exportName(type, true) + "=} [" + (config.beautify ? "properties" : "p") + "] Properties to set"
+    ]);
+    buildFunction(type, type.name, Type.generateConstructor(type));
+
+    // default values
+    var firstField = true;
+    type.fieldsArray.forEach(function(field) {
+        field.resolve();
+        var prop = util.safeProp(field.name);
+        if (config.comments) {
+            push("");
+            var jsType = toJsType(field);
+            if (field.optional && !field.map && !field.repeated && (field.resolvedType instanceof Type || config["null-defaults"]) || field.partOf)
+                jsType = jsType + "|null|undefined";
+            pushComment([
+                field.comment || type.name + " " + field.name + ".",
+                "@member {" + jsType + "} " + field.name,
+                "@memberof " + exportName(type),
+                "@instance"
+            ]);
+        } else if (firstField) {
+            push("");
+            firstField = false;
+        }
+        if (field.repeated)
+            push(escapeName(type.name) + ".prototype" + prop + " = $util.emptyArray;"); // overwritten in constructor
+        else if (field.map)
+            push(escapeName(type.name) + ".prototype" + prop + " = $util.emptyObject;"); // overwritten in constructor
+        else if (field.partOf || field.optional && config["null-defaults"])
+            push(escapeName(type.name) + ".prototype" + prop + " = null;"); // do not set default value for oneof members
+        else if (field.long)
+            push(escapeName(type.name) + ".prototype" + prop + " = $util.Long ? $util.Long.fromBits("
+                    + JSON.stringify(field.typeDefault.low) + ","
+                    + JSON.stringify(field.typeDefault.high) + ","
+                    + JSON.stringify(field.typeDefault.unsigned)
+                + ") : " + field.typeDefault.toNumber(field.type.charAt(0) === "u") + ";");
+        else if (field.bytes) {
+            push(escapeName(type.name) + ".prototype" + prop + " = $util.newBuffer(" + JSON.stringify(Array.prototype.slice.call(field.typeDefault)) + ");");
+        } else
+            push(escapeName(type.name) + ".prototype" + prop + " = " + JSON.stringify(field.typeDefault) + ";");
+    });
+
+    // virtual oneof fields
+    var firstOneOf = true;
+    type.oneofsArray.forEach(function(oneof) {
+        if (firstOneOf) {
+            firstOneOf = false;
+            push("");
+            if (config.comments)
+                push("// OneOf field names bound to virtual getters and setters");
+            push((config.es6 ? "let" : "var") + " $oneOfFields;");
+        }
+        oneof.resolve();
+        push("");
+        pushComment([
+            oneof.comment || type.name + " " + oneof.name + ".",
+            "@member {" + oneof.oneof.map(JSON.stringify).join("|") + "|undefined} " + escapeName(oneof.name),
+            "@memberof " + exportName(type),
+            "@instance"
+        ]);
+        push("Object.defineProperty(" + escapeName(type.name) + ".prototype, " + JSON.stringify(oneof.name) +", {");
+        ++indent;
+            push("get: $util.oneOfGetter($oneOfFields = [" + oneof.oneof.map(JSON.stringify).join(", ") + "]),");
+            push("set: $util.oneOfSetter($oneOfFields)");
+        --indent;
+        push("});");
+    });
+
+    if (config.create) {
+        push("");
+        pushComment([
+            "Creates a new " + type.name + " instance using the specified properties.",
+            "@function create",
+            "@memberof " + exportName(type),
+            "@static",
+            "@param {" + exportName(type, true) + "=} [properties] Properties to set",
+            "@returns {" + exportName(type) + "} " + type.name + " instance"
+        ]);
+        push(escapeName(type.name) + ".create = function create(properties) {");
+            ++indent;
+            push("return new " + escapeName(type.name) + "(properties);");
+            --indent;
+        push("};");
+    }
+
+    if (config.encode) {
+        push("");
+        pushComment([
+            "Encodes the specified " + type.name + " message. Does not implicitly {@link " + exportName(type) + ".verify|verify} messages.",
+            "@function encode",
+            "@memberof " + exportName(type),
+            "@static",
+            "@param {" + exportName(type, !config.forceMessage) + "} " + (config.beautify ? "message" : "m") + " " + type.name + " message or plain object to encode",
+            "@param {$protobuf.Writer} [" + (config.beautify ? "writer" : "w") + "] Writer to encode to",
+            "@returns {$protobuf.Writer} Writer"
+        ]);
+        buildFunction(type, "encode", protobuf.encoder(type));
+
+        if (config.delimited) {
+            push("");
+            pushComment([
+                "Encodes the specified " + type.name + " message, length delimited. Does not implicitly {@link " + exportName(type) + ".verify|verify} messages.",
+                "@function encodeDelimited",
+                "@memberof " + exportName(type),
+                "@static",
+                "@param {" + exportName(type, !config.forceMessage) + "} message " + type.name + " message or plain object to encode",
+                "@param {$protobuf.Writer} [writer] Writer to encode to",
+                "@returns {$protobuf.Writer} Writer"
+            ]);
+            push(escapeName(type.name) + ".encodeDelimited = function encodeDelimited(message, writer) {");
+            ++indent;
+            push("return this.encode(message, writer).ldelim();");
+            --indent;
+            push("};");
+        }
+    }
+
+    if (config.decode) {
+        push("");
+        pushComment([
+            "Decodes " + aOrAn(type.name) + " message from the specified reader or buffer.",
+            "@function decode",
+            "@memberof " + exportName(type),
+            "@static",
+            "@param {$protobuf.Reader|Uint8Array} " + (config.beautify ? "reader" : "r") + " Reader or buffer to decode from",
+            "@param {number} [" + (config.beautify ? "length" : "l") + "] Message length if known beforehand",
+            "@returns {" + exportName(type) + "} " + type.name,
+            "@throws {Error} If the payload is not a reader or valid buffer",
+            "@throws {$protobuf.util.ProtocolError} If required fields are missing"
+        ]);
+        buildFunction(type, "decode", protobuf.decoder(type));
+
+        if (config.delimited) {
+            push("");
+            pushComment([
+                "Decodes " + aOrAn(type.name) + " message from the specified reader or buffer, length delimited.",
+                "@function decodeDelimited",
+                "@memberof " + exportName(type),
+                "@static",
+                "@param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from",
+                "@returns {" + exportName(type) + "} " + type.name,
+                "@throws {Error} If the payload is not a reader or valid buffer",
+                "@throws {$protobuf.util.ProtocolError} If required fields are missing"
+            ]);
+            push(escapeName(type.name) + ".decodeDelimited = function decodeDelimited(reader) {");
+            ++indent;
+                push("if (!(reader instanceof $Reader))");
+                ++indent;
+                    push("reader = new $Reader(reader);");
+                --indent;
+                push("return this.decode(reader, reader.uint32());");
+            --indent;
+            push("};");
+        }
+    }
+
+    if (config.verify) {
+        push("");
+        pushComment([
+            "Verifies " + aOrAn(type.name) + " message.",
+            "@function verify",
+            "@memberof " + exportName(type),
+            "@static",
+            "@param {Object.<string,*>} " + (config.beautify ? "message" : "m") + " Plain object to verify",
+            "@returns {string|null} `null` if valid, otherwise the reason why it is not"
+        ]);
+        buildFunction(type, "verify", protobuf.verifier(type));
+    }
+
+    if (config.convert) {
+        push("");
+        pushComment([
+            "Creates " + aOrAn(type.name) + " message from a plain object. Also converts values to their respective internal types.",
+            "@function fromObject",
+            "@memberof " + exportName(type),
+            "@static",
+            "@param {Object.<string,*>} " + (config.beautify ? "object" : "d") + " Plain object",
+            "@returns {" + exportName(type) + "} " + type.name
+        ]);
+        buildFunction(type, "fromObject", protobuf.converter.fromObject(type));
+
+        push("");
+        pushComment([
+            "Creates a plain object from " + aOrAn(type.name) + " message. Also converts values to other types if specified.",
+            "@function toObject",
+            "@memberof " + exportName(type),
+            "@static",
+            "@param {" + exportName(type) + "} " + (config.beautify ? "message" : "m") + " " + type.name,
+            "@param {$protobuf.IConversionOptions} [" + (config.beautify ? "options" : "o") + "] Conversion options",
+            "@returns {Object.<string,*>} Plain object"
+        ]);
+        buildFunction(type, "toObject", protobuf.converter.toObject(type));
+
+        push("");
+        pushComment([
+            "Converts this " + type.name + " to JSON.",
+            "@function toJSON",
+            "@memberof " + exportName(type),
+            "@instance",
+            "@returns {Object.<string,*>} JSON object"
+        ]);
+        push(escapeName(type.name) + ".prototype.toJSON = function toJSON() {");
+        ++indent;
+            push("return this.constructor.toObject(this, $protobuf.util.toJSONOptions);");
+        --indent;
+        push("};");
+    }
+
+    if (config.typeurl) {
+        push("");
+        pushComment([
+            "Gets the default type url for " + type.name,
+            "@function getTypeUrl",
+            "@memberof " + exportName(type),
+            "@static",
+            "@param {string} [typeUrlPrefix] your custom typeUrlPrefix(default \"type.googleapis.com\")",
+            "@returns {string} The default type url"
+        ]);
+        push(escapeName(type.name) + ".getTypeUrl = function getTypeUrl(typeUrlPrefix) {");
+        ++indent;
+            push("if (typeUrlPrefix === undefined) {");
+            ++indent;
+                push("typeUrlPrefix = \"type.googleapis.com\";");
+            --indent;
+            push("}");
+            push("return typeUrlPrefix + \"/" + exportName(type) + "\";");
+        --indent;
+        push("};");
+    }
+}
+
+function buildService(ref, service) {
+
+    push("");
+    pushComment([
+        "Constructs a new " + service.name + " service.",
+        service.parent instanceof protobuf.Root ? "@exports " + escapeName(service.name) : "@memberof " + exportName(service.parent),
+        "@classdesc " + (service.comment || "Represents " + aOrAn(service.name)),
+        "@extends $protobuf.rpc.Service",
+        "@constructor",
+        "@param {$protobuf.RPCImpl} rpcImpl RPC implementation",
+        "@param {boolean} [requestDelimited=false] Whether requests are length-delimited",
+        "@param {boolean} [responseDelimited=false] Whether responses are length-delimited"
+    ]);
+    push("function " + escapeName(service.name) + "(rpcImpl, requestDelimited, responseDelimited) {");
+    ++indent;
+    push("$protobuf.rpc.Service.call(this, rpcImpl, requestDelimited, responseDelimited);");
+    --indent;
+    push("}");
+    push("");
+    push("(" + escapeName(service.name) + ".prototype = Object.create($protobuf.rpc.Service.prototype)).constructor = " + escapeName(service.name) + ";");
+
+    if (config.create) {
+        push("");
+        pushComment([
+            "Creates new " + service.name + " service using the specified rpc implementation.",
+            "@function create",
+            "@memberof " + exportName(service),
+            "@static",
+            "@param {$protobuf.RPCImpl} rpcImpl RPC implementation",
+            "@param {boolean} [requestDelimited=false] Whether requests are length-delimited",
+            "@param {boolean} [responseDelimited=false] Whether responses are length-delimited",
+            "@returns {" + escapeName(service.name) + "} RPC service. Useful where requests and/or responses are streamed."
+        ]);
+        push(escapeName(service.name) + ".create = function create(rpcImpl, requestDelimited, responseDelimited) {");
+            ++indent;
+            push("return new this(rpcImpl, requestDelimited, responseDelimited);");
+            --indent;
+        push("};");
+    }
+
+    service.methodsArray.forEach(function(method) {
+        method.resolve();
+        var lcName = protobuf.util.lcFirst(method.name),
+            cbName = escapeName(method.name + "Callback");
+        push("");
+        pushComment([
+            "Callback as used by {@link " + exportName(service) + "#" + escapeName(lcName) + "}.",
+            // This is a more specialized version of protobuf.rpc.ServiceCallback
+            "@memberof " + exportName(service),
+            "@typedef " + cbName,
+            "@type {function}",
+            "@param {Error|null} error Error, if any",
+            "@param {" + exportName(method.resolvedResponseType) + "} [response] " + method.resolvedResponseType.name
+        ]);
+        push("");
+        pushComment([
+            method.comment || "Calls " + method.name + ".",
+            "@function " + lcName,
+            "@memberof " + exportName(service),
+            "@instance",
+            "@param {" + exportName(method.resolvedRequestType, !config.forceMessage) + "} request " + method.resolvedRequestType.name + " message or plain object",
+            "@param {" + exportName(service) + "." + cbName + "} callback Node-style callback called with the error, if any, and " + method.resolvedResponseType.name,
+            "@returns {undefined}",
+            "@variation 1"
+        ]);
+        push("Object.defineProperty(" + escapeName(service.name) + ".prototype" + util.safeProp(lcName) + " = function " + escapeName(lcName) + "(request, callback) {");
+            ++indent;
+            push("return this.rpcCall(" + escapeName(lcName) + ", $root." + exportName(method.resolvedRequestType) + ", $root." + exportName(method.resolvedResponseType) + ", request, callback);");
+            --indent;
+        push("}, \"name\", { value: " + JSON.stringify(method.name) + " });");
+        if (config.comments)
+            push("");
+        pushComment([
+            method.comment || "Calls " + method.name + ".",
+            "@function " + lcName,
+            "@memberof " + exportName(service),
+            "@instance",
+            "@param {" + exportName(method.resolvedRequestType, !config.forceMessage) + "} request " + method.resolvedRequestType.name + " message or plain object",
+            "@returns {Promise<" + exportName(method.resolvedResponseType) + ">} Promise",
+            "@variation 2"
+        ]);
+    });
+}
+
+function buildEnum(ref, enm) {
+
+    push("");
+    var comment = [
+        enm.comment || enm.name + " enum.",
+        enm.parent instanceof protobuf.Root ? "@exports " + escapeName(enm.name) : "@name " + exportName(enm),
+        config.forceEnumString ? "@enum {string}" : "@enum {number}",
+    ];
+    Object.keys(enm.values).forEach(function(key) {
+        var val = config.forceEnumString ? key : enm.values[key];
+        comment.push((config.forceEnumString ? "@property {string} " : "@property {number} ") + key + "=" + val + " " + (enm.comments[key] || key + " value"));
+    });
+    pushComment(comment);
+    if (!ref && config.es6)
+        push("export const " + escapeName(enm.name) + " = " + escapeName(ref) + "." + escapeName(enm.name) + " = (() => {");
+    else
+        push(escapeName(ref) + "." + escapeName(enm.name) + " = (function() {");
+    ++indent;
+        push((config.es6 ? "const" : "var") + " valuesById = {}, values = Object.create(valuesById);");
+        var aliased = [];
+        Object.keys(enm.values).forEach(function(key) {
+            var valueId = enm.values[key];
+            var val = config.forceEnumString ? JSON.stringify(key) : valueId;
+            if (aliased.indexOf(valueId) > -1)
+                push("values[" + JSON.stringify(key) + "] = " + val + ";");
+            else {
+                push("values[valuesById[" + valueId + "] = " + JSON.stringify(key) + "] = " + val + ";");
+                aliased.push(valueId);
+            }
+        });
+        push("return values;");
+    --indent;
+    push("})();");
+}
diff --git a/cli/util.js b/cli/util.js
new file mode 100644
index 0000000..f87f50e
--- /dev/null
+++ b/cli/util.js
@@ -0,0 +1,243 @@
+"use strict";
+var fs       = require("fs"),
+    path     = require("path"),
+    protobuf = require("protobufjs");
+
+function basenameCompare(a, b) {
+    var aa = String(a).replace(/\.\w+$/, "").split(/(-?\d*\.?\d+)/g),
+        bb = String(b).replace(/\.\w+$/, "").split(/(-?\d*\.?\d+)/g);
+    for (var i = 0, k = Math.min(aa.length, bb.length); i < k; i++) {
+        var x = parseFloat(aa[i]) || aa[i].toLowerCase(),
+            y = parseFloat(bb[i]) || bb[i].toLowerCase();
+        if (x < y)
+            return -1;
+        if (x > y)
+            return 1;
+    }
+    return a.length < b.length ? -1 : 0;
+}
+
+exports.requireAll = function requireAll(dirname) {
+    dirname   = path.join(__dirname, dirname);
+    var files = fs.readdirSync(dirname).sort(basenameCompare),
+        all = {};
+    files.forEach(function(file) {
+        var basename = path.basename(file, ".js"),
+            extname  = path.extname(file);
+        if (extname === ".js")
+            all[basename] = require(path.join(dirname, file));
+    });
+    return all;
+};
+
+exports.traverse = function traverse(current, fn) {
+    fn(current);
+    if (current.fieldsArray)
+        current.fieldsArray.forEach(function(field) {
+            traverse(field, fn);
+        });
+    if (current.oneofsArray)
+        current.oneofsArray.forEach(function(oneof) {
+            traverse(oneof, fn);
+        });
+    if (current.methodsArray)
+        current.methodsArray.forEach(function(method) {
+            traverse(method, fn);
+        });
+    if (current.nestedArray)
+        current.nestedArray.forEach(function(nested) {
+            traverse(nested, fn);
+        });
+};
+
+exports.traverseResolved = function traverseResolved(current, fn) {
+    fn(current);
+    if (current.resolvedType)
+        traverseResolved(current.resolvedType, fn);
+    if (current.resolvedKeyType)
+        traverseResolved(current.resolvedKeyType, fn);
+    if (current.resolvedRequestType)
+        traverseResolved(current.resolvedRequestType, fn);
+    if (current.resolvedResponseType)
+        traverseResolved(current.resolvedResponseType, fn);
+};
+
+exports.inspect = function inspect(object, indent) {
+    if (!object)
+        return "";
+    var chalk = require("chalk");
+    var sb = [];
+    if (!indent)
+        indent = "";
+    var ind = indent ? indent.substring(0, indent.length - 2) + "└ " : "";
+    sb.push(
+        ind + chalk.bold(object.toString()) + (object.visible ? " (visible)" : ""),
+        indent + chalk.gray("parent: ") + object.parent
+    );
+    if (object instanceof protobuf.Field) {
+        if (object.extend !== undefined)
+            sb.push(indent + chalk.gray("extend: ") + object.extend);
+        if (object.partOf)
+            sb.push(indent + chalk.gray("oneof : ") + object.oneof);
+    }
+    sb.push("");
+    if (object.fieldsArray)
+        object.fieldsArray.forEach(function(field) {
+            sb.push(inspect(field, indent + "  "));
+        });
+    if (object.oneofsArray)
+        object.oneofsArray.forEach(function(oneof) {
+            sb.push(inspect(oneof, indent + "  "));
+        });
+    if (object.methodsArray)
+        object.methodsArray.forEach(function(service) {
+            sb.push(inspect(service, indent + "  "));
+        });
+    if (object.nestedArray)
+        object.nestedArray.forEach(function(nested) {
+            sb.push(inspect(nested, indent + "  "));
+        });
+    return sb.join("\n");
+};
+
+exports.wrap = function(OUTPUT, options) {
+    var name = options.wrap || "default";
+    var wrap;
+    try {
+        // try built-in wrappers first
+        wrap = fs.readFileSync(path.join(__dirname, "wrappers", name + ".js")).toString("utf8");
+    } catch (e) {
+        // otherwise fetch the custom one
+        wrap = fs.readFileSync(path.resolve(process.cwd(), name)).toString("utf8");
+    }
+    wrap = wrap.replace(/\$DEPENDENCY/g, JSON.stringify(options.dependency || "protobufjs"));
+    wrap = wrap.replace(/( *)\$OUTPUT;/, function($0, $1) {
+        return $1.length ? OUTPUT.replace(/^/mg, $1) : OUTPUT;
+    });
+    if (options.lint !== "")
+        wrap = "/*" + options.lint + "*/\n" + wrap;
+    return wrap.replace(/\r?\n/g, "\n");
+};
+
+exports.pad = function(str, len, l) {
+    while (str.length < len)
+        str = l ? str + " " : " " + str;
+    return str;
+};
+
+
+/**
+ * DFS to get all message dependencies, cache in filterMap.
+ * @param {Root} root  The protobuf root instance
+ * @param {Message} message  The message need to process.
+ * @param {Map} filterMap  The result of message you need and their dependencies.
+ * @param {Map} flatMap  A flag to record whether the message was searched.
+ * @returns {undefined}  Does not return a value
+ */
+function dfsFilterMessageDependencies(root, message, filterMap, flatMap) {
+    if (message instanceof protobuf.Type) {
+        if (flatMap.get(`${message.fullName}`)) return;
+        flatMap.set(`${message.fullName}`, true);
+        for (var field of message.fieldsArray) {
+            if (field.resolvedType) {
+                // a nested message
+                if (field.resolvedType.parent.name === message.name) {
+                    var nestedMessage = message.nested[field.resolvedType.name];
+                    dfsFilterMessageDependencies(root, nestedMessage, filterMap, flatMap);
+                    continue;
+                }
+                var packageName = field.resolvedType.parent.name;
+                var typeName = field.resolvedType.name;
+                var fullName = packageName ? `${packageName}.${typeName}` : typeName;
+                doFilterMessage(root, { messageNames: [fullName] }, filterMap, flatMap, packageName);
+            }
+        }
+    }
+}
+
+/**
+ * DFS to get all message you need and their dependencies, cache in filterMap.
+ * @param {Root} root  The protobuf root instance
+ * @param {object} needMessageConfig  Need message config:
+ * @param {string[]} needMessageConfig.messageNames  The message names array in the root namespace you need to gen. example: [msg1, msg2]
+ * @param {Map} filterMap The result of message you need and their dependencies.
+ * @param {Map} flatMap A flag to record whether the message was searched.
+ * @param {string} currentPackageName  Current package name
+ * @returns {undefined}  Does not return a value
+ */
+function doFilterMessage(root, needMessageConfig, filterMap, flatMap, currentPackageName) {
+    var needMessageNames = needMessageConfig.messageNames;
+
+    for (var messageFullName of needMessageNames) {
+        var nameSplit = messageFullName.split(".");
+        var packageName = "";
+        var messageName = "";
+        if (nameSplit.length > 1) {
+            packageName = nameSplit[0];
+            messageName = nameSplit[1];
+        } else {
+            messageName = nameSplit[0];
+        }
+
+        // in Namespace
+        if (packageName) {
+            var ns = root.nested[packageName];
+            if (!ns || !(ns instanceof protobuf.Namespace)) {
+                throw new Error(`package not foud ${currentPackageName}.${messageName}`);
+            }
+
+            doFilterMessage(root, { messageNames: [messageName] }, filterMap, flatMap, packageName);
+        } else {
+            var message = root.nested[messageName];
+
+            if (currentPackageName) {
+                message = root.nested[currentPackageName].nested[messageName];
+            }
+
+            if (!message) {
+                throw new Error(`message not foud ${currentPackageName}.${messageName}`);
+            }
+
+            var set = filterMap.get(currentPackageName);
+            if (!filterMap.has(currentPackageName)) {
+                set = new Set();
+                filterMap.set(currentPackageName, set);
+            }
+
+            set.add(messageName);
+
+            // dfs to find all dependencies
+            dfsFilterMessageDependencies(root, message, filterMap, flatMap, currentPackageName);
+        }
+    }
+}
+
+/**
+ * filter the message you need and their dependencies, all others will be delete from root.
+ * @param {Root} root  Root the protobuf root instance
+ * @param {object} needMessageConfig  Need message config:
+ * @param {string[]} needMessageConfig.messageNames  Tthe message names array in the root namespace you need to gen. example: [msg1, msg2]
+ * @returns {boolean} True if a message should present in the generated files
+ */
+exports.filterMessage = function (root, needMessageConfig) {
+    var filterMap = new Map();
+    var flatMap = new Map();
+    doFilterMessage(root, needMessageConfig, filterMap, flatMap, "");
+    root._nestedArray = root._nestedArray.filter(ns => {
+        if (ns instanceof protobuf.Type || ns instanceof protobuf.Enum) {
+            return filterMap.get("").has(ns.name);
+        } else if (ns instanceof protobuf.Namespace) {
+            if (!filterMap.has(ns.name)) {
+                return false;
+            }
+            ns._nestedArray = ns._nestedArray.filter(nns => {
+                const nnsSet = filterMap.get(ns.name);
+                return nnsSet.has(nns.name);
+            });
+
+            return true;
+        }
+        return true;
+    });
+};
+
diff --git a/cli/wrappers/amd.js b/cli/wrappers/amd.js
new file mode 100644
index 0000000..c43dd73
--- /dev/null
+++ b/cli/wrappers/amd.js
@@ -0,0 +1,7 @@
+define([$DEPENDENCY], function($protobuf) {
+    "use strict";
+
+    $OUTPUT;
+
+    return $root;
+});
diff --git a/cli/wrappers/closure.js b/cli/wrappers/closure.js
new file mode 100644
index 0000000..c94327c
--- /dev/null
+++ b/cli/wrappers/closure.js
@@ -0,0 +1,7 @@
+(function($protobuf) {
+    "use strict";
+
+    $OUTPUT;
+
+    return $root;
+})(protobuf);
diff --git a/cli/wrappers/commonjs.js b/cli/wrappers/commonjs.js
new file mode 100644
index 0000000..6dc9168
--- /dev/null
+++ b/cli/wrappers/commonjs.js
@@ -0,0 +1,7 @@
+"use strict";
+
+var $protobuf = require($DEPENDENCY);
+
+$OUTPUT;
+
+module.exports = $root;
diff --git a/cli/wrappers/default.js b/cli/wrappers/default.js
new file mode 100644
index 0000000..34b29ec
--- /dev/null
+++ b/cli/wrappers/default.js
@@ -0,0 +1,15 @@
+(function(global, factory) { /* global define, require, module */
+
+    /* AMD */ if (typeof define === 'function' && define.amd)
+        define([$DEPENDENCY], factory);
+
+    /* CommonJS */ else if (typeof require === 'function' && typeof module === 'object' && module && module.exports)
+        module.exports = factory(require($DEPENDENCY));
+
+})(this, function($protobuf) {
+    "use strict";
+
+    $OUTPUT;
+
+    return $root;
+});
diff --git a/cli/wrappers/es6.js b/cli/wrappers/es6.js
new file mode 100644
index 0000000..5bdc43c
--- /dev/null
+++ b/cli/wrappers/es6.js
@@ -0,0 +1,5 @@
+import * as $protobuf from $DEPENDENCY;
+
+$OUTPUT;
+
+export { $root as default };
diff --git a/config/eslint.json b/config/eslint.json
new file mode 100644
index 0000000..b87a6eb
--- /dev/null
+++ b/config/eslint.json
@@ -0,0 +1,127 @@
+{
+    "env": {
+        "node": true,
+        "browser": true
+    },
+    "globals": {
+        "ArrayBuffer": true,
+        "Uint8Array": true,
+        "Float32Array": true,
+        "Float64Array": true,
+        "define": true,
+        "global": true,
+        "XMLHttpRequest": true,
+        "Promise": true
+    },
+    "parserOptions": {
+        "ecmaVersion": 6
+    },
+    "extends": "eslint:recommended",
+    "rules": {
+
+        // Possible errors
+        "no-extra-parens": 1,               // turned on as the daily lecture
+        "no-prototype-builtins": 1,
+        "no-template-curly-in-string": 1,
+        "no-unsafe-negation": 1,
+        "valid-jsdoc": 1,
+
+        // Best practices
+        "accessor-pairs": 1,
+        "array-callback-return": 1,
+        "block-scoped-var": 1,
+        "class-methods-use-this": 1,
+        "complexity": 0,                    // is sometimes necessary
+        "consistent-return": 1,
+        "curly": 0,                         // sometimes more braces than code
+        "default-case": 0,                  // just forces unnecessary code
+        "dot-location": 0,                  // looks nicer for chainables
+        "dot-notation": 0,                  // not compatible with some reserved properties
+        "eqeqeq": [1, "allow-null"],
+        "guard-for-in": 1,
+        "no-alert": 1,
+        "no-caller": 1,
+        "no-cond-assign": 0,
+        "no-div-regex": 1,
+        "no-else-return": 1,
+        "no-empty-function": 1,
+        "no-eval": 1,
+        "no-extend-native": 1,
+        "no-extra-bind": 1,
+        "no-extra-label": 1,
+        "no-floating-decimal": 1,
+        "no-global-assign": 1,
+        "no-implicit-coercion": 1,
+        "no-implicit-globals": 1,
+        "no-implied-eval": 1,
+        "no-invalid-this": 1,
+        "no-iterator": 1,
+        "no-labels": 1,
+        "no-lone-blocks": 1,
+        "no-loop-func": 1,
+        "no-magic-numbers": 0,              // it's actually fun to turn this on here
+        "no-new-func": 1,
+        "no-new-wrappers": 1,
+        "no-new": 1,
+        "no-octal-escape": 1,
+        "no-param-reassign": 0,             // is necessary for varargs functions
+        "no-proto": 1,
+        "no-restricted-properties": 1,
+        "no-sequences": 1,
+        "no-script-url": 1,
+        "no-self-compare": 1,
+        "no-throw-literal": 1,
+        "no-unmodified-loop-condition": 1,
+        "no-unused-expressions": ["error", { "allowShortCircuit": true }],
+        "no-useless-call": 1,
+        "no-useless-concat": 1,
+        "no-useless-escape": 1,
+        "no-useless-return": 1,
+        "no-void": 1,
+        "no-warning-comments": 1,
+        "no-with": 1,
+        "radix": 1,
+        "vars-on-top": 0,                   // makes code harder to read, not faster
+        "wrap-iife": 0,                     // used frequently where polyfilling
+        "yoda": 1,
+
+        // Strict mode
+        "strict": 1,
+
+        // Variables
+        "init-declarations": 0,             // because no-undef-init is on and we actually want undefineds
+        "no-catch-shadow": 0,               // no IE8 support anyway
+        "no-label-var": 1,
+        "no-restricted-globals": 1,
+        "no-return-assign": 0,              // can make sense.
+        "no-shadow-restricted-names": 1,
+        "no-shadow": 0,                     // this is javascript. it has forEach and all that stuff.
+        "no-undef-init": 1,
+        "no-undef": 2,
+        "no-undefined": 0,                  // produces shorter code when testing against this
+        "no-use-before-define": 0,          // can actually be used for a better overview, i.e. with module.exports
+        "no-unused-vars": 1,                // a warning is sufficient
+
+        // Node.js and CommonJS
+        "callback-return": 1,
+        "global-require": 0,                // only way to resolve cyclic references
+        "handle-callback-err": 1,
+        "no-mixed-requires": 1,
+        "no-new-require": 1,
+        "no-path-concat": 1,
+        "no-process-env": 1,
+        "no-process-exit": 1,
+        "no-restricted-modules": 1,
+        "no-sync": 0,                       // for loadSync
+
+        // Stylistic Issues
+        "semi": 1,                          // maybe next time
+        "no-extra-semi": 1,
+        "quotes": 1,                        // useful for gzip
+        "no-trailing-spaces": 1,
+        "no-unneeded-ternary": 1,
+        "unicode-bom": [2, "never"]
+
+        // ECMAScript 6                     // maybe next time
+    }
+}
diff --git a/config/jsdoc.json b/config/jsdoc.json
new file mode 100644
index 0000000..7b7d005
--- /dev/null
+++ b/config/jsdoc.json
@@ -0,0 +1,50 @@
+{
+    "tags": {
+        "allowUnknownTags": true
+    },
+    "source": {
+        "include": [
+            "./src/",
+            "./lib/aspromise/index.js",
+            "./lib/base64/index.js",
+            "./lib/codegen/index.js",
+            "./lib/eventemitter/index.js",
+            "./lib/fetch/index.js",
+            "./lib/inquire/index.js",
+            "./lib/path/index.js",
+            "./lib/pool/index.js",
+            "./lib/utf8/index.js"
+        ],
+        "exclude": [],
+        "includePattern": ".+\\.js(doc)?$",
+        "excludePattern": "(^|\\/|\\\\)_"
+    },
+    "plugins": [
+        "./node_modules/jsdoc/plugins/markdown"
+    ],
+    "templates": {
+        "cleverLinks"   : false,
+        "monospaceLinks": false,
+        "default"       : {
+            "outputSourceFiles" : false
+        },
+        "applicationName": "protobuf.js",
+        "googleAnalytics": "UA-40277577-3",
+        "linenums"      : true
+    },
+    "markdown"  : {
+        "parser"        : "gfm",
+        "hardwrap"      : true,
+        "idInHeadings"  : true
+    },
+    "opts": {
+        "encoding"      : "utf8",
+        "recurse"       : true,
+        "private"       : false,
+        "lenient"       : false,
+        "destination"   : "./docs",
+        "template"      : "./node_modules/jaguarjs-jsdoc",
+        "sourceRoot"    : "https://github.com/dcodeIO/protobuf.js/blob/master/src/",
+        "repo"          : "https://github.com/dcodeIO/protobuf.js"
+    }
+}
\ No newline at end of file
diff --git a/config/tslint.json b/config/tslint.json
new file mode 100644
index 0000000..ea3cff1
--- /dev/null
+++ b/config/tslint.json
@@ -0,0 +1,29 @@
+{
+    "extends": "tslint:recommended",
+    "rules": {
+        "array-type": [ true, "array" ],
+        "no-namespace": false,
+        "interface-name": [ false ],
+        "interface-over-type-literal": true,
+        "no-empty-interface": false,
+        "max-line-length": [ false ],
+        "trailing-comma": [ true, "never" ],
+        "variable-name": [ false ],
+        "max-classes-per-file": [ false ],
+        "member-ordering": [ false ],
+        "object-literal-sort-keys": false,
+        "no-string-literal": false,
+        "prefer-const": false,
+        "adjacent-overload-signatures": false,
+        "no-shadowed-variable": false,
+        "ban-types": [
+            true,
+            ["Object", "Avoid using the `Object` type. Did you mean `object`?"],
+            // ["Function", "Avoid using the `Function` type. Prefer a specific function type, like `() => void`."],
+            ["Boolean", "Avoid using the `Boolean` type. Did you mean `boolean`?"],
+            ["Number", "Avoid using the `Number` type. Did you mean `number`?"],
+            ["String", "Avoid using the `String` type. Did you mean `string`?"],
+            ["Symbol", "Avoid using the `Symbol` type. Did you mean `symbol`?"]
+        ]
+    }
+}
\ No newline at end of file
diff --git a/examples/custom-get-set.js b/examples/custom-get-set.js
new file mode 100644
index 0000000..73833ab
--- /dev/null
+++ b/examples/custom-get-set.js
@@ -0,0 +1,50 @@
+// this example demonstrates a way to keep field casing (as defined within .proto files)
+// while still having virtual getters and setters for the camel cased counterparts.
+
+/*eslint-disable strict, no-console*/
+var protobuf = require("..");
+
+var proto = "syntax=\"proto3\";\
+message MyMessage {\
+  string some_field = 1;\
+}";
+
+var root = protobuf.parse(proto, { keepCase: true }).root; // or use Root#load
+
+// converts a string from underscore notation to camel case
+function toCamelCase(str) {
+    return str.substring(0,1) + str.substring(1).replace(/_([a-z])(?=[a-z]|$)/g, function($0, $1) { return $1.toUpperCase(); });
+}
+
+// adds a virtual alias property
+function addAliasProperty(type, name, aliasName) {
+    if (aliasName !== name)
+        Object.defineProperty(type.ctor.prototype, aliasName, {
+            get: function() { return this[name]; },
+            set: function(value) { this[name] = value; }
+        });
+}
+
+// this function adds alternative getters and setters for the camel cased counterparts
+// to the runtime message's prototype (i.e. without having to register a custom class):
+function addVirtualCamelcaseFields(type) {
+    type.fieldsArray.forEach(function(field) {
+        addAliasProperty(type, field.name, toCamelCase(field.name));
+    });
+    type.oneofsArray.forEach(function(oneof) {
+        addAliasProperty(type, oneof.name, toCamelCase(oneof.name));
+    });
+    return type;
+}
+
+var MyMessage = addVirtualCamelcaseFields(root.lookup("MyMessage"));
+
+var myMessage = MyMessage.create({
+    some_field /* or someField */: "hello world"
+});
+
+console.log(
+    "someField:", myMessage.someField,
+    "\nsome_field:", myMessage.some_field,
+    "\nJSON:", JSON.stringify(myMessage)
+);
diff --git a/examples/js-decorators.js b/examples/js-decorators.js
new file mode 100644
index 0000000..0d3cac8
--- /dev/null
+++ b/examples/js-decorators.js
@@ -0,0 +1,42 @@
+// This example shows how decorators can be used with plain JavaScript. It's otherwise identical to
+// the README example.
+
+/*eslint-disable strict, no-console*/
+var protobuf = require("../light");
+
+var Type  = protobuf.Type,
+    Field = protobuf.Field,
+    OneOf = protobuf.OneOf;
+
+function AwesomeSubMessage(properties) {
+    protobuf.Message.call(this, properties);
+}
+
+(AwesomeSubMessage.prototype = Object.create(protobuf.Message)).constructor = AwesomeSubMessage;
+
+Field.d(1, "string", "optional", "awesome default string")(AwesomeSubMessage.prototype, "awesomeField");
+
+var AwesomeEnum = {
+    ONE: 1,
+    TWO: 2
+};
+
+Type.d("SuperAwesomeMessage")(AwesomeMessage);
+function AwesomeMessage(properties) {
+    protobuf.Message.call(this, properties);
+}
+
+(AwesomeMessage.prototype = Object.create(protobuf.Message)).constructor = AwesomeMessage;
+
+Field.d(1, "string", "optional", "awesome default string")(AwesomeMessage.prototype, "awesomeField");
+Field.d(2, AwesomeSubMessage)(AwesomeMessage.prototype, "awesomeSubMessage");
+Field.d(3, AwesomeEnum, "optional", AwesomeEnum.ONE)(AwesomeMessage.prototype, "awesomeEnum");
+OneOf.d("awesomeSubMessage", "awesomeEnum")(AwesomeMessage.prototype, "which");
+
+// example code
+var message = new AwesomeMessage({ awesomeField: "hello" });
+var buffer  = AwesomeMessage.encode(message).finish();
+var decoded = AwesomeMessage.decode(buffer);
+
+console.log(decoded);
+console.log("internal name: " + AwesomeMessage.$type.name);
diff --git a/examples/reader-writer.js b/examples/reader-writer.js
new file mode 100644
index 0000000..7361b79
--- /dev/null
+++ b/examples/reader-writer.js
@@ -0,0 +1,25 @@
+// this example demonstrates how to use the reader/writer interface directly to read and write the
+// protobuf wire format.
+
+/*eslint-disable strict, no-console*/
+var protobuf = require("../runtime"); // require("protobufjs/runtime");
+
+// writing
+var buffer = protobuf.Writer.create()
+    .uint32((1 << 3 | 2) >>> 0) // id 1, wireType 2
+    .string("hello world!")
+    .finish();
+
+// reading
+var reader = protobuf.Reader.create(buffer);
+while (reader.pos < reader.len) {
+    var tag = reader.uint32();
+    switch (/*id*/ tag >>> 3) {
+        case 1:
+            console.log(reader.string());
+            break;
+        default:
+            reader.skipType(/*wireType*/ tag & 7);
+            break;
+    }
+}
diff --git a/examples/streaming-rpc.js b/examples/streaming-rpc.js
new file mode 100644
index 0000000..f06c08e
--- /dev/null
+++ b/examples/streaming-rpc.js
@@ -0,0 +1,114 @@
+// this example demonstrates how to consume a streaming rpc service.
+
+/*eslint-disable strict, no-console*/
+var protobuf = require("..");
+
+// Load a definition with services:
+
+var root = protobuf.Root.fromJSON({
+    nested: {
+        Greeter: {
+            methods: {
+                "SayHello": {
+                    requestType: "Hello",
+                    requestStream: true,
+                    responseType: "World",
+                    responseStream: true
+                }
+            }
+        },
+        Hello: {
+            fields: {
+                name: {
+                    type: "string",
+                    id: 1
+                }
+            }
+        },
+        World: {
+            fields: {
+                message: {
+                    type: "string",
+                    id: 1
+                }
+            }
+        }
+    }
+});
+
+// Get its types:
+
+var Greeter = root.lookup("Greeter"),
+    Hello   = root.lookup("Hello"),
+    World   = root.lookup("World");
+
+// Provide a stream-aware RPC implementation:
+
+var greeter = Greeter.create(/* rpcImpl */ (function() { // API documentation: Service#create
+    var ended = false;
+    return function myRPCImpl(method, requestData, callback) {
+        if (ended)
+            return;
+        if (!requestData) {
+            ended = true;
+            return;
+        }
+        // in a real-world scenario, the client would now send requestData to a server using some
+        // sort of transport layer (i.e. http), wait for responseData and call the callback.
+        performRequestOverTransportChannel(requestData, function(responseData) {
+            callback(null, responseData);
+        });
+    };
+})(), /* requestDelimited? */ true, /* responseDelimited? */ true);
+
+// examplary server-side code for the sake of this example
+function performRequestOverTransportChannel(requestData, callback) {
+    setTimeout(/* simulated delay */function() {
+        // 1. server decodes the request
+        var request = Hello.decodeDelimited(requestData);
+        // 2. server handles the request and creates a response
+        var response = { message: "Hello " + request.name };
+        setTimeout(/* simulated delay */function() {
+            // 3. server encodes and sends the response
+            callback(World.encodeDelimited(response).finish());
+        }, Math.random() * 250);
+    }, Math.random() * 250);
+}
+
+// Listen for events:
+
+greeter.on("data", function(response, method) {
+    console.log("data in " + method.name + ":", response.message);
+});
+
+greeter.on("end", function() {
+    console.log("end");
+});
+
+greeter.on("error", function(err, method) {
+    console.log("error in " + method.name + ":", err);
+});
+
+// Call methods:
+
+greeter.sayHello({ name: "one" });
+greeter.sayHello(Hello.create({ name: "two" })); // or use runtime messages
+
+// Listen to and emit your own events if you like:
+
+greeter.on("status", function(code, text) {
+    console.log("custom status:", code, text);
+});
+
+greeter.emit("status", 200, "OK");
+
+// And, if applicable, end the service when you are done:
+
+setTimeout(function() {
+    greeter.end();
+    // ^ Signals rpcImpl that the service has been ended client-side by calling it with a null buffer.
+    //   Likewise, rpcImpl can also end the stream by calling its callback with an explicit null buffer.
+    greeter.sayHello({ name: "three" }, function(err) {
+        console.error("this should fail: " + err.message);
+    });
+}, 501);
diff --git a/examples/traverse-types.js b/examples/traverse-types.js
new file mode 100644
index 0000000..567dfff
--- /dev/null
+++ b/examples/traverse-types.js
@@ -0,0 +1,42 @@
+// this example demonstrates how to traverse through a root instance by calling a custom function
+// for each message type within.
+
+/*eslint-disable strict, no-console*/
+var protobuf = require(".."); // require("protobufjs");
+
+// traverse-types.proto
+var proto = "syntax=\"proto3\";\
+package example;\
+message Foo {\
+  string a = 1;\
+}\
+message Bar {\
+  uint32 b = 1;\
+  \
+  message Inner {\
+    bytes c = 1;\
+  }\
+}";
+
+// the following is loading a string.
+// in a real application, it'd be more like protobuf.load("traverse-types.proto", ...)
+protobuf.parse.filename = "traverse-types.proto";
+var root = protobuf.parse(proto).root;
+
+function traverseTypes(current, fn) {
+    if (current instanceof protobuf.Type) // and/or protobuf.Enum, protobuf.Service etc.
+        fn(current);
+    if (current.nestedArray)
+        current.nestedArray.forEach(function(nested) {
+            traverseTypes(nested, fn);
+        });
+}
+
+traverseTypes(root, function(type) {
+    console.log(
+        type.constructor.className + " " + type.name
+        + "\n  fully qualified name: " + type.fullName
+        + "\n  defined in: " + type.filename
+        + "\n  parent: " + type.parent + " in " + type.parent.filename
+    );
+});
diff --git a/ext/debug/README.md b/ext/debug/README.md
new file mode 100644
index 0000000..a48517e
--- /dev/null
+++ b/ext/debug/README.md
@@ -0,0 +1,4 @@
+protobufjs/ext/debug
+=========================
+
+Experimental debugging extension.
diff --git a/ext/debug/index.js b/ext/debug/index.js
new file mode 100644
index 0000000..2b79766
--- /dev/null
+++ b/ext/debug/index.js
@@ -0,0 +1,71 @@
+"use strict";
+var protobuf = require("../..");
+
+/**
+ * Debugging utility functions. Only present in debug builds.
+ * @namespace
+ */
+var debug = protobuf.debug = module.exports = {};
+
+var codegen = protobuf.util.codegen;
+
+var debugFnRe = /function ([^(]+)\(([^)]*)\) {/g;
+
+// Counts number of calls to any generated function
+function codegen_debug() {
+    codegen_debug.supported = codegen.supported;
+    codegen_debug.verbose = codegen.verbose;
+    var gen = codegen.apply(null, Array.prototype.slice.call(arguments));
+    gen.str = (function(str) { return function str_debug() {
+        return str.apply(null, Array.prototype.slice.call(arguments)).replace(debugFnRe, "function $1($2) {\n\t$1.calls=($1.calls|0)+1");
+    };})(gen.str);
+    return gen;
+}
+
+/**
+ * Returns a list of unused types within the specified root.
+ * @param {NamespaceBase} ns Namespace to search
+ * @returns {Type[]} Unused types
+ */
+debug.unusedTypes = function unusedTypes(ns) {
+
+    /* istanbul ignore if */
+    if (!(ns instanceof protobuf.Namespace))
+        throw TypeError("ns must be a Namespace");
+
+    /* istanbul ignore if */
+    if (!ns.nested)
+        return [];
+
+    var unused = [];
+    for (var names = Object.keys(ns.nested), i = 0; i < names.length; ++i) {
+        var nested = ns.nested[names[i]];
+        if (nested instanceof protobuf.Type) {
+            var calls = (nested.encode.calls|0)
+                      + (nested.decode.calls|0)
+                      + (nested.verify.calls|0)
+                      + (nested.toObject.calls|0)
+                      + (nested.fromObject.calls|0);
+            if (!calls)
+                unused.push(nested);
+        } else if (nested instanceof protobuf.Namespace)
+            Array.prototype.push.apply(unused, unusedTypes(nested));
+    }
+    return unused;
+};
+
+/**
+ * Enables debugging extensions.
+ * @returns {undefined}
+ */
+debug.enable = function enable() {
+    protobuf.util.codegen = codegen_debug;
+};
+
+/**
+ * Disables debugging extensions.
+ * @returns {undefined}
+ */
+debug.disable = function disable() {
+    protobuf.util.codegen = codegen;
+};
diff --git a/ext/descriptor/README.md b/ext/descriptor/README.md
new file mode 100644
index 0000000..3bc4c6c
--- /dev/null
+++ b/ext/descriptor/README.md
@@ -0,0 +1,72 @@
+protobufjs/ext/descriptor
+=========================
+
+Experimental extension for interoperability with [descriptor.proto](https://github.com/google/protobuf/blob/master/src/google/protobuf/descriptor.proto) types.
+
+Usage
+-----
+
+```js
+var protobuf   = require("protobufjs"), // requires the full library
+    descriptor = require("protobufjs/ext/descriptor");
+
+var root = ...;
+
+// convert any existing root instance to the corresponding descriptor type
+var descriptorMsg = root.toDescriptor("proto2");
+// ^ returns a FileDescriptorSet message, see table below
+
+// encode to a descriptor buffer
+var buffer = descriptor.FileDescriptorSet.encode(descriptorMsg).finish();
+
+// decode from a descriptor buffer
+var decodedDescriptor = descriptor.FileDescriptorSet.decode(buffer);
+
+// convert any existing descriptor to a root instance
+root = protobuf.Root.fromDescriptor(decodedDescriptor);
+// ^ expects a FileDescriptorSet message or buffer, see table below
+
+// and start all over again
+```
+
+API
+---
+
+The extension adds `.fromDescriptor(descriptor[, syntax])` and `#toDescriptor([syntax])` methods to reflection objects and exports the `.google.protobuf` namespace of the internally used `Root` instance containing the following types present in descriptor.proto:
+
+| Descriptor type               | protobuf.js type | Remarks
+|-------------------------------|------------------|---------
+| **FileDescriptorSet**         | Root             |
+| FileDescriptorProto           |                  | dependencies are not supported
+| FileOptions                   |                  |
+| FileOptionsOptimizeMode       |                  |
+| SourceCodeInfo                |                  | not supported
+| SourceCodeInfoLocation        |                  |
+| GeneratedCodeInfo             |                  | not supported
+| GeneratedCodeInfoAnnotation   |                  |
+| **DescriptorProto**           | Type             |
+| MessageOptions                |                  |
+| DescriptorProtoExtensionRange |                  |
+| DescriptorProtoReservedRange  |                  |
+| **FieldDescriptorProto**      | Field            |
+| FieldDescriptorProtoLabel     |                  |
+| FieldDescriptorProtoType      |                  |
+| FieldOptions                  |                  |
+| FieldOptionsCType             |                  |
+| FieldOptionsJSType            |                  |
+| **OneofDescriptorProto**      | OneOf            |
+| OneofOptions                  |                  |
+| **EnumDescriptorProto**       | Enum             |
+| EnumOptions                   |                  |
+| EnumValueDescriptorProto      |                  |
+| EnumValueOptions              |                  | not supported
+| **ServiceDescriptorProto**    | Service          |
+| ServiceOptions                |                  |
+| **MethodDescriptorProto**     | Method           |
+| MethodOptions                 |                  |
+| UninterpretedOption           |                  | not supported
+| UninterpretedOptionNamePart   |                  |
+
+Note that not all features of descriptor.proto translate perfectly to a protobuf.js root instance. A root instance has only limited knowlege of packages or individual files for example, which is then compensated by guessing and generating fictional file names.
+
+When using TypeScript, the respective interface types can be used to reference specific message instances (i.e. `protobuf.Message<IDescriptorProto>`).
diff --git a/ext/descriptor/index.d.ts b/ext/descriptor/index.d.ts
new file mode 100644
index 0000000..1df2efc
--- /dev/null
+++ b/ext/descriptor/index.d.ts
@@ -0,0 +1,191 @@
+import * as $protobuf from "../..";
+export const FileDescriptorSet: $protobuf.Type;
+
+export const FileDescriptorProto: $protobuf.Type;
+
+export const DescriptorProto: $protobuf.Type & {
+    ExtensionRange: $protobuf.Type,
+    ReservedRange: $protobuf.Type
+};
+
+export const FieldDescriptorProto: $protobuf.Type & {
+    Label: $protobuf.Enum,
+    Type: $protobuf.Enum
+};
+
+export const OneofDescriptorProto: $protobuf.Type;
+
+export const EnumDescriptorProto: $protobuf.Type;
+
+export const ServiceDescriptorProto: $protobuf.Type;
+
+export const EnumValueDescriptorProto: $protobuf.Type;
+
+export const MethodDescriptorProto: $protobuf.Type;
+
+export const FileOptions: $protobuf.Type & {
+    OptimizeMode: $protobuf.Enum
+};
+
+export const MessageOptions: $protobuf.Type;
+
+export const FieldOptions: $protobuf.Type & {
+    CType: $protobuf.Enum,
+    JSType: $protobuf.Enum
+};
+
+export const OneofOptions: $protobuf.Type;
+
+export const EnumOptions: $protobuf.Type;
+
+export const EnumValueOptions: $protobuf.Type;
+
+export const ServiceOptions: $protobuf.Type;
+
+export const MethodOptions: $protobuf.Type;
+
+export const UninterpretedOption: $protobuf.Type & {
+    NamePart: $protobuf.Type
+};
+
+export const SourceCodeInfo: $protobuf.Type & {
+    Location: $protobuf.Type
+};
+
+export const GeneratedCodeInfo: $protobuf.Type & {
+    Annotation: $protobuf.Type
+};
+
+export interface IFileDescriptorSet {
+    file: IFileDescriptorProto[];
+}
+
+export interface IFileDescriptorProto {
+    name?: string;
+    package?: string;
+    dependency?: any;
+    publicDependency?: any;
+    weakDependency?: any;
+    messageType?: IDescriptorProto[];
+    enumType?: IEnumDescriptorProto[];
+    service?: IServiceDescriptorProto[];
+    extension?: IFieldDescriptorProto[];
+    options?: IFileOptions;
+    sourceCodeInfo?: any;
+    syntax?: string;
+}
+
+export interface IFileOptions {
+    javaPackage?: string;
+    javaOuterClassname?: string;
+    javaMultipleFiles?: boolean;
+    javaGenerateEqualsAndHash?: boolean;
+    javaStringCheckUtf8?: boolean;
+    optimizeFor?: IFileOptionsOptimizeMode;
+    goPackage?: string;
+    ccGenericServices?: boolean;
+    javaGenericServices?: boolean;
+    pyGenericServices?: boolean;
+    deprecated?: boolean;
+    ccEnableArenas?: boolean;
+    objcClassPrefix?: string;
+    csharpNamespace?: string;
+}
+
+type IFileOptionsOptimizeMode = number;
+
+export interface IDescriptorProto {
+    name?: string;
+    field?: IFieldDescriptorProto[];
+    extension?: IFieldDescriptorProto[];
+    nestedType?: IDescriptorProto[];
+    enumType?: IEnumDescriptorProto[];
+    extensionRange?: IDescriptorProtoExtensionRange[];
+    oneofDecl?: IOneofDescriptorProto[];
+    options?: IMessageOptions;
+    reservedRange?: IDescriptorProtoReservedRange[];
+    reservedName?: string[];
+}
+
+export interface IMessageOptions {
+    mapEntry?: boolean;
+}
+
+export interface IDescriptorProtoExtensionRange {
+    start?: number;
+    end?: number;
+}
+
+export interface IDescriptorProtoReservedRange {
+    start?: number;
+    end?: number;
+}
+
+export interface IFieldDescriptorProto {
+    name?: string;
+    number?: number;
+    label?: IFieldDescriptorProtoLabel;
+    type?: IFieldDescriptorProtoType;
+    typeName?: string;
+    extendee?: string;
+    defaultValue?: string;
+    oneofIndex?: number;
+    jsonName?: any;
+    options?: IFieldOptions;
+}
+
+type IFieldDescriptorProtoLabel = number;
+
+type IFieldDescriptorProtoType = number;
+
+export interface IFieldOptions {
+    packed?: boolean;
+    jstype?: IFieldOptionsJSType;
+}
+
+type IFieldOptionsJSType = number;
+
+export interface IEnumDescriptorProto {
+    name?: string;
+    value?: IEnumValueDescriptorProto[];
+    options?: IEnumOptions;
+}
+
+export interface IEnumValueDescriptorProto {
+    name?: string;
+    number?: number;
+    options?: any;
+}
+
+export interface IEnumOptions {
+    allowAlias?: boolean;
+    deprecated?: boolean;
+}
+
+export interface IOneofDescriptorProto {
+    name?: string;
+    options?: any;
+}
+
+export interface IServiceDescriptorProto {
+    name?: string;
+    method?: IMethodDescriptorProto[];
+    options?: IServiceOptions;
+}
+
+export interface IServiceOptions {
+    deprecated?: boolean;
+}
+
+export interface IMethodDescriptorProto {
+    name?: string;
+    inputType?: string;
+    outputType?: string;
+    options?: IMethodOptions;
+    clientStreaming?: boolean;
+    serverStreaming?: boolean;
+}
+
+export interface IMethodOptions {
+    deprecated?: boolean;
+}
diff --git a/ext/descriptor/index.js b/ext/descriptor/index.js
new file mode 100644
index 0000000..6aafd2a
--- /dev/null
+++ b/ext/descriptor/index.js
@@ -0,0 +1,1052 @@
+"use strict";
+var $protobuf = require("../..");
+module.exports = exports = $protobuf.descriptor = $protobuf.Root.fromJSON(require("../../google/protobuf/descriptor.json")).lookup(".google.protobuf");
+
+var Namespace = $protobuf.Namespace,
+    Root      = $protobuf.Root,
+    Enum      = $protobuf.Enum,
+    Type      = $protobuf.Type,
+    Field     = $protobuf.Field,
+    MapField  = $protobuf.MapField,
+    OneOf     = $protobuf.OneOf,
+    Service   = $protobuf.Service,
+    Method    = $protobuf.Method;
+
+// --- Root ---
+
+/**
+ * Properties of a FileDescriptorSet message.
+ * @interface IFileDescriptorSet
+ * @property {IFileDescriptorProto[]} file Files
+ */
+
+/**
+ * Properties of a FileDescriptorProto message.
+ * @interface IFileDescriptorProto
+ * @property {string} [name] File name
+ * @property {string} [package] Package
+ * @property {*} [dependency] Not supported
+ * @property {*} [publicDependency] Not supported
+ * @property {*} [weakDependency] Not supported
+ * @property {IDescriptorProto[]} [messageType] Nested message types
+ * @property {IEnumDescriptorProto[]} [enumType] Nested enums
+ * @property {IServiceDescriptorProto[]} [service] Nested services
+ * @property {IFieldDescriptorProto[]} [extension] Nested extension fields
+ * @property {IFileOptions} [options] Options
+ * @property {*} [sourceCodeInfo] Not supported
+ * @property {string} [syntax="proto2"] Syntax
+ */
+
+/**
+ * Properties of a FileOptions message.
+ * @interface IFileOptions
+ * @property {string} [javaPackage]
+ * @property {string} [javaOuterClassname]
+ * @property {boolean} [javaMultipleFiles]
+ * @property {boolean} [javaGenerateEqualsAndHash]
+ * @property {boolean} [javaStringCheckUtf8]
+ * @property {IFileOptionsOptimizeMode} [optimizeFor=1]
+ * @property {string} [goPackage]
+ * @property {boolean} [ccGenericServices]
+ * @property {boolean} [javaGenericServices]
+ * @property {boolean} [pyGenericServices]
+ * @property {boolean} [deprecated]
+ * @property {boolean} [ccEnableArenas]
+ * @property {string} [objcClassPrefix]
+ * @property {string} [csharpNamespace]
+ */
+
+/**
+ * Values of he FileOptions.OptimizeMode enum.
+ * @typedef IFileOptionsOptimizeMode
+ * @type {number}
+ * @property {number} SPEED=1
+ * @property {number} CODE_SIZE=2
+ * @property {number} LITE_RUNTIME=3
+ */
+
+/**
+ * Creates a root from a descriptor set.
+ * @param {IFileDescriptorSet|Reader|Uint8Array} descriptor Descriptor
+ * @returns {Root} Root instance
+ */
+Root.fromDescriptor = function fromDescriptor(descriptor) {
+
+    // Decode the descriptor message if specified as a buffer:
+    if (typeof descriptor.length === "number")
+        descriptor = exports.FileDescriptorSet.decode(descriptor);
+
+    var root = new Root();
+
+    if (descriptor.file) {
+        var fileDescriptor,
+            filePackage;
+        for (var j = 0, i; j < descriptor.file.length; ++j) {
+            filePackage = root;
+            if ((fileDescriptor = descriptor.file[j])["package"] && fileDescriptor["package"].length)
+                filePackage = root.define(fileDescriptor["package"]);
+            if (fileDescriptor.name && fileDescriptor.name.length)
+                root.files.push(filePackage.filename = fileDescriptor.name);
+            if (fileDescriptor.messageType)
+                for (i = 0; i < fileDescriptor.messageType.length; ++i)
+                    filePackage.add(Type.fromDescriptor(fileDescriptor.messageType[i], fileDescriptor.syntax));
+            if (fileDescriptor.enumType)
+                for (i = 0; i < fileDescriptor.enumType.length; ++i)
+                    filePackage.add(Enum.fromDescriptor(fileDescriptor.enumType[i]));
+            if (fileDescriptor.extension)
+                for (i = 0; i < fileDescriptor.extension.length; ++i)
+                    filePackage.add(Field.fromDescriptor(fileDescriptor.extension[i]));
+            if (fileDescriptor.service)
+                for (i = 0; i < fileDescriptor.service.length; ++i)
+                    filePackage.add(Service.fromDescriptor(fileDescriptor.service[i]));
+            var opts = fromDescriptorOptions(fileDescriptor.options, exports.FileOptions);
+            if (opts) {
+                var ks = Object.keys(opts);
+                for (i = 0; i < ks.length; ++i)
+                    filePackage.setOption(ks[i], opts[ks[i]]);
+            }
+        }
+    }
+
+    return root;
+};
+
+/**
+ * Converts a root to a descriptor set.
+ * @returns {Message<IFileDescriptorSet>} Descriptor
+ * @param {string} [syntax="proto2"] Syntax
+ */
+Root.prototype.toDescriptor = function toDescriptor(syntax) {
+    var set = exports.FileDescriptorSet.create();
+    Root_toDescriptorRecursive(this, set.file, syntax);
+    return set;
+};
+
+// Traverses a namespace and assembles the descriptor set
+function Root_toDescriptorRecursive(ns, files, syntax) {
+
+    // Create a new file
+    var file = exports.FileDescriptorProto.create({ name: ns.filename || (ns.fullName.substring(1).replace(/\./g, "_") || "root") + ".proto" });
+    if (syntax)
+        file.syntax = syntax;
+    if (!(ns instanceof Root))
+        file["package"] = ns.fullName.substring(1);
+
+    // Add nested types
+    for (var i = 0, nested; i < ns.nestedArray.length; ++i)
+        if ((nested = ns._nestedArray[i]) instanceof Type)
+            file.messageType.push(nested.toDescriptor(syntax));
+        else if (nested instanceof Enum)
+            file.enumType.push(nested.toDescriptor());
+        else if (nested instanceof Field)
+            file.extension.push(nested.toDescriptor(syntax));
+        else if (nested instanceof Service)
+            file.service.push(nested.toDescriptor());
+        else if (nested instanceof /* plain */ Namespace)
+            Root_toDescriptorRecursive(nested, files, syntax); // requires new file
+
+    // Keep package-level options
+    file.options = toDescriptorOptions(ns.options, exports.FileOptions);
+
+    // And keep the file only if there is at least one nested object
+    if (file.messageType.length + file.enumType.length + file.extension.length + file.service.length)
+        files.push(file);
+}
+
+// --- Type ---
+
+/**
+ * Properties of a DescriptorProto message.
+ * @interface IDescriptorProto
+ * @property {string} [name] Message type name
+ * @property {IFieldDescriptorProto[]} [field] Fields
+ * @property {IFieldDescriptorProto[]} [extension] Extension fields
+ * @property {IDescriptorProto[]} [nestedType] Nested message types
+ * @property {IEnumDescriptorProto[]} [enumType] Nested enums
+ * @property {IDescriptorProtoExtensionRange[]} [extensionRange] Extension ranges
+ * @property {IOneofDescriptorProto[]} [oneofDecl] Oneofs
+ * @property {IMessageOptions} [options] Not supported
+ * @property {IDescriptorProtoReservedRange[]} [reservedRange] Reserved ranges
+ * @property {string[]} [reservedName] Reserved names
+ */
+
+/**
+ * Properties of a MessageOptions message.
+ * @interface IMessageOptions
+ * @property {boolean} [mapEntry=false] Whether this message is a map entry
+ */
+
+/**
+ * Properties of an ExtensionRange message.
+ * @interface IDescriptorProtoExtensionRange
+ * @property {number} [start] Start field id
+ * @property {number} [end] End field id
+ */
+
+/**
+ * Properties of a ReservedRange message.
+ * @interface IDescriptorProtoReservedRange
+ * @property {number} [start] Start field id
+ * @property {number} [end] End field id
+ */
+
+var unnamedMessageIndex = 0;
+
+/**
+ * Creates a type from a descriptor.
+ * @param {IDescriptorProto|Reader|Uint8Array} descriptor Descriptor
+ * @param {string} [syntax="proto2"] Syntax
+ * @returns {Type} Type instance
+ */
+Type.fromDescriptor = function fromDescriptor(descriptor, syntax) {
+
+    // Decode the descriptor message if specified as a buffer:
+    if (typeof descriptor.length === "number")
+        descriptor = exports.DescriptorProto.decode(descriptor);
+
+    // Create the message type
+    var type = new Type(descriptor.name.length ? descriptor.name : "Type" + unnamedMessageIndex++, fromDescriptorOptions(descriptor.options, exports.MessageOptions)),
+        i;
+
+    /* Oneofs */ if (descriptor.oneofDecl)
+        for (i = 0; i < descriptor.oneofDecl.length; ++i)
+            type.add(OneOf.fromDescriptor(descriptor.oneofDecl[i]));
+    /* Fields */ if (descriptor.field)
+        for (i = 0; i < descriptor.field.length; ++i) {
+            var field = Field.fromDescriptor(descriptor.field[i], syntax);
+            type.add(field);
+            if (descriptor.field[i].hasOwnProperty("oneofIndex")) // eslint-disable-line no-prototype-builtins
+                type.oneofsArray[descriptor.field[i].oneofIndex].add(field);
+        }
+    /* Extension fields */ if (descriptor.extension)
+        for (i = 0; i < descriptor.extension.length; ++i)
+            type.add(Field.fromDescriptor(descriptor.extension[i], syntax));
+    /* Nested types */ if (descriptor.nestedType)
+        for (i = 0; i < descriptor.nestedType.length; ++i) {
+            type.add(Type.fromDescriptor(descriptor.nestedType[i], syntax));
+            if (descriptor.nestedType[i].options && descriptor.nestedType[i].options.mapEntry)
+                type.setOption("map_entry", true);
+        }
+    /* Nested enums */ if (descriptor.enumType)
+        for (i = 0; i < descriptor.enumType.length; ++i)
+            type.add(Enum.fromDescriptor(descriptor.enumType[i]));
+    /* Extension ranges */ if (descriptor.extensionRange && descriptor.extensionRange.length) {
+        type.extensions = [];
+        for (i = 0; i < descriptor.extensionRange.length; ++i)
+            type.extensions.push([ descriptor.extensionRange[i].start, descriptor.extensionRange[i].end ]);
+    }
+    /* Reserved... */ if (descriptor.reservedRange && descriptor.reservedRange.length || descriptor.reservedName && descriptor.reservedName.length) {
+        type.reserved = [];
+        /* Ranges */ if (descriptor.reservedRange)
+            for (i = 0; i < descriptor.reservedRange.length; ++i)
+                type.reserved.push([ descriptor.reservedRange[i].start, descriptor.reservedRange[i].end ]);
+        /* Names */ if (descriptor.reservedName)
+            for (i = 0; i < descriptor.reservedName.length; ++i)
+                type.reserved.push(descriptor.reservedName[i]);
+    }
+
+    return type;
+};
+
+/**
+ * Converts a type to a descriptor.
+ * @returns {Message<IDescriptorProto>} Descriptor
+ * @param {string} [syntax="proto2"] Syntax
+ */
+Type.prototype.toDescriptor = function toDescriptor(syntax) {
+    var descriptor = exports.DescriptorProto.create({ name: this.name }),
+        i;
+
+    /* Fields */ for (i = 0; i < this.fieldsArray.length; ++i) {
+        var fieldDescriptor;
+        descriptor.field.push(fieldDescriptor = this._fieldsArray[i].toDescriptor(syntax));
+        if (this._fieldsArray[i] instanceof MapField) { // map fields are repeated FieldNameEntry
+            var keyType = toDescriptorType(this._fieldsArray[i].keyType, this._fieldsArray[i].resolvedKeyType),
+                valueType = toDescriptorType(this._fieldsArray[i].type, this._fieldsArray[i].resolvedType),
+                valueTypeName = valueType === /* type */ 11 || valueType === /* enum */ 14
+                    ? this._fieldsArray[i].resolvedType && shortname(this.parent, this._fieldsArray[i].resolvedType) || this._fieldsArray[i].type
+                    : undefined;
+            descriptor.nestedType.push(exports.DescriptorProto.create({
+                name: fieldDescriptor.typeName,
+                field: [
+                    exports.FieldDescriptorProto.create({ name: "key", number: 1, label: 1, type: keyType }), // can't reference a type or enum
+                    exports.FieldDescriptorProto.create({ name: "value", number: 2, label: 1, type: valueType, typeName: valueTypeName })
+                ],
+                options: exports.MessageOptions.create({ mapEntry: true })
+            }));
+        }
+    }
+    /* Oneofs */ for (i = 0; i < this.oneofsArray.length; ++i)
+        descriptor.oneofDecl.push(this._oneofsArray[i].toDescriptor());
+    /* Nested... */ for (i = 0; i < this.nestedArray.length; ++i) {
+        /* Extension fields */ if (this._nestedArray[i] instanceof Field)
+            descriptor.field.push(this._nestedArray[i].toDescriptor(syntax));
+        /* Types */ else if (this._nestedArray[i] instanceof Type)
+            descriptor.nestedType.push(this._nestedArray[i].toDescriptor(syntax));
+        /* Enums */ else if (this._nestedArray[i] instanceof Enum)
+            descriptor.enumType.push(this._nestedArray[i].toDescriptor());
+        // plain nested namespaces become packages instead in Root#toDescriptor
+    }
+    /* Extension ranges */ if (this.extensions)
+        for (i = 0; i < this.extensions.length; ++i)
+            descriptor.extensionRange.push(exports.DescriptorProto.ExtensionRange.create({ start: this.extensions[i][0], end: this.extensions[i][1] }));
+    /* Reserved... */ if (this.reserved)
+        for (i = 0; i < this.reserved.length; ++i)
+            /* Names */ if (typeof this.reserved[i] === "string")
+                descriptor.reservedName.push(this.reserved[i]);
+            /* Ranges */ else
+                descriptor.reservedRange.push(exports.DescriptorProto.ReservedRange.create({ start: this.reserved[i][0], end: this.reserved[i][1] }));
+
+    descriptor.options = toDescriptorOptions(this.options, exports.MessageOptions);
+
+    return descriptor;
+};
+
+// --- Field ---
+
+/**
+ * Properties of a FieldDescriptorProto message.
+ * @interface IFieldDescriptorProto
+ * @property {string} [name] Field name
+ * @property {number} [number] Field id
+ * @property {IFieldDescriptorProtoLabel} [label] Field rule
+ * @property {IFieldDescriptorProtoType} [type] Field basic type
+ * @property {string} [typeName] Field type name
+ * @property {string} [extendee] Extended type name
+ * @property {string} [defaultValue] Literal default value
+ * @property {number} [oneofIndex] Oneof index if part of a oneof
+ * @property {*} [jsonName] Not supported
+ * @property {IFieldOptions} [options] Field options
+ */
+
+/**
+ * Values of the FieldDescriptorProto.Label enum.
+ * @typedef IFieldDescriptorProtoLabel
+ * @type {number}
+ * @property {number} LABEL_OPTIONAL=1
+ * @property {number} LABEL_REQUIRED=2
+ * @property {number} LABEL_REPEATED=3
+ */
+
+/**
+ * Values of the FieldDescriptorProto.Type enum.
+ * @typedef IFieldDescriptorProtoType
+ * @type {number}
+ * @property {number} TYPE_DOUBLE=1
+ * @property {number} TYPE_FLOAT=2
+ * @property {number} TYPE_INT64=3
+ * @property {number} TYPE_UINT64=4
+ * @property {number} TYPE_INT32=5
+ * @property {number} TYPE_FIXED64=6
+ * @property {number} TYPE_FIXED32=7
+ * @property {number} TYPE_BOOL=8
+ * @property {number} TYPE_STRING=9
+ * @property {number} TYPE_GROUP=10
+ * @property {number} TYPE_MESSAGE=11
+ * @property {number} TYPE_BYTES=12
+ * @property {number} TYPE_UINT32=13
+ * @property {number} TYPE_ENUM=14
+ * @property {number} TYPE_SFIXED32=15
+ * @property {number} TYPE_SFIXED64=16
+ * @property {number} TYPE_SINT32=17
+ * @property {number} TYPE_SINT64=18
+ */
+
+/**
+ * Properties of a FieldOptions message.
+ * @interface IFieldOptions
+ * @property {boolean} [packed] Whether packed or not (defaults to `false` for proto2 and `true` for proto3)
+ * @property {IFieldOptionsJSType} [jstype] JavaScript value type (not used by protobuf.js)
+ */
+
+/**
+ * Values of the FieldOptions.JSType enum.
+ * @typedef IFieldOptionsJSType
+ * @type {number}
+ * @property {number} JS_NORMAL=0
+ * @property {number} JS_STRING=1
+ * @property {number} JS_NUMBER=2
+ */
+
+// copied here from parse.js
+var numberRe = /^(?![eE])[0-9]*(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?$/;
+
+/**
+ * Creates a field from a descriptor.
+ * @param {IFieldDescriptorProto|Reader|Uint8Array} descriptor Descriptor
+ * @param {string} [syntax="proto2"] Syntax
+ * @returns {Field} Field instance
+ */
+Field.fromDescriptor = function fromDescriptor(descriptor, syntax) {
+
+    // Decode the descriptor message if specified as a buffer:
+    if (typeof descriptor.length === "number")
+        descriptor = exports.DescriptorProto.decode(descriptor);
+
+    if (typeof descriptor.number !== "number")
+        throw Error("missing field id");
+
+    // Rewire field type
+    var fieldType;
+    if (descriptor.typeName && descriptor.typeName.length)
+        fieldType = descriptor.typeName;
+    else
+        fieldType = fromDescriptorType(descriptor.type);
+
+    // Rewire field rule
+    var fieldRule;
+    switch (descriptor.label) {
+        // 0 is reserved for errors
+        case 1: fieldRule = undefined; break;
+        case 2: fieldRule = "required"; break;
+        case 3: fieldRule = "repeated"; break;
+        default: throw Error("illegal label: " + descriptor.label);
+    }
+
+	var extendee = descriptor.extendee;
+	if (descriptor.extendee !== undefined) {
+		extendee = extendee.length ? extendee : undefined;
+	}
+    var field = new Field(
+        descriptor.name.length ? descriptor.name : "field" + descriptor.number,
+        descriptor.number,
+        fieldType,
+        fieldRule,
+        extendee
+    );
+
+    field.options = fromDescriptorOptions(descriptor.options, exports.FieldOptions);
+
+    if (descriptor.defaultValue && descriptor.defaultValue.length) {
+        var defaultValue = descriptor.defaultValue;
+        switch (defaultValue) {
+            case "true": case "TRUE":
+                defaultValue = true;
+                break;
+            case "false": case "FALSE":
+                defaultValue = false;
+                break;
+            default:
+                var match = numberRe.exec(defaultValue);
+                if (match)
+                    defaultValue = parseInt(defaultValue); // eslint-disable-line radix
+                break;
+        }
+        field.setOption("default", defaultValue);
+    }
+
+    if (packableDescriptorType(descriptor.type)) {
+        if (syntax === "proto3") { // defaults to packed=true (internal preset is packed=true)
+            if (descriptor.options && !descriptor.options.packed)
+                field.setOption("packed", false);
+        } else if (!(descriptor.options && descriptor.options.packed)) // defaults to packed=false
+            field.setOption("packed", false);
+    }
+
+    return field;
+};
+
+/**
+ * Converts a field to a descriptor.
+ * @returns {Message<IFieldDescriptorProto>} Descriptor
+ * @param {string} [syntax="proto2"] Syntax
+ */
+Field.prototype.toDescriptor = function toDescriptor(syntax) {
+    var descriptor = exports.FieldDescriptorProto.create({ name: this.name, number: this.id });
+
+    if (this.map) {
+
+        descriptor.type = 11; // message
+        descriptor.typeName = $protobuf.util.ucFirst(this.name); // fieldName -> FieldNameEntry (built in Type#toDescriptor)
+        descriptor.label = 3; // repeated
+
+    } else {
+
+        // Rewire field type
+        switch (descriptor.type = toDescriptorType(this.type, this.resolve().resolvedType)) {
+            case 10: // group
+            case 11: // type
+            case 14: // enum
+                descriptor.typeName = this.resolvedType ? shortname(this.parent, this.resolvedType) : this.type;
+                break;
+        }
+
+        // Rewire field rule
+        switch (this.rule) {
+            case "repeated": descriptor.label = 3; break;
+            case "required": descriptor.label = 2; break;
+            default: descriptor.label = 1; break;
+        }
+
+    }
+
+    // Handle extension field
+    descriptor.extendee = this.extensionField ? this.extensionField.parent.fullName : this.extend;
+
+    // Handle part of oneof
+    if (this.partOf)
+        if ((descriptor.oneofIndex = this.parent.oneofsArray.indexOf(this.partOf)) < 0)
+            throw Error("missing oneof");
+
+    if (this.options) {
+        descriptor.options = toDescriptorOptions(this.options, exports.FieldOptions);
+        if (this.options["default"] != null)
+            descriptor.defaultValue = String(this.options["default"]);
+    }
+
+    if (syntax === "proto3") { // defaults to packed=true
+        if (!this.packed)
+            (descriptor.options || (descriptor.options = exports.FieldOptions.create())).packed = false;
+    } else if (this.packed) // defaults to packed=false
+        (descriptor.options || (descriptor.options = exports.FieldOptions.create())).packed = true;
+
+    return descriptor;
+};
+
+// --- Enum ---
+
+/**
+ * Properties of an EnumDescriptorProto message.
+ * @interface IEnumDescriptorProto
+ * @property {string} [name] Enum name
+ * @property {IEnumValueDescriptorProto[]} [value] Enum values
+ * @property {IEnumOptions} [options] Enum options
+ */
+
+/**
+ * Properties of an EnumValueDescriptorProto message.
+ * @interface IEnumValueDescriptorProto
+ * @property {string} [name] Name
+ * @property {number} [number] Value
+ * @property {*} [options] Not supported
+ */
+
+/**
+ * Properties of an EnumOptions message.
+ * @interface IEnumOptions
+ * @property {boolean} [allowAlias] Whether aliases are allowed
+ * @property {boolean} [deprecated]
+ */
+
+var unnamedEnumIndex = 0;
+
+/**
+ * Creates an enum from a descriptor.
+ * @param {IEnumDescriptorProto|Reader|Uint8Array} descriptor Descriptor
+ * @returns {Enum} Enum instance
+ */
+Enum.fromDescriptor = function fromDescriptor(descriptor) {
+
+    // Decode the descriptor message if specified as a buffer:
+    if (typeof descriptor.length === "number")
+        descriptor = exports.EnumDescriptorProto.decode(descriptor);
+
+    // Construct values object
+    var values = {};
+    if (descriptor.value)
+        for (var i = 0; i < descriptor.value.length; ++i) {
+            var name  = descriptor.value[i].name,
+                value = descriptor.value[i].number || 0;
+            values[name && name.length ? name : "NAME" + value] = value;
+        }
+
+    return new Enum(
+        descriptor.name && descriptor.name.length ? descriptor.name : "Enum" + unnamedEnumIndex++,
+        values,
+        fromDescriptorOptions(descriptor.options, exports.EnumOptions)
+    );
+};
+
+/**
+ * Converts an enum to a descriptor.
+ * @returns {Message<IEnumDescriptorProto>} Descriptor
+ */
+Enum.prototype.toDescriptor = function toDescriptor() {
+
+    // Values
+    var values = [];
+    for (var i = 0, ks = Object.keys(this.values); i < ks.length; ++i)
+        values.push(exports.EnumValueDescriptorProto.create({ name: ks[i], number: this.values[ks[i]] }));
+
+    return exports.EnumDescriptorProto.create({
+        name: this.name,
+        value: values,
+        options: toDescriptorOptions(this.options, exports.EnumOptions)
+    });
+};
+
+// --- OneOf ---
+
+/**
+ * Properties of a OneofDescriptorProto message.
+ * @interface IOneofDescriptorProto
+ * @property {string} [name] Oneof name
+ * @property {*} [options] Not supported
+ */
+
+var unnamedOneofIndex = 0;
+
+/**
+ * Creates a oneof from a descriptor.
+ * @param {IOneofDescriptorProto|Reader|Uint8Array} descriptor Descriptor
+ * @returns {OneOf} OneOf instance
+ */
+OneOf.fromDescriptor = function fromDescriptor(descriptor) {
+
+    // Decode the descriptor message if specified as a buffer:
+    if (typeof descriptor.length === "number")
+        descriptor = exports.OneofDescriptorProto.decode(descriptor);
+
+    return new OneOf(
+        // unnamedOneOfIndex is global, not per type, because we have no ref to a type here
+        descriptor.name && descriptor.name.length ? descriptor.name : "oneof" + unnamedOneofIndex++
+        // fromDescriptorOptions(descriptor.options, exports.OneofOptions) - only uninterpreted_option
+    );
+};
+
+/**
+ * Converts a oneof to a descriptor.
+ * @returns {Message<IOneofDescriptorProto>} Descriptor
+ */
+OneOf.prototype.toDescriptor = function toDescriptor() {
+    return exports.OneofDescriptorProto.create({
+        name: this.name
+        // options: toDescriptorOptions(this.options, exports.OneofOptions) - only uninterpreted_option
+    });
+};
+
+// --- Service ---
+
+/**
+ * Properties of a ServiceDescriptorProto message.
+ * @interface IServiceDescriptorProto
+ * @property {string} [name] Service name
+ * @property {IMethodDescriptorProto[]} [method] Methods
+ * @property {IServiceOptions} [options] Options
+ */
+
+/**
+ * Properties of a ServiceOptions message.
+ * @interface IServiceOptions
+ * @property {boolean} [deprecated]
+ */
+
+var unnamedServiceIndex = 0;
+
+/**
+ * Creates a service from a descriptor.
+ * @param {IServiceDescriptorProto|Reader|Uint8Array} descriptor Descriptor
+ * @returns {Service} Service instance
+ */
+Service.fromDescriptor = function fromDescriptor(descriptor) {
+
+    // Decode the descriptor message if specified as a buffer:
+    if (typeof descriptor.length === "number")
+        descriptor = exports.ServiceDescriptorProto.decode(descriptor);
+
+    var service = new Service(descriptor.name && descriptor.name.length ? descriptor.name : "Service" + unnamedServiceIndex++, fromDescriptorOptions(descriptor.options, exports.ServiceOptions));
+    if (descriptor.method)
+        for (var i = 0; i < descriptor.method.length; ++i)
+            service.add(Method.fromDescriptor(descriptor.method[i]));
+
+    return service;
+};
+
+/**
+ * Converts a service to a descriptor.
+ * @returns {Message<IServiceDescriptorProto>} Descriptor
+ */
+Service.prototype.toDescriptor = function toDescriptor() {
+
+    // Methods
+    var methods = [];
+    for (var i = 0; i < this.methodsArray.length; ++i)
+        methods.push(this._methodsArray[i].toDescriptor());
+
+    return exports.ServiceDescriptorProto.create({
+        name: this.name,
+        method: methods,
+        options: toDescriptorOptions(this.options, exports.ServiceOptions)
+    });
+};
+
+// --- Method ---
+
+/**
+ * Properties of a MethodDescriptorProto message.
+ * @interface IMethodDescriptorProto
+ * @property {string} [name] Method name
+ * @property {string} [inputType] Request type name
+ * @property {string} [outputType] Response type name
+ * @property {IMethodOptions} [options] Not supported
+ * @property {boolean} [clientStreaming=false] Whether requests are streamed
+ * @property {boolean} [serverStreaming=false] Whether responses are streamed
+ */
+
+/**
+ * Properties of a MethodOptions message.
+ * @interface IMethodOptions
+ * @property {boolean} [deprecated]
+ */
+
+var unnamedMethodIndex = 0;
+
+/**
+ * Creates a method from a descriptor.
+ * @param {IMethodDescriptorProto|Reader|Uint8Array} descriptor Descriptor
+ * @returns {Method} Reflected method instance
+ */
+Method.fromDescriptor = function fromDescriptor(descriptor) {
+
+    // Decode the descriptor message if specified as a buffer:
+    if (typeof descriptor.length === "number")
+        descriptor = exports.MethodDescriptorProto.decode(descriptor);
+
+    return new Method(
+        // unnamedMethodIndex is global, not per service, because we have no ref to a service here
+        descriptor.name && descriptor.name.length ? descriptor.name : "Method" + unnamedMethodIndex++,
+        "rpc",
+        descriptor.inputType,
+        descriptor.outputType,
+        Boolean(descriptor.clientStreaming),
+        Boolean(descriptor.serverStreaming),
+        fromDescriptorOptions(descriptor.options, exports.MethodOptions)
+    );
+};
+
+/**
+ * Converts a method to a descriptor.
+ * @returns {Message<IMethodDescriptorProto>} Descriptor
+ */
+Method.prototype.toDescriptor = function toDescriptor() {
+    return exports.MethodDescriptorProto.create({
+        name: this.name,
+        inputType: this.resolvedRequestType ? this.resolvedRequestType.fullName : this.requestType,
+        outputType: this.resolvedResponseType ? this.resolvedResponseType.fullName : this.responseType,
+        clientStreaming: this.requestStream,
+        serverStreaming: this.responseStream,
+        options: toDescriptorOptions(this.options, exports.MethodOptions)
+    });
+};
+
+// --- utility ---
+
+// Converts a descriptor type to a protobuf.js basic type
+function fromDescriptorType(type) {
+    switch (type) {
+        // 0 is reserved for errors
+        case 1: return "double";
+        case 2: return "float";
+        case 3: return "int64";
+        case 4: return "uint64";
+        case 5: return "int32";
+        case 6: return "fixed64";
+        case 7: return "fixed32";
+        case 8: return "bool";
+        case 9: return "string";
+        case 12: return "bytes";
+        case 13: return "uint32";
+        case 15: return "sfixed32";
+        case 16: return "sfixed64";
+        case 17: return "sint32";
+        case 18: return "sint64";
+    }
+    throw Error("illegal type: " + type);
+}
+
+// Tests if a descriptor type is packable
+function packableDescriptorType(type) {
+    switch (type) {
+        case 1: // double
+        case 2: // float
+        case 3: // int64
+        case 4: // uint64
+        case 5: // int32
+        case 6: // fixed64
+        case 7: // fixed32
+        case 8: // bool
+        case 13: // uint32
+        case 14: // enum (!)
+        case 15: // sfixed32
+        case 16: // sfixed64
+        case 17: // sint32
+        case 18: // sint64
+            return true;
+    }
+    return false;
+}
+
+// Converts a protobuf.js basic type to a descriptor type
+function toDescriptorType(type, resolvedType) {
+    switch (type) {
+        // 0 is reserved for errors
+        case "double": return 1;
+        case "float": return 2;
+        case "int64": return 3;
+        case "uint64": return 4;
+        case "int32": return 5;
+        case "fixed64": return 6;
+        case "fixed32": return 7;
+        case "bool": return 8;
+        case "string": return 9;
+        case "bytes": return 12;
+        case "uint32": return 13;
+        case "sfixed32": return 15;
+        case "sfixed64": return 16;
+        case "sint32": return 17;
+        case "sint64": return 18;
+    }
+    if (resolvedType instanceof Enum)
+        return 14;
+    if (resolvedType instanceof Type)
+        return resolvedType.group ? 10 : 11;
+    throw Error("illegal type: " + type);
+}
+
+// Converts descriptor options to an options object
+function fromDescriptorOptions(options, type) {
+    if (!options)
+        return undefined;
+    var out = [];
+    for (var i = 0, field, key, val; i < type.fieldsArray.length; ++i)
+        if ((key = (field = type._fieldsArray[i]).name) !== "uninterpretedOption")
+            if (options.hasOwnProperty(key)) { // eslint-disable-line no-prototype-builtins
+                val = options[key];
+                if (field.resolvedType instanceof Enum && typeof val === "number" && field.resolvedType.valuesById[val] !== undefined)
+                    val = field.resolvedType.valuesById[val];
+                out.push(underScore(key), val);
+            }
+    return out.length ? $protobuf.util.toObject(out) : undefined;
+}
+
+// Converts an options object to descriptor options
+function toDescriptorOptions(options, type) {
+    if (!options)
+        return undefined;
+    var out = [];
+    for (var i = 0, ks = Object.keys(options), key, val; i < ks.length; ++i) {
+        val = options[key = ks[i]];
+        if (key === "default")
+            continue;
+        var field = type.fields[key];
+        if (!field && !(field = type.fields[key = $protobuf.util.camelCase(key)]))
+            continue;
+        out.push(key, val);
+    }
+    return out.length ? type.fromObject($protobuf.util.toObject(out)) : undefined;
+}
+
+// Calculates the shortest relative path from `from` to `to`.
+function shortname(from, to) {
+    var fromPath = from.fullName.split("."),
+        toPath = to.fullName.split("."),
+        i = 0,
+        j = 0,
+        k = toPath.length - 1;
+    if (!(from instanceof Root) && to instanceof Namespace)
+        while (i < fromPath.length && j < k && fromPath[i] === toPath[j]) {
+            var other = to.lookup(fromPath[i++], true);
+            if (other !== null && other !== to)
+                break;
+            ++j;
+        }
+    else
+        for (; i < fromPath.length && j < k && fromPath[i] === toPath[j]; ++i, ++j);
+    return toPath.slice(j).join(".");
+}
+
+// copied here from cli/targets/proto.js
+function underScore(str) {
+    return str.substring(0,1)
+         + str.substring(1)
+               .replace(/([A-Z])(?=[a-z]|$)/g, function($0, $1) { return "_" + $1.toLowerCase(); });
+}
+
+// --- exports ---
+
+/**
+ * Reflected file descriptor set.
+ * @name FileDescriptorSet
+ * @type {Type}
+ * @const
+ * @tstype $protobuf.Type
+ */
+
+/**
+ * Reflected file descriptor proto.
+ * @name FileDescriptorProto
+ * @type {Type}
+ * @const
+ * @tstype $protobuf.Type
+ */
+
+/**
+ * Reflected descriptor proto.
+ * @name DescriptorProto
+ * @type {Type}
+ * @property {Type} ExtensionRange
+ * @property {Type} ReservedRange
+ * @const
+ * @tstype $protobuf.Type & {
+ *     ExtensionRange: $protobuf.Type,
+ *     ReservedRange: $protobuf.Type
+ * }
+ */
+
+/**
+ * Reflected field descriptor proto.
+ * @name FieldDescriptorProto
+ * @type {Type}
+ * @property {Enum} Label
+ * @property {Enum} Type
+ * @const
+ * @tstype $protobuf.Type & {
+ *     Label: $protobuf.Enum,
+ *     Type: $protobuf.Enum
+ * }
+ */
+
+/**
+ * Reflected oneof descriptor proto.
+ * @name OneofDescriptorProto
+ * @type {Type}
+ * @const
+ * @tstype $protobuf.Type
+ */
+
+/**
+ * Reflected enum descriptor proto.
+ * @name EnumDescriptorProto
+ * @type {Type}
+ * @const
+ * @tstype $protobuf.Type
+ */
+
+/**
+ * Reflected service descriptor proto.
+ * @name ServiceDescriptorProto
+ * @type {Type}
+ * @const
+ * @tstype $protobuf.Type
+ */
+
+/**
+ * Reflected enum value descriptor proto.
+ * @name EnumValueDescriptorProto
+ * @type {Type}
+ * @const
+ * @tstype $protobuf.Type
+ */
+
+/**
+ * Reflected method descriptor proto.
+ * @name MethodDescriptorProto
+ * @type {Type}
+ * @const
+ * @tstype $protobuf.Type
+ */
+
+/**
+ * Reflected file options.
+ * @name FileOptions
+ * @type {Type}
+ * @property {Enum} OptimizeMode
+ * @const
+ * @tstype $protobuf.Type & {
+ *     OptimizeMode: $protobuf.Enum
+ * }
+ */
+
+/**
+ * Reflected message options.
+ * @name MessageOptions
+ * @type {Type}
+ * @const
+ * @tstype $protobuf.Type
+ */
+
+/**
+ * Reflected field options.
+ * @name FieldOptions
+ * @type {Type}
+ * @property {Enum} CType
+ * @property {Enum} JSType
+ * @const
+ * @tstype $protobuf.Type & {
+ *     CType: $protobuf.Enum,
+ *     JSType: $protobuf.Enum
+ * }
+ */
+
+/**
+ * Reflected oneof options.
+ * @name OneofOptions
+ * @type {Type}
+ * @const
+ * @tstype $protobuf.Type
+ */
+
+/**
+ * Reflected enum options.
+ * @name EnumOptions
+ * @type {Type}
+ * @const
+ * @tstype $protobuf.Type
+ */
+
+/**
+ * Reflected enum value options.
+ * @name EnumValueOptions
+ * @type {Type}
+ * @const
+ * @tstype $protobuf.Type
+ */
+
+/**
+ * Reflected service options.
+ * @name ServiceOptions
+ * @type {Type}
+ * @const
+ * @tstype $protobuf.Type
+ */
+
+/**
+ * Reflected method options.
+ * @name MethodOptions
+ * @type {Type}
+ * @const
+ * @tstype $protobuf.Type
+ */
+
+/**
+ * Reflected uninterpretet option.
+ * @name UninterpretedOption
+ * @type {Type}
+ * @property {Type} NamePart
+ * @const
+ * @tstype $protobuf.Type & {
+ *     NamePart: $protobuf.Type
+ * }
+ */
+
+/**
+ * Reflected source code info.
+ * @name SourceCodeInfo
+ * @type {Type}
+ * @property {Type} Location
+ * @const
+ * @tstype $protobuf.Type & {
+ *     Location: $protobuf.Type
+ * }
+ */
+
+/**
+ * Reflected generated code info.
+ * @name GeneratedCodeInfo
+ * @type {Type}
+ * @property {Type} Annotation
+ * @const
+ * @tstype $protobuf.Type & {
+ *     Annotation: $protobuf.Type
+ * }
+ */
diff --git a/ext/descriptor/test.js b/ext/descriptor/test.js
new file mode 100644
index 0000000..ceb80f8
--- /dev/null
+++ b/ext/descriptor/test.js
@@ -0,0 +1,54 @@
+/*eslint-disable no-console*/
+"use strict";
+var protobuf   = require("../../"),
+    descriptor = require(".");
+
+/* var proto = {
+    nested: {
+        Message: {
+            fields: {
+                foo: {
+                    type: "string",
+                    id: 1
+                }
+            },
+            nested: {
+                SubMessage: {
+                    fields: {}
+                }
+            }
+        },
+        Enum: {
+            values: {
+                ONE: 1,
+                TWO: 2
+            }
+        }
+    }
+}; */
+
+// var root = protobuf.Root.fromJSON(proto).resolveAll();
+var root = protobuf.loadSync("tests/data/google/protobuf/descriptor.proto").resolveAll();
+
+// console.log("Original proto", JSON.stringify(root, null, 2));
+
+var msg  = root.toDescriptor();
+
+// console.log("\nDescriptor", JSON.stringify(msg.toObject(), null, 2));
+
+var buf  = descriptor.FileDescriptorSet.encode(msg).finish();
+var root2 = protobuf.Root.fromDescriptor(buf, "proto2").resolveAll();
+
+// console.log("\nDecoded proto", JSON.stringify(root2, null, 2));
+
+var diff = require("deep-diff").diff(root.toJSON(), root2.toJSON());
+if (diff) {
+    diff.forEach(function(diff) {
+        console.log(diff.kind + " @ " + diff.path.join("."));
+        console.log("lhs:", typeof diff.lhs, diff.lhs);
+        console.log("rhs:", typeof diff.rhs, diff.rhs);
+        console.log();
+    });
+    process.exitCode = 1;
+} else
+    console.log("no differences");
diff --git a/google/LICENSE b/google/LICENSE
new file mode 100644
index 0000000..868bd40
--- /dev/null
+++ b/google/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
diff --git a/google/README.md b/google/README.md
new file mode 100644
index 0000000..09e3f23
--- /dev/null
+++ b/google/README.md
@@ -0,0 +1 @@
+This folder contains stripped and pre-parsed definitions of common Google types. These files are not used by protobuf.js directly but are here so you can use or include them where required.
diff --git a/google/api/annotations.json b/google/api/annotations.json
new file mode 100644
index 0000000..3f13a73
--- /dev/null
+++ b/google/api/annotations.json
@@ -0,0 +1,83 @@
+{
+  "nested": {
+    "google": {
+      "nested": {
+        "api": {
+          "nested": {
+            "http": {
+              "type": "HttpRule",
+              "id": 72295728,
+              "extend": "google.protobuf.MethodOptions"
+            },
+            "HttpRule": {
+              "oneofs": {
+                "pattern": {
+                  "oneof": [
+                    "get",
+                    "put",
+                    "post",
+                    "delete",
+                    "patch",
+                    "custom"
+                  ]
+                }
+              },
+              "fields": {
+                "get": {
+                  "type": "string",
+                  "id": 2
+                },
+                "put": {
+                  "type": "string",
+                  "id": 3
+                },
+                "post": {
+                  "type": "string",
+                  "id": 4
+                },
+                "delete": {
+                  "type": "string",
+                  "id": 5
+                },
+                "patch": {
+                  "type": "string",
+                  "id": 6
+                },
+                "custom": {
+                  "type": "CustomHttpPattern",
+                  "id": 8
+                },
+                "selector": {
+                  "type": "string",
+                  "id": 1
+                },
+                "body": {
+                  "type": "string",
+                  "id": 7
+                },
+                "additionalBindings": {
+                  "rule": "repeated",
+                  "type": "HttpRule",
+                  "id": 11
+                }
+              }
+            }
+          }
+        },
+        "protobuf": {
+          "nested": {
+            "MethodOptions": {
+              "fields": {},
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ]
+            }
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/google/api/annotations.proto b/google/api/annotations.proto
new file mode 100644
index 0000000..63a8eef
--- /dev/null
+++ b/google/api/annotations.proto
@@ -0,0 +1,11 @@
+syntax = "proto3";
+
+package google.api;
+
+import "google/api/http.proto";
+import "google/protobuf/descriptor.proto";
+
+extend google.protobuf.MethodOptions {
+
+    HttpRule http = 72295728;
+}
\ No newline at end of file
diff --git a/google/api/http.json b/google/api/http.json
new file mode 100644
index 0000000..e3a0f4f
--- /dev/null
+++ b/google/api/http.json
@@ -0,0 +1,86 @@
+{
+  "nested": {
+    "google": {
+      "nested": {
+        "api": {
+          "nested": {
+            "Http": {
+              "fields": {
+                "rules": {
+                  "rule": "repeated",
+                  "type": "HttpRule",
+                  "id": 1
+                }
+              }
+            },
+            "HttpRule": {
+              "oneofs": {
+                "pattern": {
+                  "oneof": [
+                    "get",
+                    "put",
+                    "post",
+                    "delete",
+                    "patch",
+                    "custom"
+                  ]
+                }
+              },
+              "fields": {
+                "get": {
+                  "type": "string",
+                  "id": 2
+                },
+                "put": {
+                  "type": "string",
+                  "id": 3
+                },
+                "post": {
+                  "type": "string",
+                  "id": 4
+                },
+                "delete": {
+                  "type": "string",
+                  "id": 5
+                },
+                "patch": {
+                  "type": "string",
+                  "id": 6
+                },
+                "custom": {
+                  "type": "CustomHttpPattern",
+                  "id": 8
+                },
+                "selector": {
+                  "type": "string",
+                  "id": 1
+                },
+                "body": {
+                  "type": "string",
+                  "id": 7
+                },
+                "additionalBindings": {
+                  "rule": "repeated",
+                  "type": "HttpRule",
+                  "id": 11
+                }
+              }
+            },
+            "CustomHttpPattern": {
+              "fields": {
+                "kind": {
+                  "type": "string",
+                  "id": 1
+                },
+                "path": {
+                  "type": "string",
+                  "id": 2
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/google/api/http.proto b/google/api/http.proto
new file mode 100644
index 0000000..e9a7e9d
--- /dev/null
+++ b/google/api/http.proto
@@ -0,0 +1,31 @@
+syntax = "proto3";
+
+package google.api;
+
+message Http {
+
+    repeated HttpRule rules = 1;
+}
+
+message HttpRule {
+
+    oneof pattern {
+
+        string get = 2;
+        string put = 3;
+        string post = 4;
+        string delete = 5;
+        string patch = 6;
+        CustomHttpPattern custom = 8;
+    }
+
+    string selector = 1;
+    string body = 7;
+    repeated HttpRule additional_bindings = 11;
+}
+
+message CustomHttpPattern {
+
+    string kind = 1;
+    string path = 2;
+}
\ No newline at end of file
diff --git a/google/protobuf/api.json b/google/protobuf/api.json
new file mode 100644
index 0000000..5460612
--- /dev/null
+++ b/google/protobuf/api.json
@@ -0,0 +1,118 @@
+{
+  "nested": {
+    "google": {
+      "nested": {
+        "protobuf": {
+          "nested": {
+            "Api": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "methods": {
+                  "rule": "repeated",
+                  "type": "Method",
+                  "id": 2
+                },
+                "options": {
+                  "rule": "repeated",
+                  "type": "Option",
+                  "id": 3
+                },
+                "version": {
+                  "type": "string",
+                  "id": 4
+                },
+                "sourceContext": {
+                  "type": "SourceContext",
+                  "id": 5
+                },
+                "mixins": {
+                  "rule": "repeated",
+                  "type": "Mixin",
+                  "id": 6
+                },
+                "syntax": {
+                  "type": "Syntax",
+                  "id": 7
+                }
+              }
+            },
+            "Method": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "requestTypeUrl": {
+                  "type": "string",
+                  "id": 2
+                },
+                "requestStreaming": {
+                  "type": "bool",
+                  "id": 3
+                },
+                "responseTypeUrl": {
+                  "type": "string",
+                  "id": 4
+                },
+                "responseStreaming": {
+                  "type": "bool",
+                  "id": 5
+                },
+                "options": {
+                  "rule": "repeated",
+                  "type": "Option",
+                  "id": 6
+                },
+                "syntax": {
+                  "type": "Syntax",
+                  "id": 7
+                }
+              }
+            },
+            "Mixin": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "root": {
+                  "type": "string",
+                  "id": 2
+                }
+              }
+            },
+            "SourceContext": {
+              "fields": {
+                "fileName": {
+                  "type": "string",
+                  "id": 1
+                }
+              }
+            },
+            "Option": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "value": {
+                  "type": "Any",
+                  "id": 2
+                }
+              }
+            },
+            "Syntax": {
+              "values": {
+                "SYNTAX_PROTO2": 0,
+                "SYNTAX_PROTO3": 1
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/google/protobuf/api.proto b/google/protobuf/api.proto
new file mode 100644
index 0000000..cf6ae3f
--- /dev/null
+++ b/google/protobuf/api.proto
@@ -0,0 +1,34 @@
+syntax = "proto3";
+
+package google.protobuf;
+
+import "google/protobuf/source_context.proto";
+import "google/protobuf/type.proto";
+
+message Api {
+
+    string name = 1;
+    repeated Method methods = 2;
+    repeated Option options = 3;
+    string version = 4;
+    SourceContext source_context = 5;
+    repeated Mixin mixins = 6;
+    Syntax syntax = 7;
+}
+
+message Method {
+
+    string name = 1;
+    string request_type_url = 2;
+    bool request_streaming = 3;
+    string response_type_url = 4;
+    bool response_streaming = 5;
+    repeated Option options = 6;
+    Syntax syntax = 7;
+}
+
+message Mixin {
+
+    string name = 1;
+    string root = 2;
+}
\ No newline at end of file
diff --git a/google/protobuf/descriptor.json b/google/protobuf/descriptor.json
new file mode 100644
index 0000000..f6c5c11
--- /dev/null
+++ b/google/protobuf/descriptor.json
@@ -0,0 +1,739 @@
+{
+  "nested": {
+    "google": {
+      "nested": {
+        "protobuf": {
+          "nested": {
+            "FileDescriptorSet": {
+              "fields": {
+                "file": {
+                  "rule": "repeated",
+                  "type": "FileDescriptorProto",
+                  "id": 1
+                }
+              }
+            },
+            "FileDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "package": {
+                  "type": "string",
+                  "id": 2
+                },
+                "dependency": {
+                  "rule": "repeated",
+                  "type": "string",
+                  "id": 3
+                },
+                "publicDependency": {
+                  "rule": "repeated",
+                  "type": "int32",
+                  "id": 10,
+                  "options": {
+                    "packed": false
+                  }
+                },
+                "weakDependency": {
+                  "rule": "repeated",
+                  "type": "int32",
+                  "id": 11,
+                  "options": {
+                    "packed": false
+                  }
+                },
+                "messageType": {
+                  "rule": "repeated",
+                  "type": "DescriptorProto",
+                  "id": 4
+                },
+                "enumType": {
+                  "rule": "repeated",
+                  "type": "EnumDescriptorProto",
+                  "id": 5
+                },
+                "service": {
+                  "rule": "repeated",
+                  "type": "ServiceDescriptorProto",
+                  "id": 6
+                },
+                "extension": {
+                  "rule": "repeated",
+                  "type": "FieldDescriptorProto",
+                  "id": 7
+                },
+                "options": {
+                  "type": "FileOptions",
+                  "id": 8
+                },
+                "sourceCodeInfo": {
+                  "type": "SourceCodeInfo",
+                  "id": 9
+                },
+                "syntax": {
+                  "type": "string",
+                  "id": 12
+                }
+              }
+            },
+            "DescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "field": {
+                  "rule": "repeated",
+                  "type": "FieldDescriptorProto",
+                  "id": 2
+                },
+                "extension": {
+                  "rule": "repeated",
+                  "type": "FieldDescriptorProto",
+                  "id": 6
+                },
+                "nestedType": {
+                  "rule": "repeated",
+                  "type": "DescriptorProto",
+                  "id": 3
+                },
+                "enumType": {
+                  "rule": "repeated",
+                  "type": "EnumDescriptorProto",
+                  "id": 4
+                },
+                "extensionRange": {
+                  "rule": "repeated",
+                  "type": "ExtensionRange",
+                  "id": 5
+                },
+                "oneofDecl": {
+                  "rule": "repeated",
+                  "type": "OneofDescriptorProto",
+                  "id": 8
+                },
+                "options": {
+                  "type": "MessageOptions",
+                  "id": 7
+                },
+                "reservedRange": {
+                  "rule": "repeated",
+                  "type": "ReservedRange",
+                  "id": 9
+                },
+                "reservedName": {
+                  "rule": "repeated",
+                  "type": "string",
+                  "id": 10
+                }
+              },
+              "nested": {
+                "ExtensionRange": {
+                  "fields": {
+                    "start": {
+                      "type": "int32",
+                      "id": 1
+                    },
+                    "end": {
+                      "type": "int32",
+                      "id": 2
+                    }
+                  }
+                },
+                "ReservedRange": {
+                  "fields": {
+                    "start": {
+                      "type": "int32",
+                      "id": 1
+                    },
+                    "end": {
+                      "type": "int32",
+                      "id": 2
+                    }
+                  }
+                }
+              }
+            },
+            "FieldDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "number": {
+                  "type": "int32",
+                  "id": 3
+                },
+                "label": {
+                  "type": "Label",
+                  "id": 4
+                },
+                "type": {
+                  "type": "Type",
+                  "id": 5
+                },
+                "typeName": {
+                  "type": "string",
+                  "id": 6
+                },
+                "extendee": {
+                  "type": "string",
+                  "id": 2
+                },
+                "defaultValue": {
+                  "type": "string",
+                  "id": 7
+                },
+                "oneofIndex": {
+                  "type": "int32",
+                  "id": 9
+                },
+                "jsonName": {
+                  "type": "string",
+                  "id": 10
+                },
+                "options": {
+                  "type": "FieldOptions",
+                  "id": 8
+                }
+              },
+              "nested": {
+                "Type": {
+                  "values": {
+                    "TYPE_DOUBLE": 1,
+                    "TYPE_FLOAT": 2,
+                    "TYPE_INT64": 3,
+                    "TYPE_UINT64": 4,
+                    "TYPE_INT32": 5,
+                    "TYPE_FIXED64": 6,
+                    "TYPE_FIXED32": 7,
+                    "TYPE_BOOL": 8,
+                    "TYPE_STRING": 9,
+                    "TYPE_GROUP": 10,
+                    "TYPE_MESSAGE": 11,
+                    "TYPE_BYTES": 12,
+                    "TYPE_UINT32": 13,
+                    "TYPE_ENUM": 14,
+                    "TYPE_SFIXED32": 15,
+                    "TYPE_SFIXED64": 16,
+                    "TYPE_SINT32": 17,
+                    "TYPE_SINT64": 18
+                  }
+                },
+                "Label": {
+                  "values": {
+                    "LABEL_OPTIONAL": 1,
+                    "LABEL_REQUIRED": 2,
+                    "LABEL_REPEATED": 3
+                  }
+                }
+              }
+            },
+            "OneofDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "options": {
+                  "type": "OneofOptions",
+                  "id": 2
+                }
+              }
+            },
+            "EnumDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "value": {
+                  "rule": "repeated",
+                  "type": "EnumValueDescriptorProto",
+                  "id": 2
+                },
+                "options": {
+                  "type": "EnumOptions",
+                  "id": 3
+                }
+              }
+            },
+            "EnumValueDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "number": {
+                  "type": "int32",
+                  "id": 2
+                },
+                "options": {
+                  "type": "EnumValueOptions",
+                  "id": 3
+                }
+              }
+            },
+            "ServiceDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "method": {
+                  "rule": "repeated",
+                  "type": "MethodDescriptorProto",
+                  "id": 2
+                },
+                "options": {
+                  "type": "ServiceOptions",
+                  "id": 3
+                }
+              }
+            },
+            "MethodDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "inputType": {
+                  "type": "string",
+                  "id": 2
+                },
+                "outputType": {
+                  "type": "string",
+                  "id": 3
+                },
+                "options": {
+                  "type": "MethodOptions",
+                  "id": 4
+                },
+                "clientStreaming": {
+                  "type": "bool",
+                  "id": 5
+                },
+                "serverStreaming": {
+                  "type": "bool",
+                  "id": 6
+                }
+              }
+            },
+            "FileOptions": {
+              "fields": {
+                "javaPackage": {
+                  "type": "string",
+                  "id": 1
+                },
+                "javaOuterClassname": {
+                  "type": "string",
+                  "id": 8
+                },
+                "javaMultipleFiles": {
+                  "type": "bool",
+                  "id": 10
+                },
+                "javaGenerateEqualsAndHash": {
+                  "type": "bool",
+                  "id": 20,
+                  "options": {
+                    "deprecated": true
+                  }
+                },
+                "javaStringCheckUtf8": {
+                  "type": "bool",
+                  "id": 27
+                },
+                "optimizeFor": {
+                  "type": "OptimizeMode",
+                  "id": 9,
+                  "options": {
+                    "default": "SPEED"
+                  }
+                },
+                "goPackage": {
+                  "type": "string",
+                  "id": 11
+                },
+                "ccGenericServices": {
+                  "type": "bool",
+                  "id": 16
+                },
+                "javaGenericServices": {
+                  "type": "bool",
+                  "id": 17
+                },
+                "pyGenericServices": {
+                  "type": "bool",
+                  "id": 18
+                },
+                "deprecated": {
+                  "type": "bool",
+                  "id": 23
+                },
+                "ccEnableArenas": {
+                  "type": "bool",
+                  "id": 31
+                },
+                "objcClassPrefix": {
+                  "type": "string",
+                  "id": 36
+                },
+                "csharpNamespace": {
+                  "type": "string",
+                  "id": 37
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ],
+              "reserved": [
+                [
+                  38,
+                  38
+                ]
+              ],
+              "nested": {
+                "OptimizeMode": {
+                  "values": {
+                    "SPEED": 1,
+                    "CODE_SIZE": 2,
+                    "LITE_RUNTIME": 3
+                  }
+                }
+              }
+            },
+            "MessageOptions": {
+              "fields": {
+                "messageSetWireFormat": {
+                  "type": "bool",
+                  "id": 1
+                },
+                "noStandardDescriptorAccessor": {
+                  "type": "bool",
+                  "id": 2
+                },
+                "deprecated": {
+                  "type": "bool",
+                  "id": 3
+                },
+                "mapEntry": {
+                  "type": "bool",
+                  "id": 7
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ],
+              "reserved": [
+                [
+                  8,
+                  8
+                ]
+              ]
+            },
+            "FieldOptions": {
+              "fields": {
+                "ctype": {
+                  "type": "CType",
+                  "id": 1,
+                  "options": {
+                    "default": "STRING"
+                  }
+                },
+                "packed": {
+                  "type": "bool",
+                  "id": 2
+                },
+                "jstype": {
+                  "type": "JSType",
+                  "id": 6,
+                  "options": {
+                    "default": "JS_NORMAL"
+                  }
+                },
+                "lazy": {
+                  "type": "bool",
+                  "id": 5
+                },
+                "deprecated": {
+                  "type": "bool",
+                  "id": 3
+                },
+                "weak": {
+                  "type": "bool",
+                  "id": 10
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ],
+              "reserved": [
+                [
+                  4,
+                  4
+                ]
+              ],
+              "nested": {
+                "CType": {
+                  "values": {
+                    "STRING": 0,
+                    "CORD": 1,
+                    "STRING_PIECE": 2
+                  }
+                },
+                "JSType": {
+                  "values": {
+                    "JS_NORMAL": 0,
+                    "JS_STRING": 1,
+                    "JS_NUMBER": 2
+                  }
+                }
+              }
+            },
+            "OneofOptions": {
+              "fields": {
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ]
+            },
+            "EnumOptions": {
+              "fields": {
+                "allowAlias": {
+                  "type": "bool",
+                  "id": 2
+                },
+                "deprecated": {
+                  "type": "bool",
+                  "id": 3
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ]
+            },
+            "EnumValueOptions": {
+              "fields": {
+                "deprecated": {
+                  "type": "bool",
+                  "id": 1
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ]
+            },
+            "ServiceOptions": {
+              "fields": {
+                "deprecated": {
+                  "type": "bool",
+                  "id": 33
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ]
+            },
+            "MethodOptions": {
+              "fields": {
+                "deprecated": {
+                  "type": "bool",
+                  "id": 33
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ]
+            },
+            "UninterpretedOption": {
+              "fields": {
+                "name": {
+                  "rule": "repeated",
+                  "type": "NamePart",
+                  "id": 2
+                },
+                "identifierValue": {
+                  "type": "string",
+                  "id": 3
+                },
+                "positiveIntValue": {
+                  "type": "uint64",
+                  "id": 4
+                },
+                "negativeIntValue": {
+                  "type": "int64",
+                  "id": 5
+                },
+                "doubleValue": {
+                  "type": "double",
+                  "id": 6
+                },
+                "stringValue": {
+                  "type": "bytes",
+                  "id": 7
+                },
+                "aggregateValue": {
+                  "type": "string",
+                  "id": 8
+                }
+              },
+              "nested": {
+                "NamePart": {
+                  "fields": {
+                    "namePart": {
+                      "rule": "required",
+                      "type": "string",
+                      "id": 1
+                    },
+                    "isExtension": {
+                      "rule": "required",
+                      "type": "bool",
+                      "id": 2
+                    }
+                  }
+                }
+              }
+            },
+            "SourceCodeInfo": {
+              "fields": {
+                "location": {
+                  "rule": "repeated",
+                  "type": "Location",
+                  "id": 1
+                }
+              },
+              "nested": {
+                "Location": {
+                  "fields": {
+                    "path": {
+                      "rule": "repeated",
+                      "type": "int32",
+                      "id": 1
+                    },
+                    "span": {
+                      "rule": "repeated",
+                      "type": "int32",
+                      "id": 2
+                    },
+                    "leadingComments": {
+                      "type": "string",
+                      "id": 3
+                    },
+                    "trailingComments": {
+                      "type": "string",
+                      "id": 4
+                    },
+                    "leadingDetachedComments": {
+                      "rule": "repeated",
+                      "type": "string",
+                      "id": 6
+                    }
+                  }
+                }
+              }
+            },
+            "GeneratedCodeInfo": {
+              "fields": {
+                "annotation": {
+                  "rule": "repeated",
+                  "type": "Annotation",
+                  "id": 1
+                }
+              },
+              "nested": {
+                "Annotation": {
+                  "fields": {
+                    "path": {
+                      "rule": "repeated",
+                      "type": "int32",
+                      "id": 1
+                    },
+                    "sourceFile": {
+                      "type": "string",
+                      "id": 2
+                    },
+                    "begin": {
+                      "type": "int32",
+                      "id": 3
+                    },
+                    "end": {
+                      "type": "int32",
+                      "id": 4
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/google/protobuf/descriptor.proto b/google/protobuf/descriptor.proto
new file mode 100644
index 0000000..3279492
--- /dev/null
+++ b/google/protobuf/descriptor.proto
@@ -0,0 +1,286 @@
+syntax = "proto2";
+
+package google.protobuf;
+
+message FileDescriptorSet {
+
+    repeated FileDescriptorProto file = 1;
+}
+
+message FileDescriptorProto {
+
+    optional string name = 1;
+    optional string package = 2;
+    repeated string dependency = 3;
+    repeated int32 public_dependency = 10;
+    repeated int32 weak_dependency = 11;
+    repeated DescriptorProto message_type = 4;
+    repeated EnumDescriptorProto enum_type = 5;
+    repeated ServiceDescriptorProto service = 6;
+    repeated FieldDescriptorProto extension = 7;
+    optional FileOptions options = 8;
+    optional SourceCodeInfo source_code_info = 9;
+    optional string syntax = 12;
+}
+
+message DescriptorProto {
+
+    optional string name = 1;
+    repeated FieldDescriptorProto field = 2;
+    repeated FieldDescriptorProto extension = 6;
+    repeated DescriptorProto nested_type = 3;
+    repeated EnumDescriptorProto enum_type = 4;
+    repeated ExtensionRange extension_range = 5;
+    repeated OneofDescriptorProto oneof_decl = 8;
+    optional MessageOptions options = 7;
+    repeated ReservedRange reserved_range = 9;
+    repeated string reserved_name = 10;
+
+    message ExtensionRange {
+
+        optional int32 start = 1;
+        optional int32 end = 2;
+    }
+
+    message ReservedRange {
+
+        optional int32 start = 1;
+        optional int32 end = 2;
+    }
+}
+
+message FieldDescriptorProto {
+
+    optional string name = 1;
+    optional int32 number = 3;
+    optional Label label = 4;
+    optional Type type = 5;
+    optional string type_name = 6;
+    optional string extendee = 2;
+    optional string default_value = 7;
+    optional int32 oneof_index = 9;
+    optional string json_name = 10;
+    optional FieldOptions options = 8;
+
+    enum Type {
+
+        TYPE_DOUBLE = 1;
+        TYPE_FLOAT = 2;
+        TYPE_INT64 = 3;
+        TYPE_UINT64 = 4;
+        TYPE_INT32 = 5;
+        TYPE_FIXED64 = 6;
+        TYPE_FIXED32 = 7;
+        TYPE_BOOL = 8;
+        TYPE_STRING = 9;
+        TYPE_GROUP = 10;
+        TYPE_MESSAGE = 11;
+        TYPE_BYTES = 12;
+        TYPE_UINT32 = 13;
+        TYPE_ENUM = 14;
+        TYPE_SFIXED32 = 15;
+        TYPE_SFIXED64 = 16;
+        TYPE_SINT32 = 17;
+        TYPE_SINT64 = 18;
+    }
+
+    enum Label {
+
+        LABEL_OPTIONAL = 1;
+        LABEL_REQUIRED = 2;
+        LABEL_REPEATED = 3;
+    }
+}
+
+message OneofDescriptorProto {
+
+    optional string name = 1;
+    optional OneofOptions options = 2;
+}
+
+message EnumDescriptorProto {
+
+    optional string name = 1;
+    repeated EnumValueDescriptorProto value = 2;
+    optional EnumOptions options = 3;
+}
+
+message EnumValueDescriptorProto {
+
+    optional string name = 1;
+    optional int32 number = 2;
+    optional EnumValueOptions options = 3;
+}
+
+message ServiceDescriptorProto {
+
+    optional string name = 1;
+    repeated MethodDescriptorProto method = 2;
+    optional ServiceOptions options = 3;
+}
+
+message MethodDescriptorProto {
+
+    optional string name = 1;
+    optional string input_type = 2;
+    optional string output_type = 3;
+    optional MethodOptions options = 4;
+    optional bool client_streaming = 5;
+    optional bool server_streaming = 6;
+}
+
+message FileOptions {
+
+    optional string java_package = 1;
+    optional string java_outer_classname = 8;
+    optional bool java_multiple_files = 10;
+    optional bool java_generate_equals_and_hash = 20 [deprecated=true];
+    optional bool java_string_check_utf8 = 27;
+    optional OptimizeMode optimize_for = 9 [default=SPEED];
+    optional string go_package = 11;
+    optional bool cc_generic_services = 16;
+    optional bool java_generic_services = 17;
+    optional bool py_generic_services = 18;
+    optional bool deprecated = 23;
+    optional bool cc_enable_arenas = 31;
+    optional string objc_class_prefix = 36;
+    optional string csharp_namespace = 37;
+    repeated UninterpretedOption uninterpreted_option = 999;
+
+    enum OptimizeMode {
+
+        SPEED = 1;
+        CODE_SIZE = 2;
+        LITE_RUNTIME = 3;
+    }
+
+    extensions 1000 to max;
+
+    reserved 38;
+}
+
+message MessageOptions {
+
+    optional bool message_set_wire_format = 1;
+    optional bool no_standard_descriptor_accessor = 2;
+    optional bool deprecated = 3;
+    optional bool map_entry = 7;
+    repeated UninterpretedOption uninterpreted_option = 999;
+
+    extensions 1000 to max;
+
+    reserved 8;
+}
+
+message FieldOptions {
+
+    optional CType ctype = 1 [default=STRING];
+    optional bool packed = 2;
+    optional JSType jstype = 6 [default=JS_NORMAL];
+    optional bool lazy = 5;
+    optional bool deprecated = 3;
+    optional bool weak = 10;
+    repeated UninterpretedOption uninterpreted_option = 999;
+
+    enum CType {
+
+        STRING = 0;
+        CORD = 1;
+        STRING_PIECE = 2;
+    }
+
+    enum JSType {
+
+        JS_NORMAL = 0;
+        JS_STRING = 1;
+        JS_NUMBER = 2;
+    }
+
+    extensions 1000 to max;
+
+    reserved 4;
+}
+
+message OneofOptions {
+
+    repeated UninterpretedOption uninterpreted_option = 999;
+
+    extensions 1000 to max;
+}
+
+message EnumOptions {
+
+    optional bool allow_alias = 2;
+    optional bool deprecated = 3;
+    repeated UninterpretedOption uninterpreted_option = 999;
+
+    extensions 1000 to max;
+}
+
+message EnumValueOptions {
+
+    optional bool deprecated = 1;
+    repeated UninterpretedOption uninterpreted_option = 999;
+
+    extensions 1000 to max;
+}
+
+message ServiceOptions {
+
+    optional bool deprecated = 33;
+    repeated UninterpretedOption uninterpreted_option = 999;
+
+    extensions 1000 to max;
+}
+
+message MethodOptions {
+
+    optional bool deprecated = 33;
+    repeated UninterpretedOption uninterpreted_option = 999;
+
+    extensions 1000 to max;
+}
+
+message UninterpretedOption {
+
+    repeated NamePart name = 2;
+    optional string identifier_value = 3;
+    optional uint64 positive_int_value = 4;
+    optional int64 negative_int_value = 5;
+    optional double double_value = 6;
+    optional bytes string_value = 7;
+    optional string aggregate_value = 8;
+
+    message NamePart {
+
+        required string name_part = 1;
+        required bool is_extension = 2;
+    }
+}
+
+message SourceCodeInfo {
+
+    repeated Location location = 1;
+
+    message Location {
+
+        repeated int32 path = 1 [packed=true];
+        repeated int32 span = 2 [packed=true];
+        optional string leading_comments = 3;
+        optional string trailing_comments = 4;
+        repeated string leading_detached_comments = 6;
+    }
+}
+
+message GeneratedCodeInfo {
+
+    repeated Annotation annotation = 1;
+
+    message Annotation {
+
+        repeated int32 path = 1 [packed=true];
+        optional string source_file = 2;
+        optional int32 begin = 3;
+        optional int32 end = 4;
+    }
+}
diff --git a/google/protobuf/source_context.json b/google/protobuf/source_context.json
new file mode 100644
index 0000000..51adb63
--- /dev/null
+++ b/google/protobuf/source_context.json
@@ -0,0 +1,20 @@
+{
+  "nested": {
+    "google": {
+      "nested": {
+        "protobuf": {
+          "nested": {
+            "SourceContext": {
+              "fields": {
+                "fileName": {
+                  "type": "string",
+                  "id": 1
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/google/protobuf/source_context.proto b/google/protobuf/source_context.proto
new file mode 100644
index 0000000..584d36c
--- /dev/null
+++ b/google/protobuf/source_context.proto
@@ -0,0 +1,7 @@
+syntax = "proto3";
+
+package google.protobuf;
+
+message SourceContext {
+    string file_name = 1;
+}
diff --git a/google/protobuf/type.json b/google/protobuf/type.json
new file mode 100644
index 0000000..fffa70d
--- /dev/null
+++ b/google/protobuf/type.json
@@ -0,0 +1,202 @@
+{
+  "nested": {
+    "google": {
+      "nested": {
+        "protobuf": {
+          "nested": {
+            "Type": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "fields": {
+                  "rule": "repeated",
+                  "type": "Field",
+                  "id": 2
+                },
+                "oneofs": {
+                  "rule": "repeated",
+                  "type": "string",
+                  "id": 3
+                },
+                "options": {
+                  "rule": "repeated",
+                  "type": "Option",
+                  "id": 4
+                },
+                "sourceContext": {
+                  "type": "SourceContext",
+                  "id": 5
+                },
+                "syntax": {
+                  "type": "Syntax",
+                  "id": 6
+                }
+              }
+            },
+            "Field": {
+              "fields": {
+                "kind": {
+                  "type": "Kind",
+                  "id": 1
+                },
+                "cardinality": {
+                  "type": "Cardinality",
+                  "id": 2
+                },
+                "number": {
+                  "type": "int32",
+                  "id": 3
+                },
+                "name": {
+                  "type": "string",
+                  "id": 4
+                },
+                "typeUrl": {
+                  "type": "string",
+                  "id": 6
+                },
+                "oneofIndex": {
+                  "type": "int32",
+                  "id": 7
+                },
+                "packed": {
+                  "type": "bool",
+                  "id": 8
+                },
+                "options": {
+                  "rule": "repeated",
+                  "type": "Option",
+                  "id": 9
+                },
+                "jsonName": {
+                  "type": "string",
+                  "id": 10
+                },
+                "defaultValue": {
+                  "type": "string",
+                  "id": 11
+                }
+              },
+              "nested": {
+                "Kind": {
+                  "values": {
+                    "TYPE_UNKNOWN": 0,
+                    "TYPE_DOUBLE": 1,
+                    "TYPE_FLOAT": 2,
+                    "TYPE_INT64": 3,
+                    "TYPE_UINT64": 4,
+                    "TYPE_INT32": 5,
+                    "TYPE_FIXED64": 6,
+                    "TYPE_FIXED32": 7,
+                    "TYPE_BOOL": 8,
+                    "TYPE_STRING": 9,
+                    "TYPE_GROUP": 10,
+                    "TYPE_MESSAGE": 11,
+                    "TYPE_BYTES": 12,
+                    "TYPE_UINT32": 13,
+                    "TYPE_ENUM": 14,
+                    "TYPE_SFIXED32": 15,
+                    "TYPE_SFIXED64": 16,
+                    "TYPE_SINT32": 17,
+                    "TYPE_SINT64": 18
+                  }
+                },
+                "Cardinality": {
+                  "values": {
+                    "CARDINALITY_UNKNOWN": 0,
+                    "CARDINALITY_OPTIONAL": 1,
+                    "CARDINALITY_REQUIRED": 2,
+                    "CARDINALITY_REPEATED": 3
+                  }
+                }
+              }
+            },
+            "Enum": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "enumvalue": {
+                  "rule": "repeated",
+                  "type": "EnumValue",
+                  "id": 2
+                },
+                "options": {
+                  "rule": "repeated",
+                  "type": "Option",
+                  "id": 3
+                },
+                "sourceContext": {
+                  "type": "SourceContext",
+                  "id": 4
+                },
+                "syntax": {
+                  "type": "Syntax",
+                  "id": 5
+                }
+              }
+            },
+            "EnumValue": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "number": {
+                  "type": "int32",
+                  "id": 2
+                },
+                "options": {
+                  "rule": "repeated",
+                  "type": "Option",
+                  "id": 3
+                }
+              }
+            },
+            "Option": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "value": {
+                  "type": "Any",
+                  "id": 2
+                }
+              }
+            },
+            "Syntax": {
+              "values": {
+                "SYNTAX_PROTO2": 0,
+                "SYNTAX_PROTO3": 1
+              }
+            },
+            "Any": {
+              "fields": {
+                "type_url": {
+                  "type": "string",
+                  "id": 1
+                },
+                "value": {
+                  "type": "bytes",
+                  "id": 2
+                }
+              }
+            },
+            "SourceContext": {
+              "fields": {
+                "fileName": {
+                  "type": "string",
+                  "id": 1
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/google/protobuf/type.proto b/google/protobuf/type.proto
new file mode 100644
index 0000000..8ee445b
--- /dev/null
+++ b/google/protobuf/type.proto
@@ -0,0 +1,89 @@
+syntax = "proto3";
+
+package google.protobuf;
+
+import "google/protobuf/any.proto";
+import "google/protobuf/source_context.proto";
+
+message Type {
+
+    string name = 1;
+    repeated Field fields = 2;
+    repeated string oneofs = 3;
+    repeated Option options = 4;
+    SourceContext source_context = 5;
+    Syntax syntax = 6;
+}
+
+message Field {
+
+    Kind kind = 1;
+    Cardinality cardinality = 2;
+    int32 number = 3;
+    string name = 4;
+    string type_url = 6;
+    int32 oneof_index = 7;
+    bool packed = 8;
+    repeated Option options = 9;
+    string json_name = 10;
+    string default_value = 11;
+
+    enum Kind {
+
+        TYPE_UNKNOWN = 0;
+        TYPE_DOUBLE = 1;
+        TYPE_FLOAT = 2;
+        TYPE_INT64 = 3;
+        TYPE_UINT64 = 4;
+        TYPE_INT32 = 5;
+        TYPE_FIXED64 = 6;
+        TYPE_FIXED32 = 7;
+        TYPE_BOOL = 8;
+        TYPE_STRING = 9;
+        TYPE_GROUP = 10;
+        TYPE_MESSAGE = 11;
+        TYPE_BYTES = 12;
+        TYPE_UINT32 = 13;
+        TYPE_ENUM = 14;
+        TYPE_SFIXED32 = 15;
+        TYPE_SFIXED64 = 16;
+        TYPE_SINT32 = 17;
+        TYPE_SINT64 = 18;
+    }
+
+    enum Cardinality {
+
+        CARDINALITY_UNKNOWN = 0;
+        CARDINALITY_OPTIONAL = 1;
+        CARDINALITY_REQUIRED = 2;
+        CARDINALITY_REPEATED = 3;
+    }
+}
+
+message Enum {
+
+    string name = 1;
+    repeated EnumValue enumvalue = 2;
+    repeated Option options = 3;
+    SourceContext source_context = 4;
+    Syntax syntax = 5;
+}
+
+message EnumValue {
+
+    string name = 1;
+    int32 number = 2;
+    repeated Option options = 3;
+}
+
+message Option {
+
+    string name = 1;
+    Any value = 2;
+}
+
+enum Syntax {
+
+    SYNTAX_PROTO2 = 0;
+    SYNTAX_PROTO3 = 1;
+}
diff --git a/index.d.ts b/index.d.ts
new file mode 100644
index 0000000..750ad2f
--- /dev/null
+++ b/index.d.ts
@@ -0,0 +1,2741 @@
+// DO NOT EDIT! This is a generated file. Edit the JSDoc in src/*.js instead and run 'npm run build:types'.
+
+export as namespace protobuf;
+
+/**
+ * Provides common type definitions.
+ * Can also be used to provide additional google types or your own custom types.
+ * @param name Short name as in `google/protobuf/[name].proto` or full file name
+ * @param json JSON definition within `google.protobuf` if a short name, otherwise the file's root definition
+ */
+export function common(name: string, json: { [k: string]: any }): void;
+
+export namespace common {
+
+    /** Properties of a google.protobuf.Any message. */
+    interface IAny {
+        typeUrl?: string;
+        bytes?: Uint8Array;
+    }
+
+    /** Properties of a google.protobuf.Duration message. */
+    interface IDuration {
+        seconds?: (number|Long);
+        nanos?: number;
+    }
+
+    /** Properties of a google.protobuf.Timestamp message. */
+    interface ITimestamp {
+        seconds?: (number|Long);
+        nanos?: number;
+    }
+
+    /** Properties of a google.protobuf.Empty message. */
+    interface IEmpty {
+    }
+
+    /** Properties of a google.protobuf.Struct message. */
+    interface IStruct {
+        fields?: { [k: string]: IValue };
+    }
+
+    /** Properties of a google.protobuf.Value message. */
+    interface IValue {
+        kind?: string;
+        nullValue?: 0;
+        numberValue?: number;
+        stringValue?: string;
+        boolValue?: boolean;
+        structValue?: IStruct;
+        listValue?: IListValue;
+    }
+
+    /** Properties of a google.protobuf.ListValue message. */
+    interface IListValue {
+        values?: IValue[];
+    }
+
+    /** Properties of a google.protobuf.DoubleValue message. */
+    interface IDoubleValue {
+        value?: number;
+    }
+
+    /** Properties of a google.protobuf.FloatValue message. */
+    interface IFloatValue {
+        value?: number;
+    }
+
+    /** Properties of a google.protobuf.Int64Value message. */
+    interface IInt64Value {
+        value?: (number|Long);
+    }
+
+    /** Properties of a google.protobuf.UInt64Value message. */
+    interface IUInt64Value {
+        value?: (number|Long);
+    }
+
+    /** Properties of a google.protobuf.Int32Value message. */
+    interface IInt32Value {
+        value?: number;
+    }
+
+    /** Properties of a google.protobuf.UInt32Value message. */
+    interface IUInt32Value {
+        value?: number;
+    }
+
+    /** Properties of a google.protobuf.BoolValue message. */
+    interface IBoolValue {
+        value?: boolean;
+    }
+
+    /** Properties of a google.protobuf.StringValue message. */
+    interface IStringValue {
+        value?: string;
+    }
+
+    /** Properties of a google.protobuf.BytesValue message. */
+    interface IBytesValue {
+        value?: Uint8Array;
+    }
+
+    /**
+     * Gets the root definition of the specified common proto file.
+     *
+     * Bundled definitions are:
+     * - google/protobuf/any.proto
+     * - google/protobuf/duration.proto
+     * - google/protobuf/empty.proto
+     * - google/protobuf/field_mask.proto
+     * - google/protobuf/struct.proto
+     * - google/protobuf/timestamp.proto
+     * - google/protobuf/wrappers.proto
+     *
+     * @param file Proto file name
+     * @returns Root definition or `null` if not defined
+     */
+    function get(file: string): (INamespace|null);
+}
+
+/** Runtime message from/to plain object converters. */
+export namespace converter {
+
+    /**
+     * Generates a plain object to runtime message converter specific to the specified message type.
+     * @param mtype Message type
+     * @returns Codegen instance
+     */
+    function fromObject(mtype: Type): Codegen;
+
+    /**
+     * Generates a runtime message to plain object converter specific to the specified message type.
+     * @param mtype Message type
+     * @returns Codegen instance
+     */
+    function toObject(mtype: Type): Codegen;
+}
+
+/**
+ * Generates a decoder specific to the specified message type.
+ * @param mtype Message type
+ * @returns Codegen instance
+ */
+export function decoder(mtype: Type): Codegen;
+
+/**
+ * Generates an encoder specific to the specified message type.
+ * @param mtype Message type
+ * @returns Codegen instance
+ */
+export function encoder(mtype: Type): Codegen;
+
+/** Reflected enum. */
+export class Enum extends ReflectionObject {
+
+    /**
+     * Constructs a new enum instance.
+     * @param name Unique name within its namespace
+     * @param [values] Enum values as an object, by name
+     * @param [options] Declared options
+     * @param [comment] The comment for this enum
+     * @param [comments] The value comments for this enum
+     * @param [valuesOptions] The value options for this enum
+     */
+    constructor(name: string, values?: { [k: string]: number }, options?: { [k: string]: any }, comment?: string, comments?: { [k: string]: string }, valuesOptions?: ({ [k: string]: { [k: string]: any } }|undefined));
+
+    /** Enum values by id. */
+    public valuesById: { [k: number]: string };
+
+    /** Enum values by name. */
+    public values: { [k: string]: number };
+
+    /** Enum comment text. */
+    public comment: (string|null);
+
+    /** Value comment texts, if any. */
+    public comments: { [k: string]: string };
+
+    /** Values options, if any */
+    public valuesOptions?: { [k: string]: { [k: string]: any } };
+
+    /** Reserved ranges, if any. */
+    public reserved: (number[]|string)[];
+
+    /**
+     * Constructs an enum from an enum descriptor.
+     * @param name Enum name
+     * @param json Enum descriptor
+     * @returns Created enum
+     * @throws {TypeError} If arguments are invalid
+     */
+    public static fromJSON(name: string, json: IEnum): Enum;
+
+    /**
+     * Converts this enum to an enum descriptor.
+     * @param [toJSONOptions] JSON conversion options
+     * @returns Enum descriptor
+     */
+    public toJSON(toJSONOptions?: IToJSONOptions): IEnum;
+
+    /**
+     * Adds a value to this enum.
+     * @param name Value name
+     * @param id Value id
+     * @param [comment] Comment, if any
+     * @param {Object.<string, *>|undefined} [options] Options, if any
+     * @returns `this`
+     * @throws {TypeError} If arguments are invalid
+     * @throws {Error} If there is already a value with this name or id
+     */
+    public add(name: string, id: number, comment?: string, options?: ({ [k: string]: any }|undefined)): Enum;
+
+    /**
+     * Removes a value from this enum
+     * @param name Value name
+     * @returns `this`
+     * @throws {TypeError} If arguments are invalid
+     * @throws {Error} If `name` is not a name of this enum
+     */
+    public remove(name: string): Enum;
+
+    /**
+     * Tests if the specified id is reserved.
+     * @param id Id to test
+     * @returns `true` if reserved, otherwise `false`
+     */
+    public isReservedId(id: number): boolean;
+
+    /**
+     * Tests if the specified name is reserved.
+     * @param name Name to test
+     * @returns `true` if reserved, otherwise `false`
+     */
+    public isReservedName(name: string): boolean;
+}
+
+/** Enum descriptor. */
+export interface IEnum {
+
+    /** Enum values */
+    values: { [k: string]: number };
+
+    /** Enum options */
+    options?: { [k: string]: any };
+}
+
+/** Reflected message field. */
+export class Field extends FieldBase {
+
+    /**
+     * Constructs a new message field instance. Note that {@link MapField|map fields} have their own class.
+     * @param name Unique name within its namespace
+     * @param id Unique id within its namespace
+     * @param type Value type
+     * @param [rule="optional"] Field rule
+     * @param [extend] Extended type if different from parent
+     * @param [options] Declared options
+     */
+    constructor(name: string, id: number, type: string, rule?: (string|{ [k: string]: any }), extend?: (string|{ [k: string]: any }), options?: { [k: string]: any });
+
+    /**
+     * Constructs a field from a field descriptor.
+     * @param name Field name
+     * @param json Field descriptor
+     * @returns Created field
+     * @throws {TypeError} If arguments are invalid
+     */
+    public static fromJSON(name: string, json: IField): Field;
+
+    /** Determines whether this field is packed. Only relevant when repeated and working with proto2. */
+    public readonly packed: boolean;
+
+    /**
+     * Field decorator (TypeScript).
+     * @param fieldId Field id
+     * @param fieldType Field type
+     * @param [fieldRule="optional"] Field rule
+     * @param [defaultValue] Default value
+     * @returns Decorator function
+     */
+    public static d<T extends number | number[] | Long | Long[] | string | string[] | boolean | boolean[] | Uint8Array | Uint8Array[] | Buffer | Buffer[]>(fieldId: number, fieldType: ("double"|"float"|"int32"|"uint32"|"sint32"|"fixed32"|"sfixed32"|"int64"|"uint64"|"sint64"|"fixed64"|"sfixed64"|"string"|"bool"|"bytes"|object), fieldRule?: ("optional"|"required"|"repeated"), defaultValue?: T): FieldDecorator;
+
+    /**
+     * Field decorator (TypeScript).
+     * @param fieldId Field id
+     * @param fieldType Field type
+     * @param [fieldRule="optional"] Field rule
+     * @returns Decorator function
+     */
+    public static d<T extends Message<T>>(fieldId: number, fieldType: (Constructor<T>|string), fieldRule?: ("optional"|"required"|"repeated")): FieldDecorator;
+}
+
+/** Base class of all reflected message fields. This is not an actual class but here for the sake of having consistent type definitions. */
+export class FieldBase extends ReflectionObject {
+
+    /**
+     * Not an actual constructor. Use {@link Field} instead.
+     * @param name Unique name within its namespace
+     * @param id Unique id within its namespace
+     * @param type Value type
+     * @param [rule="optional"] Field rule
+     * @param [extend] Extended type if different from parent
+     * @param [options] Declared options
+     * @param [comment] Comment associated with this field
+     */
+    constructor(name: string, id: number, type: string, rule?: (string|{ [k: string]: any }), extend?: (string|{ [k: string]: any }), options?: { [k: string]: any }, comment?: string);
+
+    /** Field type. */
+    public type: string;
+
+    /** Unique field id. */
+    public id: number;
+
+    /** Extended type if different from parent. */
+    public extend?: string;
+
+    /** Whether this field is required. */
+    public required: boolean;
+
+    /** Whether this field is optional. */
+    public optional: boolean;
+
+    /** Whether this field is repeated. */
+    public repeated: boolean;
+
+    /** Whether this field is a map or not. */
+    public map: boolean;
+
+    /** Message this field belongs to. */
+    public message: (Type|null);
+
+    /** OneOf this field belongs to, if any, */
+    public partOf: (OneOf|null);
+
+    /** The field type's default value. */
+    public typeDefault: any;
+
+    /** The field's default value on prototypes. */
+    public defaultValue: any;
+
+    /** Whether this field's value should be treated as a long. */
+    public long: boolean;
+
+    /** Whether this field's value is a buffer. */
+    public bytes: boolean;
+
+    /** Resolved type if not a basic type. */
+    public resolvedType: (Type|Enum|null);
+
+    /** Sister-field within the extended type if a declaring extension field. */
+    public extensionField: (Field|null);
+
+    /** Sister-field within the declaring namespace if an extended field. */
+    public declaringField: (Field|null);
+
+    /** Comment for this field. */
+    public comment: (string|null);
+
+    /**
+     * Converts this field to a field descriptor.
+     * @param [toJSONOptions] JSON conversion options
+     * @returns Field descriptor
+     */
+    public toJSON(toJSONOptions?: IToJSONOptions): IField;
+
+    /**
+     * Resolves this field's type references.
+     * @returns `this`
+     * @throws {Error} If any reference cannot be resolved
+     */
+    public resolve(): Field;
+}
+
+/** Field descriptor. */
+export interface IField {
+
+    /** Field rule */
+    rule?: string;
+
+    /** Field type */
+    type: string;
+
+    /** Field id */
+    id: number;
+
+    /** Field options */
+    options?: { [k: string]: any };
+}
+
+/** Extension field descriptor. */
+export interface IExtensionField extends IField {
+
+    /** Extended type */
+    extend: string;
+}
+
+/**
+ * Decorator function as returned by {@link Field.d} and {@link MapField.d} (TypeScript).
+ * @param prototype Target prototype
+ * @param fieldName Field name
+ */
+type FieldDecorator = (prototype: object, fieldName: string) => void;
+
+/**
+ * A node-style callback as used by {@link load} and {@link Root#load}.
+ * @param error Error, if any, otherwise `null`
+ * @param [root] Root, if there hasn't been an error
+ */
+type LoadCallback = (error: (Error|null), root?: Root) => void;
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into a common root namespace and calls the callback.
+ * @param filename One or multiple files to load
+ * @param root Root namespace, defaults to create a new one if omitted.
+ * @param callback Callback function
+ * @see {@link Root#load}
+ */
+export function load(filename: (string|string[]), root: Root, callback: LoadCallback): void;
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into a common root namespace and calls the callback.
+ * @param filename One or multiple files to load
+ * @param callback Callback function
+ * @see {@link Root#load}
+ */
+export function load(filename: (string|string[]), callback: LoadCallback): void;
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into a common root namespace and returns a promise.
+ * @param filename One or multiple files to load
+ * @param [root] Root namespace, defaults to create a new one if omitted.
+ * @returns Promise
+ * @see {@link Root#load}
+ */
+export function load(filename: (string|string[]), root?: Root): Promise<Root>;
+
+/**
+ * Synchronously loads one or multiple .proto or preprocessed .json files into a common root namespace (node only).
+ * @param filename One or multiple files to load
+ * @param [root] Root namespace, defaults to create a new one if omitted.
+ * @returns Root namespace
+ * @throws {Error} If synchronous fetching is not supported (i.e. in browsers) or if a file's syntax is invalid
+ * @see {@link Root#loadSync}
+ */
+export function loadSync(filename: (string|string[]), root?: Root): Root;
+
+/** Build type, one of `"full"`, `"light"` or `"minimal"`. */
+export const build: string;
+
+/** Reconfigures the library according to the environment. */
+export function configure(): void;
+
+/** Reflected map field. */
+export class MapField extends FieldBase {
+
+    /**
+     * Constructs a new map field instance.
+     * @param name Unique name within its namespace
+     * @param id Unique id within its namespace
+     * @param keyType Key type
+     * @param type Value type
+     * @param [options] Declared options
+     * @param [comment] Comment associated with this field
+     */
+    constructor(name: string, id: number, keyType: string, type: string, options?: { [k: string]: any }, comment?: string);
+
+    /** Key type. */
+    public keyType: string;
+
+    /** Resolved key type if not a basic type. */
+    public resolvedKeyType: (ReflectionObject|null);
+
+    /**
+     * Constructs a map field from a map field descriptor.
+     * @param name Field name
+     * @param json Map field descriptor
+     * @returns Created map field
+     * @throws {TypeError} If arguments are invalid
+     */
+    public static fromJSON(name: string, json: IMapField): MapField;
+
+    /**
+     * Converts this map field to a map field descriptor.
+     * @param [toJSONOptions] JSON conversion options
+     * @returns Map field descriptor
+     */
+    public toJSON(toJSONOptions?: IToJSONOptions): IMapField;
+
+    /**
+     * Map field decorator (TypeScript).
+     * @param fieldId Field id
+     * @param fieldKeyType Field key type
+     * @param fieldValueType Field value type
+     * @returns Decorator function
+     */
+    public static d<T extends { [key: string]: number | Long | string | boolean | Uint8Array | Buffer | number[] | Message<{}> }>(fieldId: number, fieldKeyType: ("int32"|"uint32"|"sint32"|"fixed32"|"sfixed32"|"int64"|"uint64"|"sint64"|"fixed64"|"sfixed64"|"bool"|"string"), fieldValueType: ("double"|"float"|"int32"|"uint32"|"sint32"|"fixed32"|"sfixed32"|"int64"|"uint64"|"sint64"|"fixed64"|"sfixed64"|"bool"|"string"|"bytes"|object|Constructor<{}>)): FieldDecorator;
+}
+
+/** Map field descriptor. */
+export interface IMapField extends IField {
+
+    /** Key type */
+    keyType: string;
+}
+
+/** Extension map field descriptor. */
+export interface IExtensionMapField extends IMapField {
+
+    /** Extended type */
+    extend: string;
+}
+
+/** Abstract runtime message. */
+export class Message<T extends object = object> {
+
+    /**
+     * Constructs a new message instance.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: Properties<T>);
+
+    /** Reference to the reflected type. */
+    public static readonly $type: Type;
+
+    /** Reference to the reflected type. */
+    public readonly $type: Type;
+
+    /**
+     * Creates a new message of this type using the specified properties.
+     * @param [properties] Properties to set
+     * @returns Message instance
+     */
+    public static create<T extends Message<T>>(this: Constructor<T>, properties?: { [k: string]: any }): Message<T>;
+
+    /**
+     * Encodes a message of this type.
+     * @param message Message to encode
+     * @param [writer] Writer to use
+     * @returns Writer
+     */
+    public static encode<T extends Message<T>>(this: Constructor<T>, message: (T|{ [k: string]: any }), writer?: Writer): Writer;
+
+    /**
+     * Encodes a message of this type preceeded by its length as a varint.
+     * @param message Message to encode
+     * @param [writer] Writer to use
+     * @returns Writer
+     */
+    public static encodeDelimited<T extends Message<T>>(this: Constructor<T>, message: (T|{ [k: string]: any }), writer?: Writer): Writer;
+
+    /**
+     * Decodes a message of this type.
+     * @param reader Reader or buffer to decode
+     * @returns Decoded message
+     */
+    public static decode<T extends Message<T>>(this: Constructor<T>, reader: (Reader|Uint8Array)): T;
+
+    /**
+     * Decodes a message of this type preceeded by its length as a varint.
+     * @param reader Reader or buffer to decode
+     * @returns Decoded message
+     */
+    public static decodeDelimited<T extends Message<T>>(this: Constructor<T>, reader: (Reader|Uint8Array)): T;
+
+    /**
+     * Verifies a message of this type.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a new message of this type from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns Message instance
+     */
+    public static fromObject<T extends Message<T>>(this: Constructor<T>, object: { [k: string]: any }): T;
+
+    /**
+     * Creates a plain object from a message of this type. Also converts values to other types if specified.
+     * @param message Message instance
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject<T extends Message<T>>(this: Constructor<T>, message: T, options?: IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this message to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Reflected service method. */
+export class Method extends ReflectionObject {
+
+    /**
+     * Constructs a new service method instance.
+     * @param name Method name
+     * @param type Method type, usually `"rpc"`
+     * @param requestType Request message type
+     * @param responseType Response message type
+     * @param [requestStream] Whether the request is streamed
+     * @param [responseStream] Whether the response is streamed
+     * @param [options] Declared options
+     * @param [comment] The comment for this method
+     * @param [parsedOptions] Declared options, properly parsed into an object
+     */
+    constructor(name: string, type: (string|undefined), requestType: string, responseType: string, requestStream?: (boolean|{ [k: string]: any }), responseStream?: (boolean|{ [k: string]: any }), options?: { [k: string]: any }, comment?: string, parsedOptions?: { [k: string]: any });
+
+    /** Method type. */
+    public type: string;
+
+    /** Request type. */
+    public requestType: string;
+
+    /** Whether requests are streamed or not. */
+    public requestStream?: boolean;
+
+    /** Response type. */
+    public responseType: string;
+
+    /** Whether responses are streamed or not. */
+    public responseStream?: boolean;
+
+    /** Resolved request type. */
+    public resolvedRequestType: (Type|null);
+
+    /** Resolved response type. */
+    public resolvedResponseType: (Type|null);
+
+    /** Comment for this method */
+    public comment: (string|null);
+
+    /** Options properly parsed into an object */
+    public parsedOptions: any;
+
+    /**
+     * Constructs a method from a method descriptor.
+     * @param name Method name
+     * @param json Method descriptor
+     * @returns Created method
+     * @throws {TypeError} If arguments are invalid
+     */
+    public static fromJSON(name: string, json: IMethod): Method;
+
+    /**
+     * Converts this method to a method descriptor.
+     * @param [toJSONOptions] JSON conversion options
+     * @returns Method descriptor
+     */
+    public toJSON(toJSONOptions?: IToJSONOptions): IMethod;
+}
+
+/** Method descriptor. */
+export interface IMethod {
+
+    /** Method type */
+    type?: string;
+
+    /** Request type */
+    requestType: string;
+
+    /** Response type */
+    responseType: string;
+
+    /** Whether requests are streamed */
+    requestStream?: boolean;
+
+    /** Whether responses are streamed */
+    responseStream?: boolean;
+
+    /** Method options */
+    options?: { [k: string]: any };
+
+    /** Method comments */
+    comment: string;
+
+    /** Method options properly parsed into an object */
+    parsedOptions?: { [k: string]: any };
+}
+
+/** Reflected namespace. */
+export class Namespace extends NamespaceBase {
+
+    /**
+     * Constructs a new namespace instance.
+     * @param name Namespace name
+     * @param [options] Declared options
+     */
+    constructor(name: string, options?: { [k: string]: any });
+
+    /**
+     * Constructs a namespace from JSON.
+     * @param name Namespace name
+     * @param json JSON object
+     * @returns Created namespace
+     * @throws {TypeError} If arguments are invalid
+     */
+    public static fromJSON(name: string, json: { [k: string]: any }): Namespace;
+
+    /**
+     * Converts an array of reflection objects to JSON.
+     * @param array Object array
+     * @param [toJSONOptions] JSON conversion options
+     * @returns JSON object or `undefined` when array is empty
+     */
+    public static arrayToJSON(array: ReflectionObject[], toJSONOptions?: IToJSONOptions): ({ [k: string]: any }|undefined);
+
+    /**
+     * Tests if the specified id is reserved.
+     * @param reserved Array of reserved ranges and names
+     * @param id Id to test
+     * @returns `true` if reserved, otherwise `false`
+     */
+    public static isReservedId(reserved: ((number[]|string)[]|undefined), id: number): boolean;
+
+    /**
+     * Tests if the specified name is reserved.
+     * @param reserved Array of reserved ranges and names
+     * @param name Name to test
+     * @returns `true` if reserved, otherwise `false`
+     */
+    public static isReservedName(reserved: ((number[]|string)[]|undefined), name: string): boolean;
+}
+
+/** Base class of all reflection objects containing nested objects. This is not an actual class but here for the sake of having consistent type definitions. */
+export abstract class NamespaceBase extends ReflectionObject {
+
+    /** Nested objects by name. */
+    public nested?: { [k: string]: ReflectionObject };
+
+    /** Nested objects of this namespace as an array for iteration. */
+    public readonly nestedArray: ReflectionObject[];
+
+    /**
+     * Converts this namespace to a namespace descriptor.
+     * @param [toJSONOptions] JSON conversion options
+     * @returns Namespace descriptor
+     */
+    public toJSON(toJSONOptions?: IToJSONOptions): INamespace;
+
+    /**
+     * Adds nested objects to this namespace from nested object descriptors.
+     * @param nestedJson Any nested object descriptors
+     * @returns `this`
+     */
+    public addJSON(nestedJson: { [k: string]: AnyNestedObject }): Namespace;
+
+    /**
+     * Gets the nested object of the specified name.
+     * @param name Nested object name
+     * @returns The reflection object or `null` if it doesn't exist
+     */
+    public get(name: string): (ReflectionObject|null);
+
+    /**
+     * Gets the values of the nested {@link Enum|enum} of the specified name.
+     * This methods differs from {@link Namespace#get|get} in that it returns an enum's values directly and throws instead of returning `null`.
+     * @param name Nested enum name
+     * @returns Enum values
+     * @throws {Error} If there is no such enum
+     */
+    public getEnum(name: string): { [k: string]: number };
+
+    /**
+     * Adds a nested object to this namespace.
+     * @param object Nested object to add
+     * @returns `this`
+     * @throws {TypeError} If arguments are invalid
+     * @throws {Error} If there is already a nested object with this name
+     */
+    public add(object: ReflectionObject): Namespace;
+
+    /**
+     * Removes a nested object from this namespace.
+     * @param object Nested object to remove
+     * @returns `this`
+     * @throws {TypeError} If arguments are invalid
+     * @throws {Error} If `object` is not a member of this namespace
+     */
+    public remove(object: ReflectionObject): Namespace;
+
+    /**
+     * Defines additial namespaces within this one if not yet existing.
+     * @param path Path to create
+     * @param [json] Nested types to create from JSON
+     * @returns Pointer to the last namespace created or `this` if path is empty
+     */
+    public define(path: (string|string[]), json?: any): Namespace;
+
+    /**
+     * Resolves this namespace's and all its nested objects' type references. Useful to validate a reflection tree, but comes at a cost.
+     * @returns `this`
+     */
+    public resolveAll(): Namespace;
+
+    /**
+     * Recursively looks up the reflection object matching the specified path in the scope of this namespace.
+     * @param path Path to look up
+     * @param filterTypes Filter types, any combination of the constructors of `protobuf.Type`, `protobuf.Enum`, `protobuf.Service` etc.
+     * @param [parentAlreadyChecked=false] If known, whether the parent has already been checked
+     * @returns Looked up object or `null` if none could be found
+     */
+    public lookup(path: (string|string[]), filterTypes: (any|any[]), parentAlreadyChecked?: boolean): (ReflectionObject|null);
+
+    /**
+     * Looks up the reflection object at the specified path, relative to this namespace.
+     * @param path Path to look up
+     * @param [parentAlreadyChecked=false] Whether the parent has already been checked
+     * @returns Looked up object or `null` if none could be found
+     */
+    public lookup(path: (string|string[]), parentAlreadyChecked?: boolean): (ReflectionObject|null);
+
+    /**
+     * Looks up the {@link Type|type} at the specified path, relative to this namespace.
+     * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
+     * @param path Path to look up
+     * @returns Looked up type
+     * @throws {Error} If `path` does not point to a type
+     */
+    public lookupType(path: (string|string[])): Type;
+
+    /**
+     * Looks up the values of the {@link Enum|enum} at the specified path, relative to this namespace.
+     * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
+     * @param path Path to look up
+     * @returns Looked up enum
+     * @throws {Error} If `path` does not point to an enum
+     */
+    public lookupEnum(path: (string|string[])): Enum;
+
+    /**
+     * Looks up the {@link Type|type} or {@link Enum|enum} at the specified path, relative to this namespace.
+     * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
+     * @param path Path to look up
+     * @returns Looked up type or enum
+     * @throws {Error} If `path` does not point to a type or enum
+     */
+    public lookupTypeOrEnum(path: (string|string[])): Type;
+
+    /**
+     * Looks up the {@link Service|service} at the specified path, relative to this namespace.
+     * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
+     * @param path Path to look up
+     * @returns Looked up service
+     * @throws {Error} If `path` does not point to a service
+     */
+    public lookupService(path: (string|string[])): Service;
+}
+
+/** Namespace descriptor. */
+export interface INamespace {
+
+    /** Namespace options */
+    options?: { [k: string]: any };
+
+    /** Nested object descriptors */
+    nested?: { [k: string]: AnyNestedObject };
+}
+
+/** Any extension field descriptor. */
+type AnyExtensionField = (IExtensionField|IExtensionMapField);
+
+/** Any nested object descriptor. */
+type AnyNestedObject = (IEnum|IType|IService|AnyExtensionField|INamespace|IOneOf);
+
+/** Base class of all reflection objects. */
+export abstract class ReflectionObject {
+
+    /** Options. */
+    public options?: { [k: string]: any };
+
+    /** Parsed Options. */
+    public parsedOptions?: { [k: string]: any[] };
+
+    /** Unique name within its namespace. */
+    public name: string;
+
+    /** Parent namespace. */
+    public parent: (Namespace|null);
+
+    /** Whether already resolved or not. */
+    public resolved: boolean;
+
+    /** Comment text, if any. */
+    public comment: (string|null);
+
+    /** Defining file name. */
+    public filename: (string|null);
+
+    /** Reference to the root namespace. */
+    public readonly root: Root;
+
+    /** Full name including leading dot. */
+    public readonly fullName: string;
+
+    /**
+     * Converts this reflection object to its descriptor representation.
+     * @returns Descriptor
+     */
+    public toJSON(): { [k: string]: any };
+
+    /**
+     * Called when this object is added to a parent.
+     * @param parent Parent added to
+     */
+    public onAdd(parent: ReflectionObject): void;
+
+    /**
+     * Called when this object is removed from a parent.
+     * @param parent Parent removed from
+     */
+    public onRemove(parent: ReflectionObject): void;
+
+    /**
+     * Resolves this objects type references.
+     * @returns `this`
+     */
+    public resolve(): ReflectionObject;
+
+    /**
+     * Gets an option value.
+     * @param name Option name
+     * @returns Option value or `undefined` if not set
+     */
+    public getOption(name: string): any;
+
+    /**
+     * Sets an option.
+     * @param name Option name
+     * @param value Option value
+     * @param [ifNotSet] Sets the option only if it isn't currently set
+     * @returns `this`
+     */
+    public setOption(name: string, value: any, ifNotSet?: boolean): ReflectionObject;
+
+    /**
+     * Sets a parsed option.
+     * @param name parsed Option name
+     * @param value Option value
+     * @param propName dot '.' delimited full path of property within the option to set. if undefined\empty, will add a new option with that value
+     * @returns `this`
+     */
+    public setParsedOption(name: string, value: any, propName: string): ReflectionObject;
+
+    /**
+     * Sets multiple options.
+     * @param options Options to set
+     * @param [ifNotSet] Sets an option only if it isn't currently set
+     * @returns `this`
+     */
+    public setOptions(options: { [k: string]: any }, ifNotSet?: boolean): ReflectionObject;
+
+    /**
+     * Converts this instance to its string representation.
+     * @returns Class name[, space, full name]
+     */
+    public toString(): string;
+}
+
+/** Reflected oneof. */
+export class OneOf extends ReflectionObject {
+
+    /**
+     * Constructs a new oneof instance.
+     * @param name Oneof name
+     * @param [fieldNames] Field names
+     * @param [options] Declared options
+     * @param [comment] Comment associated with this field
+     */
+    constructor(name: string, fieldNames?: (string[]|{ [k: string]: any }), options?: { [k: string]: any }, comment?: string);
+
+    /** Field names that belong to this oneof. */
+    public oneof: string[];
+
+    /** Fields that belong to this oneof as an array for iteration. */
+    public readonly fieldsArray: Field[];
+
+    /** Comment for this field. */
+    public comment: (string|null);
+
+    /**
+     * Constructs a oneof from a oneof descriptor.
+     * @param name Oneof name
+     * @param json Oneof descriptor
+     * @returns Created oneof
+     * @throws {TypeError} If arguments are invalid
+     */
+    public static fromJSON(name: string, json: IOneOf): OneOf;
+
+    /**
+     * Converts this oneof to a oneof descriptor.
+     * @param [toJSONOptions] JSON conversion options
+     * @returns Oneof descriptor
+     */
+    public toJSON(toJSONOptions?: IToJSONOptions): IOneOf;
+
+    /**
+     * Adds a field to this oneof and removes it from its current parent, if any.
+     * @param field Field to add
+     * @returns `this`
+     */
+    public add(field: Field): OneOf;
+
+    /**
+     * Removes a field from this oneof and puts it back to the oneof's parent.
+     * @param field Field to remove
+     * @returns `this`
+     */
+    public remove(field: Field): OneOf;
+
+    /**
+     * OneOf decorator (TypeScript).
+     * @param fieldNames Field names
+     * @returns Decorator function
+     */
+    public static d<T extends string>(...fieldNames: string[]): OneOfDecorator;
+}
+
+/** Oneof descriptor. */
+export interface IOneOf {
+
+    /** Oneof field names */
+    oneof: string[];
+
+    /** Oneof options */
+    options?: { [k: string]: any };
+}
+
+/**
+ * Decorator function as returned by {@link OneOf.d} (TypeScript).
+ * @param prototype Target prototype
+ * @param oneofName OneOf name
+ */
+type OneOfDecorator = (prototype: object, oneofName: string) => void;
+
+/**
+ * Parses the given .proto source and returns an object with the parsed contents.
+ * @param source Source contents
+ * @param [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+ * @returns Parser result
+ */
+export function parse(source: string, options?: IParseOptions): IParserResult;
+
+/** Result object returned from {@link parse}. */
+export interface IParserResult {
+
+    /** Package name, if declared */
+    package: (string|undefined);
+
+    /** Imports, if any */
+    imports: (string[]|undefined);
+
+    /** Weak imports, if any */
+    weakImports: (string[]|undefined);
+
+    /** Syntax, if specified (either `"proto2"` or `"proto3"`) */
+    syntax: (string|undefined);
+
+    /** Populated root instance */
+    root: Root;
+}
+
+/** Options modifying the behavior of {@link parse}. */
+export interface IParseOptions {
+
+    /** Keeps field casing instead of converting to camel case */
+    keepCase?: boolean;
+
+    /** Recognize double-slash comments in addition to doc-block comments. */
+    alternateCommentMode?: boolean;
+
+    /** Use trailing comment when both leading comment and trailing comment exist. */
+    preferTrailingComment?: boolean;
+}
+
+/** Options modifying the behavior of JSON serialization. */
+export interface IToJSONOptions {
+
+    /** Serializes comments. */
+    keepComments?: boolean;
+}
+
+/**
+ * Parses the given .proto source and returns an object with the parsed contents.
+ * @param source Source contents
+ * @param root Root to populate
+ * @param [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+ * @returns Parser result
+ */
+export function parse(source: string, root: Root, options?: IParseOptions): IParserResult;
+
+/** Wire format reader using `Uint8Array` if available, otherwise `Array`. */
+export class Reader {
+
+    /**
+     * Constructs a new reader instance using the specified buffer.
+     * @param buffer Buffer to read from
+     */
+    constructor(buffer: Uint8Array);
+
+    /** Read buffer. */
+    public buf: Uint8Array;
+
+    /** Read buffer position. */
+    public pos: number;
+
+    /** Read buffer length. */
+    public len: number;
+
+    /**
+     * Creates a new reader using the specified buffer.
+     * @param buffer Buffer to read from
+     * @returns A {@link BufferReader} if `buffer` is a Buffer, otherwise a {@link Reader}
+     * @throws {Error} If `buffer` is not a valid buffer
+     */
+    public static create(buffer: (Uint8Array|Buffer)): (Reader|BufferReader);
+
+    /**
+     * Reads a varint as an unsigned 32 bit value.
+     * @returns Value read
+     */
+    public uint32(): number;
+
+    /**
+     * Reads a varint as a signed 32 bit value.
+     * @returns Value read
+     */
+    public int32(): number;
+
+    /**
+     * Reads a zig-zag encoded varint as a signed 32 bit value.
+     * @returns Value read
+     */
+    public sint32(): number;
+
+    /**
+     * Reads a varint as a signed 64 bit value.
+     * @returns Value read
+     */
+    public int64(): Long;
+
+    /**
+     * Reads a varint as an unsigned 64 bit value.
+     * @returns Value read
+     */
+    public uint64(): Long;
+
+    /**
+     * Reads a zig-zag encoded varint as a signed 64 bit value.
+     * @returns Value read
+     */
+    public sint64(): Long;
+
+    /**
+     * Reads a varint as a boolean.
+     * @returns Value read
+     */
+    public bool(): boolean;
+
+    /**
+     * Reads fixed 32 bits as an unsigned 32 bit integer.
+     * @returns Value read
+     */
+    public fixed32(): number;
+
+    /**
+     * Reads fixed 32 bits as a signed 32 bit integer.
+     * @returns Value read
+     */
+    public sfixed32(): number;
+
+    /**
+     * Reads fixed 64 bits.
+     * @returns Value read
+     */
+    public fixed64(): Long;
+
+    /**
+     * Reads zig-zag encoded fixed 64 bits.
+     * @returns Value read
+     */
+    public sfixed64(): Long;
+
+    /**
+     * Reads a float (32 bit) as a number.
+     * @returns Value read
+     */
+    public float(): number;
+
+    /**
+     * Reads a double (64 bit float) as a number.
+     * @returns Value read
+     */
+    public double(): number;
+
+    /**
+     * Reads a sequence of bytes preceeded by its length as a varint.
+     * @returns Value read
+     */
+    public bytes(): Uint8Array;
+
+    /**
+     * Reads a string preceeded by its byte length as a varint.
+     * @returns Value read
+     */
+    public string(): string;
+
+    /**
+     * Skips the specified number of bytes if specified, otherwise skips a varint.
+     * @param [length] Length if known, otherwise a varint is assumed
+     * @returns `this`
+     */
+    public skip(length?: number): Reader;
+
+    /**
+     * Skips the next element of the specified wire type.
+     * @param wireType Wire type received
+     * @returns `this`
+     */
+    public skipType(wireType: number): Reader;
+}
+
+/** Wire format reader using node buffers. */
+export class BufferReader extends Reader {
+
+    /**
+     * Constructs a new buffer reader instance.
+     * @param buffer Buffer to read from
+     */
+    constructor(buffer: Buffer);
+
+    /**
+     * Reads a sequence of bytes preceeded by its length as a varint.
+     * @returns Value read
+     */
+    public bytes(): Buffer;
+}
+
+/** Root namespace wrapping all types, enums, services, sub-namespaces etc. that belong together. */
+export class Root extends NamespaceBase {
+
+    /**
+     * Constructs a new root namespace instance.
+     * @param [options] Top level options
+     */
+    constructor(options?: { [k: string]: any });
+
+    /** Deferred extension fields. */
+    public deferred: Field[];
+
+    /** Resolved file names of loaded files. */
+    public files: string[];
+
+    /**
+     * Loads a namespace descriptor into a root namespace.
+     * @param json Nameespace descriptor
+     * @param [root] Root namespace, defaults to create a new one if omitted
+     * @returns Root namespace
+     */
+    public static fromJSON(json: INamespace, root?: Root): Root;
+
+    /**
+     * Resolves the path of an imported file, relative to the importing origin.
+     * This method exists so you can override it with your own logic in case your imports are scattered over multiple directories.
+     * @param origin The file name of the importing file
+     * @param target The file name being imported
+     * @returns Resolved path to `target` or `null` to skip the file
+     */
+    public resolvePath(origin: string, target: string): (string|null);
+
+    /**
+     * Fetch content from file path or url
+     * This method exists so you can override it with your own logic.
+     * @param path File path or url
+     * @param callback Callback function
+     */
+    public fetch(path: string, callback: FetchCallback): void;
+
+    /**
+     * Loads one or multiple .proto or preprocessed .json files into this root namespace and calls the callback.
+     * @param filename Names of one or multiple files to load
+     * @param options Parse options
+     * @param callback Callback function
+     */
+    public load(filename: (string|string[]), options: IParseOptions, callback: LoadCallback): void;
+
+    /**
+     * Loads one or multiple .proto or preprocessed .json files into this root namespace and calls the callback.
+     * @param filename Names of one or multiple files to load
+     * @param callback Callback function
+     */
+    public load(filename: (string|string[]), callback: LoadCallback): void;
+
+    /**
+     * Loads one or multiple .proto or preprocessed .json files into this root namespace and returns a promise.
+     * @param filename Names of one or multiple files to load
+     * @param [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+     * @returns Promise
+     */
+    public load(filename: (string|string[]), options?: IParseOptions): Promise<Root>;
+
+    /**
+     * Synchronously loads one or multiple .proto or preprocessed .json files into this root namespace (node only).
+     * @param filename Names of one or multiple files to load
+     * @param [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+     * @returns Root namespace
+     * @throws {Error} If synchronous fetching is not supported (i.e. in browsers) or if a file's syntax is invalid
+     */
+    public loadSync(filename: (string|string[]), options?: IParseOptions): Root;
+}
+
+/**
+ * Named roots.
+ * This is where pbjs stores generated structures (the option `-r, --root` specifies a name).
+ * Can also be used manually to make roots available across modules.
+ */
+export let roots: { [k: string]: Root };
+
+/** Streaming RPC helpers. */
+export namespace rpc {
+
+    /**
+     * A service method callback as used by {@link rpc.ServiceMethod|ServiceMethod}.
+     *
+     * Differs from {@link RPCImplCallback} in that it is an actual callback of a service method which may not return `response = null`.
+     * @param error Error, if any
+     * @param [response] Response message
+     */
+    type ServiceMethodCallback<TRes extends Message<TRes>> = (error: (Error|null), response?: TRes) => void;
+
+    /**
+     * A service method part of a {@link rpc.Service} as created by {@link Service.create}.
+     * @param request Request message or plain object
+     * @param [callback] Node-style callback called with the error, if any, and the response message
+     * @returns Promise if `callback` has been omitted, otherwise `undefined`
+     */
+    type ServiceMethod<TReq extends Message<TReq>, TRes extends Message<TRes>> = (request: (TReq|Properties<TReq>), callback?: rpc.ServiceMethodCallback<TRes>) => Promise<Message<TRes>>;
+
+    /** An RPC service as returned by {@link Service#create}. */
+    class Service extends util.EventEmitter {
+
+        /**
+         * Constructs a new RPC service instance.
+         * @param rpcImpl RPC implementation
+         * @param [requestDelimited=false] Whether requests are length-delimited
+         * @param [responseDelimited=false] Whether responses are length-delimited
+         */
+        constructor(rpcImpl: RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean);
+
+        /** RPC implementation. Becomes `null` once the service is ended. */
+        public rpcImpl: (RPCImpl|null);
+
+        /** Whether requests are length-delimited. */
+        public requestDelimited: boolean;
+
+        /** Whether responses are length-delimited. */
+        public responseDelimited: boolean;
+
+        /**
+         * Calls a service method through {@link rpc.Service#rpcImpl|rpcImpl}.
+         * @param method Reflected or static method
+         * @param requestCtor Request constructor
+         * @param responseCtor Response constructor
+         * @param request Request message or plain object
+         * @param callback Service callback
+         */
+        public rpcCall<TReq extends Message<TReq>, TRes extends Message<TRes>>(method: (Method|rpc.ServiceMethod<TReq, TRes>), requestCtor: Constructor<TReq>, responseCtor: Constructor<TRes>, request: (TReq|Properties<TReq>), callback: rpc.ServiceMethodCallback<TRes>): void;
+
+        /**
+         * Ends this service and emits the `end` event.
+         * @param [endedByRPC=false] Whether the service has been ended by the RPC implementation.
+         * @returns `this`
+         */
+        public end(endedByRPC?: boolean): rpc.Service;
+    }
+}
+
+/**
+ * RPC implementation passed to {@link Service#create} performing a service request on network level, i.e. by utilizing http requests or websockets.
+ * @param method Reflected or static method being called
+ * @param requestData Request data
+ * @param callback Callback function
+ */
+type RPCImpl = (method: (Method|rpc.ServiceMethod<Message<{}>, Message<{}>>), requestData: Uint8Array, callback: RPCImplCallback) => void;
+
+/**
+ * Node-style callback as used by {@link RPCImpl}.
+ * @param error Error, if any, otherwise `null`
+ * @param [response] Response data or `null` to signal end of stream, if there hasn't been an error
+ */
+type RPCImplCallback = (error: (Error|null), response?: (Uint8Array|null)) => void;
+
+/** Reflected service. */
+export class Service extends NamespaceBase {
+
+    /**
+     * Constructs a new service instance.
+     * @param name Service name
+     * @param [options] Service options
+     * @throws {TypeError} If arguments are invalid
+     */
+    constructor(name: string, options?: { [k: string]: any });
+
+    /** Service methods. */
+    public methods: { [k: string]: Method };
+
+    /**
+     * Constructs a service from a service descriptor.
+     * @param name Service name
+     * @param json Service descriptor
+     * @returns Created service
+     * @throws {TypeError} If arguments are invalid
+     */
+    public static fromJSON(name: string, json: IService): Service;
+
+    /**
+     * Converts this service to a service descriptor.
+     * @param [toJSONOptions] JSON conversion options
+     * @returns Service descriptor
+     */
+    public toJSON(toJSONOptions?: IToJSONOptions): IService;
+
+    /** Methods of this service as an array for iteration. */
+    public readonly methodsArray: Method[];
+
+    /**
+     * Creates a runtime service using the specified rpc implementation.
+     * @param rpcImpl RPC implementation
+     * @param [requestDelimited=false] Whether requests are length-delimited
+     * @param [responseDelimited=false] Whether responses are length-delimited
+     * @returns RPC service. Useful where requests and/or responses are streamed.
+     */
+    public create(rpcImpl: RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean): rpc.Service;
+}
+
+/** Service descriptor. */
+export interface IService extends INamespace {
+
+    /** Method descriptors */
+    methods: { [k: string]: IMethod };
+}
+
+/**
+ * Gets the next token and advances.
+ * @returns Next token or `null` on eof
+ */
+type TokenizerHandleNext = () => (string|null);
+
+/**
+ * Peeks for the next token.
+ * @returns Next token or `null` on eof
+ */
+type TokenizerHandlePeek = () => (string|null);
+
+/**
+ * Pushes a token back to the stack.
+ * @param token Token
+ */
+type TokenizerHandlePush = (token: string) => void;
+
+/**
+ * Skips the next token.
+ * @param expected Expected token
+ * @param [optional=false] If optional
+ * @returns Whether the token matched
+ * @throws {Error} If the token didn't match and is not optional
+ */
+type TokenizerHandleSkip = (expected: string, optional?: boolean) => boolean;
+
+/**
+ * Gets the comment on the previous line or, alternatively, the line comment on the specified line.
+ * @param [line] Line number
+ * @returns Comment text or `null` if none
+ */
+type TokenizerHandleCmnt = (line?: number) => (string|null);
+
+/** Handle object returned from {@link tokenize}. */
+export interface ITokenizerHandle {
+
+    /** Gets the next token and advances (`null` on eof) */
+    next: TokenizerHandleNext;
+
+    /** Peeks for the next token (`null` on eof) */
+    peek: TokenizerHandlePeek;
+
+    /** Pushes a token back to the stack */
+    push: TokenizerHandlePush;
+
+    /** Skips a token, returns its presence and advances or, if non-optional and not present, throws */
+    skip: TokenizerHandleSkip;
+
+    /** Gets the comment on the previous line or the line comment on the specified line, if any */
+    cmnt: TokenizerHandleCmnt;
+
+    /** Current line number */
+    line: number;
+}
+
+/**
+ * Tokenizes the given .proto source and returns an object with useful utility functions.
+ * @param source Source contents
+ * @param alternateCommentMode Whether we should activate alternate comment parsing mode.
+ * @returns Tokenizer handle
+ */
+export function tokenize(source: string, alternateCommentMode: boolean): ITokenizerHandle;
+
+export namespace tokenize {
+
+    /**
+     * Unescapes a string.
+     * @param str String to unescape
+     * @returns Unescaped string
+     */
+    function unescape(str: string): string;
+}
+
+/** Reflected message type. */
+export class Type extends NamespaceBase {
+
+    /**
+     * Constructs a new reflected message type instance.
+     * @param name Message name
+     * @param [options] Declared options
+     */
+    constructor(name: string, options?: { [k: string]: any });
+
+    /** Message fields. */
+    public fields: { [k: string]: Field };
+
+    /** Oneofs declared within this namespace, if any. */
+    public oneofs: { [k: string]: OneOf };
+
+    /** Extension ranges, if any. */
+    public extensions: number[][];
+
+    /** Reserved ranges, if any. */
+    public reserved: (number[]|string)[];
+
+    /** Message fields by id. */
+    public readonly fieldsById: { [k: number]: Field };
+
+    /** Fields of this message as an array for iteration. */
+    public readonly fieldsArray: Field[];
+
+    /** Oneofs of this message as an array for iteration. */
+    public readonly oneofsArray: OneOf[];
+
+    /**
+     * The registered constructor, if any registered, otherwise a generic constructor.
+     * Assigning a function replaces the internal constructor. If the function does not extend {@link Message} yet, its prototype will be setup accordingly and static methods will be populated. If it already extends {@link Message}, it will just replace the internal constructor.
+     */
+    public ctor: Constructor<{}>;
+
+    /**
+     * Generates a constructor function for the specified type.
+     * @param mtype Message type
+     * @returns Codegen instance
+     */
+    public static generateConstructor(mtype: Type): Codegen;
+
+    /**
+     * Creates a message type from a message type descriptor.
+     * @param name Message name
+     * @param json Message type descriptor
+     * @returns Created message type
+     */
+    public static fromJSON(name: string, json: IType): Type;
+
+    /**
+     * Converts this message type to a message type descriptor.
+     * @param [toJSONOptions] JSON conversion options
+     * @returns Message type descriptor
+     */
+    public toJSON(toJSONOptions?: IToJSONOptions): IType;
+
+    /**
+     * Adds a nested object to this type.
+     * @param object Nested object to add
+     * @returns `this`
+     * @throws {TypeError} If arguments are invalid
+     * @throws {Error} If there is already a nested object with this name or, if a field, when there is already a field with this id
+     */
+    public add(object: ReflectionObject): Type;
+
+    /**
+     * Removes a nested object from this type.
+     * @param object Nested object to remove
+     * @returns `this`
+     * @throws {TypeError} If arguments are invalid
+     * @throws {Error} If `object` is not a member of this type
+     */
+    public remove(object: ReflectionObject): Type;
+
+    /**
+     * Tests if the specified id is reserved.
+     * @param id Id to test
+     * @returns `true` if reserved, otherwise `false`
+     */
+    public isReservedId(id: number): boolean;
+
+    /**
+     * Tests if the specified name is reserved.
+     * @param name Name to test
+     * @returns `true` if reserved, otherwise `false`
+     */
+    public isReservedName(name: string): boolean;
+
+    /**
+     * Creates a new message of this type using the specified properties.
+     * @param [properties] Properties to set
+     * @returns Message instance
+     */
+    public create(properties?: { [k: string]: any }): Message<{}>;
+
+    /**
+     * Sets up {@link Type#encode|encode}, {@link Type#decode|decode} and {@link Type#verify|verify}.
+     * @returns `this`
+     */
+    public setup(): Type;
+
+    /**
+     * Encodes a message of this type. Does not implicitly {@link Type#verify|verify} messages.
+     * @param message Message instance or plain object
+     * @param [writer] Writer to encode to
+     * @returns writer
+     */
+    public encode(message: (Message<{}>|{ [k: string]: any }), writer?: Writer): Writer;
+
+    /**
+     * Encodes a message of this type preceeded by its byte length as a varint. Does not implicitly {@link Type#verify|verify} messages.
+     * @param message Message instance or plain object
+     * @param [writer] Writer to encode to
+     * @returns writer
+     */
+    public encodeDelimited(message: (Message<{}>|{ [k: string]: any }), writer?: Writer): Writer;
+
+    /**
+     * Decodes a message of this type.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Length of the message, if known beforehand
+     * @returns Decoded message
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {util.ProtocolError<{}>} If required fields are missing
+     */
+    public decode(reader: (Reader|Uint8Array), length?: number): Message<{}>;
+
+    /**
+     * Decodes a message of this type preceeded by its byte length as a varint.
+     * @param reader Reader or buffer to decode from
+     * @returns Decoded message
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {util.ProtocolError} If required fields are missing
+     */
+    public decodeDelimited(reader: (Reader|Uint8Array)): Message<{}>;
+
+    /**
+     * Verifies that field values are valid and that required fields are present.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public verify(message: { [k: string]: any }): (null|string);
+
+    /**
+     * Creates a new message of this type from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object to convert
+     * @returns Message instance
+     */
+    public fromObject(object: { [k: string]: any }): Message<{}>;
+
+    /**
+     * Creates a plain object from a message of this type. Also converts values to other types if specified.
+     * @param message Message instance
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public toObject(message: Message<{}>, options?: IConversionOptions): { [k: string]: any };
+
+    /**
+     * Type decorator (TypeScript).
+     * @param [typeName] Type name, defaults to the constructor's name
+     * @returns Decorator function
+     */
+    public static d<T extends Message<T>>(typeName?: string): TypeDecorator<T>;
+}
+
+/** Message type descriptor. */
+export interface IType extends INamespace {
+
+    /** Oneof descriptors */
+    oneofs?: { [k: string]: IOneOf };
+
+    /** Field descriptors */
+    fields: { [k: string]: IField };
+
+    /** Extension ranges */
+    extensions?: number[][];
+
+    /** Reserved ranges */
+    reserved?: number[][];
+
+    /** Whether a legacy group or not */
+    group?: boolean;
+}
+
+/** Conversion options as used by {@link Type#toObject} and {@link Message.toObject}. */
+export interface IConversionOptions {
+
+    /**
+     * Long conversion type.
+     * Valid values are `String` and `Number` (the global types).
+     * Defaults to copy the present value, which is a possibly unsafe number without and a {@link Long} with a long library.
+     */
+    longs?: Function;
+
+    /**
+     * Enum value conversion type.
+     * Only valid value is `String` (the global type).
+     * Defaults to copy the present value, which is the numeric id.
+     */
+    enums?: Function;
+
+    /**
+     * Bytes value conversion type.
+     * Valid values are `Array` and (a base64 encoded) `String` (the global types).
+     * Defaults to copy the present value, which usually is a Buffer under node and an Uint8Array in the browser.
+     */
+    bytes?: Function;
+
+    /** Also sets default values on the resulting object */
+    defaults?: boolean;
+
+    /** Sets empty arrays for missing repeated fields even if `defaults=false` */
+    arrays?: boolean;
+
+    /** Sets empty objects for missing map fields even if `defaults=false` */
+    objects?: boolean;
+
+    /** Includes virtual oneof properties set to the present field's name, if any */
+    oneofs?: boolean;
+
+    /** Performs additional JSON compatibility conversions, i.e. NaN and Infinity to strings */
+    json?: boolean;
+}
+
+/**
+ * Decorator function as returned by {@link Type.d} (TypeScript).
+ * @param target Target constructor
+ */
+type TypeDecorator<T extends Message<T>> = (target: Constructor<T>) => void;
+
+/** Common type constants. */
+export namespace types {
+
+    /** Basic type wire types. */
+    const basic: {
+        "double": number,
+        "float": number,
+        "int32": number,
+        "uint32": number,
+        "sint32": number,
+        "fixed32": number,
+        "sfixed32": number,
+        "int64": number,
+        "uint64": number,
+        "sint64": number,
+        "fixed64": number,
+        "sfixed64": number,
+        "bool": number,
+        "string": number,
+        "bytes": number
+    };
+
+    /** Basic type defaults. */
+    const defaults: {
+        "double": number,
+        "float": number,
+        "int32": number,
+        "uint32": number,
+        "sint32": number,
+        "fixed32": number,
+        "sfixed32": number,
+        "int64": number,
+        "uint64": number,
+        "sint64": number,
+        "fixed64": number,
+        "sfixed64": number,
+        "bool": boolean,
+        "string": string,
+        "bytes": number[],
+        "message": null
+    };
+
+    /** Basic long type wire types. */
+    const long: {
+        "int64": number,
+        "uint64": number,
+        "sint64": number,
+        "fixed64": number,
+        "sfixed64": number
+    };
+
+    /** Allowed types for map keys with their associated wire type. */
+    const mapKey: {
+        "int32": number,
+        "uint32": number,
+        "sint32": number,
+        "fixed32": number,
+        "sfixed32": number,
+        "int64": number,
+        "uint64": number,
+        "sint64": number,
+        "fixed64": number,
+        "sfixed64": number,
+        "bool": number,
+        "string": number
+    };
+
+    /** Allowed types for packed repeated fields with their associated wire type. */
+    const packed: {
+        "double": number,
+        "float": number,
+        "int32": number,
+        "uint32": number,
+        "sint32": number,
+        "fixed32": number,
+        "sfixed32": number,
+        "int64": number,
+        "uint64": number,
+        "sint64": number,
+        "fixed64": number,
+        "sfixed64": number,
+        "bool": number
+    };
+}
+
+/** Constructor type. */
+export interface Constructor<T> extends Function {
+    new(...params: any[]): T; prototype: T;
+}
+
+/** Properties type. */
+type Properties<T> = { [P in keyof T]?: T[P] };
+
+/**
+ * Any compatible Buffer instance.
+ * This is a minimal stand-alone definition of a Buffer instance. The actual type is that exported by node's typings.
+ */
+export interface Buffer extends Uint8Array {
+}
+
+/**
+ * Any compatible Long instance.
+ * This is a minimal stand-alone definition of a Long instance. The actual type is that exported by long.js.
+ */
+export interface Long {
+
+    /** Low bits */
+    low: number;
+
+    /** High bits */
+    high: number;
+
+    /** Whether unsigned or not */
+    unsigned: boolean;
+}
+
+/**
+ * A OneOf getter as returned by {@link util.oneOfGetter}.
+ * @returns Set field name, if any
+ */
+type OneOfGetter = () => (string|undefined);
+
+/**
+ * A OneOf setter as returned by {@link util.oneOfSetter}.
+ * @param value Field name
+ */
+type OneOfSetter = (value: (string|undefined)) => void;
+
+/** Various utility functions. */
+export namespace util {
+
+    /** Helper class for working with the low and high bits of a 64 bit value. */
+    class LongBits {
+
+        /**
+         * Constructs new long bits.
+         * @param lo Low 32 bits, unsigned
+         * @param hi High 32 bits, unsigned
+         */
+        constructor(lo: number, hi: number);
+
+        /** Low bits. */
+        public lo: number;
+
+        /** High bits. */
+        public hi: number;
+
+        /** Zero bits. */
+        public static zero: util.LongBits;
+
+        /** Zero hash. */
+        public static zeroHash: string;
+
+        /**
+         * Constructs new long bits from the specified number.
+         * @param value Value
+         * @returns Instance
+         */
+        public static fromNumber(value: number): util.LongBits;
+
+        /**
+         * Constructs new long bits from a number, long or string.
+         * @param value Value
+         * @returns Instance
+         */
+        public static from(value: (Long|number|string)): util.LongBits;
+
+        /**
+         * Converts this long bits to a possibly unsafe JavaScript number.
+         * @param [unsigned=false] Whether unsigned or not
+         * @returns Possibly unsafe number
+         */
+        public toNumber(unsigned?: boolean): number;
+
+        /**
+         * Converts this long bits to a long.
+         * @param [unsigned=false] Whether unsigned or not
+         * @returns Long
+         */
+        public toLong(unsigned?: boolean): Long;
+
+        /**
+         * Constructs new long bits from the specified 8 characters long hash.
+         * @param hash Hash
+         * @returns Bits
+         */
+        public static fromHash(hash: string): util.LongBits;
+
+        /**
+         * Converts this long bits to a 8 characters long hash.
+         * @returns Hash
+         */
+        public toHash(): string;
+
+        /**
+         * Zig-zag encodes this long bits.
+         * @returns `this`
+         */
+        public zzEncode(): util.LongBits;
+
+        /**
+         * Zig-zag decodes this long bits.
+         * @returns `this`
+         */
+        public zzDecode(): util.LongBits;
+
+        /**
+         * Calculates the length of this longbits when encoded as a varint.
+         * @returns Length
+         */
+        public length(): number;
+    }
+
+    /** Whether running within node or not. */
+    let isNode: boolean;
+
+    /** Global object reference. */
+    let global: object;
+
+    /** An immuable empty array. */
+    const emptyArray: any[];
+
+    /** An immutable empty object. */
+    const emptyObject: object;
+
+    /**
+     * Tests if the specified value is an integer.
+     * @param value Value to test
+     * @returns `true` if the value is an integer
+     */
+    function isInteger(value: any): boolean;
+
+    /**
+     * Tests if the specified value is a string.
+     * @param value Value to test
+     * @returns `true` if the value is a string
+     */
+    function isString(value: any): boolean;
+
+    /**
+     * Tests if the specified value is a non-null object.
+     * @param value Value to test
+     * @returns `true` if the value is a non-null object
+     */
+    function isObject(value: any): boolean;
+
+    /**
+     * Checks if a property on a message is considered to be present.
+     * This is an alias of {@link util.isSet}.
+     * @param obj Plain object or message instance
+     * @param prop Property name
+     * @returns `true` if considered to be present, otherwise `false`
+     */
+    function isset(obj: object, prop: string): boolean;
+
+    /**
+     * Checks if a property on a message is considered to be present.
+     * @param obj Plain object or message instance
+     * @param prop Property name
+     * @returns `true` if considered to be present, otherwise `false`
+     */
+    function isSet(obj: object, prop: string): boolean;
+
+    /** Node's Buffer class if available. */
+    let Buffer: Constructor<Buffer>;
+
+    /**
+     * Creates a new buffer of whatever type supported by the environment.
+     * @param [sizeOrArray=0] Buffer size or number array
+     * @returns Buffer
+     */
+    function newBuffer(sizeOrArray?: (number|number[])): (Uint8Array|Buffer);
+
+    /** Array implementation used in the browser. `Uint8Array` if supported, otherwise `Array`. */
+    let Array: Constructor<Uint8Array>;
+
+    /** Long.js's Long class if available. */
+    let Long: Constructor<Long>;
+
+    /** Regular expression used to verify 2 bit (`bool`) map keys. */
+    const key2Re: RegExp;
+
+    /** Regular expression used to verify 32 bit (`int32` etc.) map keys. */
+    const key32Re: RegExp;
+
+    /** Regular expression used to verify 64 bit (`int64` etc.) map keys. */
+    const key64Re: RegExp;
+
+    /**
+     * Converts a number or long to an 8 characters long hash string.
+     * @param value Value to convert
+     * @returns Hash
+     */
+    function longToHash(value: (Long|number)): string;
+
+    /**
+     * Converts an 8 characters long hash string to a long or number.
+     * @param hash Hash
+     * @param [unsigned=false] Whether unsigned or not
+     * @returns Original value
+     */
+    function longFromHash(hash: string, unsigned?: boolean): (Long|number);
+
+    /**
+     * Merges the properties of the source object into the destination object.
+     * @param dst Destination object
+     * @param src Source object
+     * @param [ifNotSet=false] Merges only if the key is not already set
+     * @returns Destination object
+     */
+    function merge(dst: { [k: string]: any }, src: { [k: string]: any }, ifNotSet?: boolean): { [k: string]: any };
+
+    /**
+     * Converts the first character of a string to lower case.
+     * @param str String to convert
+     * @returns Converted string
+     */
+    function lcFirst(str: string): string;
+
+    /**
+     * Creates a custom error constructor.
+     * @param name Error name
+     * @returns Custom error constructor
+     */
+    function newError(name: string): Constructor<Error>;
+
+    /** Error subclass indicating a protocol specifc error. */
+    class ProtocolError<T extends Message<T>> extends Error {
+
+        /**
+         * Constructs a new protocol error.
+         * @param message Error message
+         * @param [properties] Additional properties
+         */
+        constructor(message: string, properties?: { [k: string]: any });
+
+        /** So far decoded message instance. */
+        public instance: Message<T>;
+    }
+
+    /**
+     * Builds a getter for a oneof's present field name.
+     * @param fieldNames Field names
+     * @returns Unbound getter
+     */
+    function oneOfGetter(fieldNames: string[]): OneOfGetter;
+
+    /**
+     * Builds a setter for a oneof's present field name.
+     * @param fieldNames Field names
+     * @returns Unbound setter
+     */
+    function oneOfSetter(fieldNames: string[]): OneOfSetter;
+
+    /**
+     * Default conversion options used for {@link Message#toJSON} implementations.
+     *
+     * These options are close to proto3's JSON mapping with the exception that internal types like Any are handled just like messages. More precisely:
+     *
+     * - Longs become strings
+     * - Enums become string keys
+     * - Bytes become base64 encoded strings
+     * - (Sub-)Messages become plain objects
+     * - Maps become plain objects with all string keys
+     * - Repeated fields become arrays
+     * - NaN and Infinity for float and double fields become strings
+     *
+     * @see https://developers.google.com/protocol-buffers/docs/proto3?hl=en#json
+     */
+    let toJSONOptions: IConversionOptions;
+
+    /** Node's fs module if available. */
+    let fs: { [k: string]: any };
+
+    /**
+     * Converts an object's values to an array.
+     * @param object Object to convert
+     * @returns Converted array
+     */
+    function toArray(object: { [k: string]: any }): any[];
+
+    /**
+     * Converts an array of keys immediately followed by their respective value to an object, omitting undefined values.
+     * @param array Array to convert
+     * @returns Converted object
+     */
+    function toObject(array: any[]): { [k: string]: any };
+
+    /**
+     * Tests whether the specified name is a reserved word in JS.
+     * @param name Name to test
+     * @returns `true` if reserved, otherwise `false`
+     */
+    function isReserved(name: string): boolean;
+
+    /**
+     * Returns a safe property accessor for the specified property name.
+     * @param prop Property name
+     * @returns Safe accessor
+     */
+    function safeProp(prop: string): string;
+
+    /**
+     * Converts the first character of a string to upper case.
+     * @param str String to convert
+     * @returns Converted string
+     */
+    function ucFirst(str: string): string;
+
+    /**
+     * Converts a string to camel case.
+     * @param str String to convert
+     * @returns Converted string
+     */
+    function camelCase(str: string): string;
+
+    /**
+     * Compares reflected fields by id.
+     * @param a First field
+     * @param b Second field
+     * @returns Comparison value
+     */
+    function compareFieldsById(a: Field, b: Field): number;
+
+    /**
+     * Decorator helper for types (TypeScript).
+     * @param ctor Constructor function
+     * @param [typeName] Type name, defaults to the constructor's name
+     * @returns Reflected type
+     */
+    function decorateType<T extends Message<T>>(ctor: Constructor<T>, typeName?: string): Type;
+
+    /**
+     * Decorator helper for enums (TypeScript).
+     * @param object Enum object
+     * @returns Reflected enum
+     */
+    function decorateEnum(object: object): Enum;
+
+    /**
+     * Sets the value of a property by property path. If a value already exists, it is turned to an array
+     * @param dst Destination object
+     * @param path dot '.' delimited path of the property to set
+     * @param value the value to set
+     * @returns Destination object
+     */
+    function setProperty(dst: { [k: string]: any }, path: string, value: object): { [k: string]: any };
+
+    /** Decorator root (TypeScript). */
+    let decorateRoot: Root;
+
+    /**
+     * Returns a promise from a node-style callback function.
+     * @param fn Function to call
+     * @param ctx Function context
+     * @param params Function arguments
+     * @returns Promisified function
+     */
+    function asPromise(fn: asPromiseCallback, ctx: any, ...params: any[]): Promise<any>;
+
+    /** A minimal base64 implementation for number arrays. */
+    namespace base64 {
+
+        /**
+         * Calculates the byte length of a base64 encoded string.
+         * @param string Base64 encoded string
+         * @returns Byte length
+         */
+        function length(string: string): number;
+
+        /**
+         * Encodes a buffer to a base64 encoded string.
+         * @param buffer Source buffer
+         * @param start Source start
+         * @param end Source end
+         * @returns Base64 encoded string
+         */
+        function encode(buffer: Uint8Array, start: number, end: number): string;
+
+        /**
+         * Decodes a base64 encoded string to a buffer.
+         * @param string Source string
+         * @param buffer Destination buffer
+         * @param offset Destination offset
+         * @returns Number of bytes written
+         * @throws {Error} If encoding is invalid
+         */
+        function decode(string: string, buffer: Uint8Array, offset: number): number;
+
+        /**
+         * Tests if the specified string appears to be base64 encoded.
+         * @param string String to test
+         * @returns `true` if probably base64 encoded, otherwise false
+         */
+        function test(string: string): boolean;
+    }
+
+    /**
+     * Begins generating a function.
+     * @param functionParams Function parameter names
+     * @param [functionName] Function name if not anonymous
+     * @returns Appender that appends code to the function's body
+     */
+    function codegen(functionParams: string[], functionName?: string): Codegen;
+
+    namespace codegen {
+
+        /** When set to `true`, codegen will log generated code to console. Useful for debugging. */
+        let verbose: boolean;
+    }
+
+    /**
+     * Begins generating a function.
+     * @param [functionName] Function name if not anonymous
+     * @returns Appender that appends code to the function's body
+     */
+    function codegen(functionName?: string): Codegen;
+
+    /** A minimal event emitter. */
+    class EventEmitter {
+
+        /** Constructs a new event emitter instance. */
+        constructor();
+
+        /**
+         * Registers an event listener.
+         * @param evt Event name
+         * @param fn Listener
+         * @param [ctx] Listener context
+         * @returns `this`
+         */
+        public on(evt: string, fn: EventEmitterListener, ctx?: any): this;
+
+        /**
+         * Removes an event listener or any matching listeners if arguments are omitted.
+         * @param [evt] Event name. Removes all listeners if omitted.
+         * @param [fn] Listener to remove. Removes all listeners of `evt` if omitted.
+         * @returns `this`
+         */
+        public off(evt?: string, fn?: EventEmitterListener): this;
+
+        /**
+         * Emits an event by calling its listeners with the specified arguments.
+         * @param evt Event name
+         * @param args Arguments
+         * @returns `this`
+         */
+        public emit(evt: string, ...args: any[]): this;
+    }
+
+    /** Reads / writes floats / doubles from / to buffers. */
+    namespace float {
+
+        /**
+         * Writes a 32 bit float to a buffer using little endian byte order.
+         * @param val Value to write
+         * @param buf Target buffer
+         * @param pos Target buffer offset
+         */
+        function writeFloatLE(val: number, buf: Uint8Array, pos: number): void;
+
+        /**
+         * Writes a 32 bit float to a buffer using big endian byte order.
+         * @param val Value to write
+         * @param buf Target buffer
+         * @param pos Target buffer offset
+         */
+        function writeFloatBE(val: number, buf: Uint8Array, pos: number): void;
+
+        /**
+         * Reads a 32 bit float from a buffer using little endian byte order.
+         * @param buf Source buffer
+         * @param pos Source buffer offset
+         * @returns Value read
+         */
+        function readFloatLE(buf: Uint8Array, pos: number): number;
+
+        /**
+         * Reads a 32 bit float from a buffer using big endian byte order.
+         * @param buf Source buffer
+         * @param pos Source buffer offset
+         * @returns Value read
+         */
+        function readFloatBE(buf: Uint8Array, pos: number): number;
+
+        /**
+         * Writes a 64 bit double to a buffer using little endian byte order.
+         * @param val Value to write
+         * @param buf Target buffer
+         * @param pos Target buffer offset
+         */
+        function writeDoubleLE(val: number, buf: Uint8Array, pos: number): void;
+
+        /**
+         * Writes a 64 bit double to a buffer using big endian byte order.
+         * @param val Value to write
+         * @param buf Target buffer
+         * @param pos Target buffer offset
+         */
+        function writeDoubleBE(val: number, buf: Uint8Array, pos: number): void;
+
+        /**
+         * Reads a 64 bit double from a buffer using little endian byte order.
+         * @param buf Source buffer
+         * @param pos Source buffer offset
+         * @returns Value read
+         */
+        function readDoubleLE(buf: Uint8Array, pos: number): number;
+
+        /**
+         * Reads a 64 bit double from a buffer using big endian byte order.
+         * @param buf Source buffer
+         * @param pos Source buffer offset
+         * @returns Value read
+         */
+        function readDoubleBE(buf: Uint8Array, pos: number): number;
+    }
+
+    /**
+     * Fetches the contents of a file.
+     * @param filename File path or url
+     * @param options Fetch options
+     * @param callback Callback function
+     */
+    function fetch(filename: string, options: IFetchOptions, callback: FetchCallback): void;
+
+    /**
+     * Fetches the contents of a file.
+     * @param path File path or url
+     * @param callback Callback function
+     */
+    function fetch(path: string, callback: FetchCallback): void;
+
+    /**
+     * Fetches the contents of a file.
+     * @param path File path or url
+     * @param [options] Fetch options
+     * @returns Promise
+     */
+    function fetch(path: string, options?: IFetchOptions): Promise<(string|Uint8Array)>;
+
+    /**
+     * Requires a module only if available.
+     * @param moduleName Module to require
+     * @returns Required module if available and not empty, otherwise `null`
+     */
+    function inquire(moduleName: string): object;
+
+    /** A minimal path module to resolve Unix, Windows and URL paths alike. */
+    namespace path {
+
+        /**
+         * Tests if the specified path is absolute.
+         * @param path Path to test
+         * @returns `true` if path is absolute
+         */
+        function isAbsolute(path: string): boolean;
+
+        /**
+         * Normalizes the specified path.
+         * @param path Path to normalize
+         * @returns Normalized path
+         */
+        function normalize(path: string): string;
+
+        /**
+         * Resolves the specified include path against the specified origin path.
+         * @param originPath Path to the origin file
+         * @param includePath Include path relative to origin path
+         * @param [alreadyNormalized=false] `true` if both paths are already known to be normalized
+         * @returns Path to the include file
+         */
+        function resolve(originPath: string, includePath: string, alreadyNormalized?: boolean): string;
+    }
+
+    /**
+     * A general purpose buffer pool.
+     * @param alloc Allocator
+     * @param slice Slicer
+     * @param [size=8192] Slab size
+     * @returns Pooled allocator
+     */
+    function pool(alloc: PoolAllocator, slice: PoolSlicer, size?: number): PoolAllocator;
+
+    /** A minimal UTF8 implementation for number arrays. */
+    namespace utf8 {
+
+        /**
+         * Calculates the UTF8 byte length of a string.
+         * @param string String
+         * @returns Byte length
+         */
+        function length(string: string): number;
+
+        /**
+         * Reads UTF8 bytes as a string.
+         * @param buffer Source buffer
+         * @param start Source start
+         * @param end Source end
+         * @returns String read
+         */
+        function read(buffer: Uint8Array, start: number, end: number): string;
+
+        /**
+         * Writes a string as UTF8 bytes.
+         * @param string Source string
+         * @param buffer Destination buffer
+         * @param offset Destination offset
+         * @returns Bytes written
+         */
+        function write(string: string, buffer: Uint8Array, offset: number): number;
+    }
+}
+
+/**
+ * Generates a verifier specific to the specified message type.
+ * @param mtype Message type
+ * @returns Codegen instance
+ */
+export function verifier(mtype: Type): Codegen;
+
+/** Wrappers for common types. */
+export const wrappers: { [k: string]: IWrapper };
+
+/**
+ * From object converter part of an {@link IWrapper}.
+ * @param object Plain object
+ * @returns Message instance
+ */
+type WrapperFromObjectConverter = (this: Type, object: { [k: string]: any }) => Message<{}>;
+
+/**
+ * To object converter part of an {@link IWrapper}.
+ * @param message Message instance
+ * @param [options] Conversion options
+ * @returns Plain object
+ */
+type WrapperToObjectConverter = (this: Type, message: Message<{}>, options?: IConversionOptions) => { [k: string]: any };
+
+/** Common type wrapper part of {@link wrappers}. */
+export interface IWrapper {
+
+    /** From object converter */
+    fromObject?: WrapperFromObjectConverter;
+
+    /** To object converter */
+    toObject?: WrapperToObjectConverter;
+}
+
+/** Wire format writer using `Uint8Array` if available, otherwise `Array`. */
+export class Writer {
+
+    /** Constructs a new writer instance. */
+    constructor();
+
+    /** Current length. */
+    public len: number;
+
+    /** Operations head. */
+    public head: object;
+
+    /** Operations tail */
+    public tail: object;
+
+    /** Linked forked states. */
+    public states: (object|null);
+
+    /**
+     * Creates a new writer.
+     * @returns A {@link BufferWriter} when Buffers are supported, otherwise a {@link Writer}
+     */
+    public static create(): (BufferWriter|Writer);
+
+    /**
+     * Allocates a buffer of the specified size.
+     * @param size Buffer size
+     * @returns Buffer
+     */
+    public static alloc(size: number): Uint8Array;
+
+    /**
+     * Writes an unsigned 32 bit value as a varint.
+     * @param value Value to write
+     * @returns `this`
+     */
+    public uint32(value: number): Writer;
+
+    /**
+     * Writes a signed 32 bit value as a varint.
+     * @param value Value to write
+     * @returns `this`
+     */
+    public int32(value: number): Writer;
+
+    /**
+     * Writes a 32 bit value as a varint, zig-zag encoded.
+     * @param value Value to write
+     * @returns `this`
+     */
+    public sint32(value: number): Writer;
+
+    /**
+     * Writes an unsigned 64 bit value as a varint.
+     * @param value Value to write
+     * @returns `this`
+     * @throws {TypeError} If `value` is a string and no long library is present.
+     */
+    public uint64(value: (Long|number|string)): Writer;
+
+    /**
+     * Writes a signed 64 bit value as a varint.
+     * @param value Value to write
+     * @returns `this`
+     * @throws {TypeError} If `value` is a string and no long library is present.
+     */
+    public int64(value: (Long|number|string)): Writer;
+
+    /**
+     * Writes a signed 64 bit value as a varint, zig-zag encoded.
+     * @param value Value to write
+     * @returns `this`
+     * @throws {TypeError} If `value` is a string and no long library is present.
+     */
+    public sint64(value: (Long|number|string)): Writer;
+
+    /**
+     * Writes a boolish value as a varint.
+     * @param value Value to write
+     * @returns `this`
+     */
+    public bool(value: boolean): Writer;
+
+    /**
+     * Writes an unsigned 32 bit value as fixed 32 bits.
+     * @param value Value to write
+     * @returns `this`
+     */
+    public fixed32(value: number): Writer;
+
+    /**
+     * Writes a signed 32 bit value as fixed 32 bits.
+     * @param value Value to write
+     * @returns `this`
+     */
+    public sfixed32(value: number): Writer;
+
+    /**
+     * Writes an unsigned 64 bit value as fixed 64 bits.
+     * @param value Value to write
+     * @returns `this`
+     * @throws {TypeError} If `value` is a string and no long library is present.
+     */
+    public fixed64(value: (Long|number|string)): Writer;
+
+    /**
+     * Writes a signed 64 bit value as fixed 64 bits.
+     * @param value Value to write
+     * @returns `this`
+     * @throws {TypeError} If `value` is a string and no long library is present.
+     */
+    public sfixed64(value: (Long|number|string)): Writer;
+
+    /**
+     * Writes a float (32 bit).
+     * @param value Value to write
+     * @returns `this`
+     */
+    public float(value: number): Writer;
+
+    /**
+     * Writes a double (64 bit float).
+     * @param value Value to write
+     * @returns `this`
+     */
+    public double(value: number): Writer;
+
+    /**
+     * Writes a sequence of bytes.
+     * @param value Buffer or base64 encoded string to write
+     * @returns `this`
+     */
+    public bytes(value: (Uint8Array|string)): Writer;
+
+    /**
+     * Writes a string.
+     * @param value Value to write
+     * @returns `this`
+     */
+    public string(value: string): Writer;
+
+    /**
+     * Forks this writer's state by pushing it to a stack.
+     * Calling {@link Writer#reset|reset} or {@link Writer#ldelim|ldelim} resets the writer to the previous state.
+     * @returns `this`
+     */
+    public fork(): Writer;
+
+    /**
+     * Resets this instance to the last state.
+     * @returns `this`
+     */
+    public reset(): Writer;
+
+    /**
+     * Resets to the last state and appends the fork state's current write length as a varint followed by its operations.
+     * @returns `this`
+     */
+    public ldelim(): Writer;
+
+    /**
+     * Finishes the write operation.
+     * @returns Finished buffer
+     */
+    public finish(): Uint8Array;
+}
+
+/** Wire format writer using node buffers. */
+export class BufferWriter extends Writer {
+
+    /** Constructs a new buffer writer instance. */
+    constructor();
+
+    /**
+     * Allocates a buffer of the specified size.
+     * @param size Buffer size
+     * @returns Buffer
+     */
+    public static alloc(size: number): Buffer;
+
+    /**
+     * Finishes the write operation.
+     * @returns Finished buffer
+     */
+    public finish(): Buffer;
+}
+
+/**
+ * Callback as used by {@link util.asPromise}.
+ * @param error Error, if any
+ * @param params Additional arguments
+ */
+type asPromiseCallback = (error: (Error|null), ...params: any[]) => void;
+
+/**
+ * Appends code to the function's body or finishes generation.
+ * @param [formatStringOrScope] Format string or, to finish the function, an object of additional scope variables, if any
+ * @param [formatParams] Format parameters
+ * @returns Itself or the generated function if finished
+ * @throws {Error} If format parameter counts do not match
+ */
+type Codegen = (formatStringOrScope?: (string|{ [k: string]: any }), ...formatParams: any[]) => (Codegen|Function);
+
+/**
+ * Event listener as used by {@link util.EventEmitter}.
+ * @param args Arguments
+ */
+type EventEmitterListener = (...args: any[]) => void;
+
+/**
+ * Node-style callback as used by {@link util.fetch}.
+ * @param error Error, if any, otherwise `null`
+ * @param [contents] File contents, if there hasn't been an error
+ */
+type FetchCallback = (error: Error, contents?: string) => void;
+
+/** Options as used by {@link util.fetch}. */
+export interface IFetchOptions {
+
+    /** Whether expecting a binary response */
+    binary?: boolean;
+
+    /** If `true`, forces the use of XMLHttpRequest */
+    xhr?: boolean;
+}
+
+/**
+ * An allocator as used by {@link util.pool}.
+ * @param size Buffer size
+ * @returns Buffer
+ */
+type PoolAllocator = (size: number) => Uint8Array;
+
+/**
+ * A slicer as used by {@link util.pool}.
+ * @param start Start offset
+ * @param end End offset
+ * @returns Buffer slice
+ */
+type PoolSlicer = (this: Uint8Array, start: number, end: number) => Uint8Array;
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..042042a
--- /dev/null
+++ b/index.js
@@ -0,0 +1,4 @@
+// full library entry point.
+
+"use strict";
+module.exports = require("./src/index");
diff --git a/lib/aspromise/LICENSE b/lib/aspromise/LICENSE
new file mode 100644
index 0000000..be2b397
--- /dev/null
+++ b/lib/aspromise/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2016, Daniel Wirtz  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 its author, 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
diff --git a/lib/aspromise/README.md b/lib/aspromise/README.md
new file mode 100644
index 0000000..c7ae36f
--- /dev/null
+++ b/lib/aspromise/README.md
@@ -0,0 +1,13 @@
+@protobufjs/aspromise
+=====================
+[![npm](https://img.shields.io/npm/v/@protobufjs/aspromise.svg)](https://www.npmjs.com/package/@protobufjs/aspromise)
+
+Returns a promise from a node-style callback function.
+
+API
+---
+
+* **asPromise(fn: `function`, ctx: `Object`, ...params: `*`): `Promise<*>`**<br />
+  Returns a promise from a node-style callback function.
+
+**License:** [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/lib/aspromise/index.d.ts b/lib/aspromise/index.d.ts
new file mode 100644
index 0000000..3db03db
--- /dev/null
+++ b/lib/aspromise/index.d.ts
@@ -0,0 +1,13 @@
+export = asPromise;
+
+type asPromiseCallback = (error: Error | null, ...params: any[]) => {};
+
+/**
+ * Returns a promise from a node-style callback function.
+ * @memberof util
+ * @param {asPromiseCallback} fn Function to call
+ * @param {*} ctx Function context
+ * @param {...*} params Function arguments
+ * @returns {Promise<*>} Promisified function
+ */
+declare function asPromise(fn: asPromiseCallback, ctx: any, ...params: any[]): Promise<any>;
diff --git a/lib/aspromise/index.js b/lib/aspromise/index.js
new file mode 100644
index 0000000..d6f642c
--- /dev/null
+++ b/lib/aspromise/index.js
@@ -0,0 +1,52 @@
+"use strict";
+module.exports = asPromise;
+
+/**
+ * Callback as used by {@link util.asPromise}.
+ * @typedef asPromiseCallback
+ * @type {function}
+ * @param {Error|null} error Error, if any
+ * @param {...*} params Additional arguments
+ * @returns {undefined}
+ */
+
+/**
+ * Returns a promise from a node-style callback function.
+ * @memberof util
+ * @param {asPromiseCallback} fn Function to call
+ * @param {*} ctx Function context
+ * @param {...*} params Function arguments
+ * @returns {Promise<*>} Promisified function
+ */
+function asPromise(fn, ctx/*, varargs */) {
+    var params  = new Array(arguments.length - 1),
+        offset  = 0,
+        index   = 2,
+        pending = true;
+    while (index < arguments.length)
+        params[offset++] = arguments[index++];
+    return new Promise(function executor(resolve, reject) {
+        params[offset] = function callback(err/*, varargs */) {
+            if (pending) {
+                pending = false;
+                if (err)
+                    reject(err);
+                else {
+                    var params = new Array(arguments.length - 1),
+                        offset = 0;
+                    while (offset < params.length)
+                        params[offset++] = arguments[offset];
+                    resolve.apply(null, params);
+                }
+            }
+        };
+        try {
+            fn.apply(ctx || null, params);
+        } catch (err) {
+            if (pending) {
+                pending = false;
+                reject(err);
+            }
+        }
+    });
+}
diff --git a/lib/aspromise/package.json b/lib/aspromise/package.json
new file mode 100644
index 0000000..e05eecd
--- /dev/null
+++ b/lib/aspromise/package.json
@@ -0,0 +1,21 @@
+{
+  "name": "@protobufjs/aspromise",
+  "description": "Returns a promise from a node-style callback function.",
+  "version": "1.1.2",
+  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/dcodeIO/protobuf.js.git"
+  },
+  "license": "BSD-3-Clause",
+  "main": "index.js",
+  "types": "index.d.ts",
+  "devDependencies": {
+    "istanbul": "^0.4.5",
+    "tape": "^5.0.0"
+  },
+  "scripts": {
+    "test": "tape tests/*.js",
+    "coverage": "istanbul cover node_modules/tape/bin/tape tests/*.js"
+  }
+}
\ No newline at end of file
diff --git a/lib/aspromise/tests/index.js b/lib/aspromise/tests/index.js
new file mode 100644
index 0000000..cfdb258
--- /dev/null
+++ b/lib/aspromise/tests/index.js
@@ -0,0 +1,130 @@
+var tape = require("tape");
+
+var asPromise = require("..");
+
+tape.test("aspromise", function(test) {
+
+    test.test(this.name + " - resolve", function(test) {
+
+        function fn(arg1, arg2, callback) {
+            test.equal(this, ctx, "function should be called with this = ctx");
+            test.equal(arg1, 1, "function should be called with arg1 = 1");
+            test.equal(arg2, 2, "function should be called with arg2 = 2");
+            callback(null, arg2);
+        }
+
+        var ctx = {};
+
+        var promise = asPromise(fn, ctx, 1, 2);
+        promise.then(function(arg2) {
+            test.equal(arg2, 2, "promise should be resolved with arg2 = 2");
+            test.end();
+        }).catch(function(err) {
+            test.fail("promise should not be rejected (" + err + ")");
+        });
+    });
+
+    test.test(this.name + " - reject", function(test) {
+
+        function fn(arg1, arg2, callback) {
+            test.equal(this, ctx, "function should be called with this = ctx");
+            test.equal(arg1, 1, "function should be called with arg1 = 1");
+            test.equal(arg2, 2, "function should be called with arg2 = 2");
+            callback(arg1);
+        }
+
+        var ctx = {};
+
+        var promise = asPromise(fn, ctx, 1, 2);
+        promise.then(function() {
+            test.fail("promise should not be resolved");
+        }).catch(function(err) {
+            test.equal(err, 1, "promise should be rejected with err = 1");
+            test.end();
+        });
+    });
+
+    test.test(this.name + " - resolve twice", function(test) {
+
+        function fn(arg1, arg2, callback) {
+            test.equal(this, ctx, "function should be called with this = ctx");
+            test.equal(arg1, 1, "function should be called with arg1 = 1");
+            test.equal(arg2, 2, "function should be called with arg2 = 2");
+            callback(null, arg2);
+            callback(null, arg1);
+        }
+
+        var ctx = {};
+        var count = 0;
+
+        var promise = asPromise(fn, ctx, 1, 2);
+        promise.then(function(arg2) {
+            test.equal(arg2, 2, "promise should be resolved with arg2 = 2");
+            if (++count > 1)
+                test.fail("promise should not be resolved twice");
+            test.end();
+        }).catch(function(err) {
+            test.fail("promise should not be rejected (" + err + ")");
+        });
+    });
+
+    test.test(this.name + " - reject twice", function(test) {
+
+        function fn(arg1, arg2, callback) {
+            test.equal(this, ctx, "function should be called with this = ctx");
+            test.equal(arg1, 1, "function should be called with arg1 = 1");
+            test.equal(arg2, 2, "function should be called with arg2 = 2");
+            callback(arg1);
+            callback(arg2);
+        }
+
+        var ctx = {};
+        var count = 0;
+
+        var promise = asPromise(fn, ctx, 1, 2);
+        promise.then(function() {
+            test.fail("promise should not be resolved");
+        }).catch(function(err) {
+            test.equal(err, 1, "promise should be rejected with err = 1");
+            if (++count > 1)
+                test.fail("promise should not be rejected twice");
+            test.end();
+        });
+    });
+
+    test.test(this.name + " - reject error", function(test) {
+
+        function fn(callback) {
+            test.ok(arguments.length === 1 && typeof callback === "function", "function should be called with just a callback");
+            throw 3;
+        }
+
+        var promise = asPromise(fn, null);
+        promise.then(function() {
+            test.fail("promise should not be resolved");
+        }).catch(function(err) {
+            test.equal(err, 3, "promise should be rejected with err = 3");
+            test.end();
+        });
+    });
+
+    test.test(this.name + " - reject and error", function(test) {
+
+        function fn(callback) {
+            callback(3);
+            throw 4;
+        }
+
+        var count = 0;
+
+        var promise = asPromise(fn, null);
+        promise.then(function() {
+            test.fail("promise should not be resolved");
+        }).catch(function(err) {
+            test.equal(err, 3, "promise should be rejected with err = 3");
+            if (++count > 1)
+                test.fail("promise should not be rejected twice");
+            test.end();
+        });
+    });
+});
diff --git a/lib/base64/LICENSE b/lib/base64/LICENSE
new file mode 100644
index 0000000..be2b397
--- /dev/null
+++ b/lib/base64/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2016, Daniel Wirtz  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 its author, 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
diff --git a/lib/base64/README.md b/lib/base64/README.md
new file mode 100644
index 0000000..b06cb0a
--- /dev/null
+++ b/lib/base64/README.md
@@ -0,0 +1,19 @@
+@protobufjs/base64
+==================
+[![npm](https://img.shields.io/npm/v/@protobufjs/base64.svg)](https://www.npmjs.com/package/@protobufjs/base64)
+
+A minimal base64 implementation for number arrays.
+
+API
+---
+
+* **base64.length(string: `string`): `number`**<br />
+  Calculates the byte length of a base64 encoded string.
+
+* **base64.encode(buffer: `Uint8Array`, start: `number`, end: `number`): `string`**<br />
+  Encodes a buffer to a base64 encoded string.
+
+* **base64.decode(string: `string`, buffer: `Uint8Array`, offset: `number`): `number`**<br />
+  Decodes a base64 encoded string to a buffer.
+
+**License:** [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/lib/base64/index.d.ts b/lib/base64/index.d.ts
new file mode 100644
index 0000000..085d0a7
--- /dev/null
+++ b/lib/base64/index.d.ts
@@ -0,0 +1,32 @@
+/**
+ * Calculates the byte length of a base64 encoded string.
+ * @param {string} string Base64 encoded string
+ * @returns {number} Byte length
+ */
+export function length(string: string): number;
+
+/**
+ * Encodes a buffer to a base64 encoded string.
+ * @param {Uint8Array} buffer Source buffer
+ * @param {number} start Source start
+ * @param {number} end Source end
+ * @returns {string} Base64 encoded string
+ */
+export function encode(buffer: Uint8Array, start: number, end: number): string;
+
+/**
+ * Decodes a base64 encoded string to a buffer.
+ * @param {string} string Source string
+ * @param {Uint8Array} buffer Destination buffer
+ * @param {number} offset Destination offset
+ * @returns {number} Number of bytes written
+ * @throws {Error} If encoding is invalid
+ */
+export function decode(string: string, buffer: Uint8Array, offset: number): number;
+
+/**
+ * Tests if the specified string appears to be base64 encoded.
+ * @param {string} string String to test
+ * @returns {boolean} `true` if it appears to be base64 encoded, otherwise false
+ */
+export function test(string: string): boolean;
diff --git a/lib/base64/index.js b/lib/base64/index.js
new file mode 100644
index 0000000..6146f54
--- /dev/null
+++ b/lib/base64/index.js
@@ -0,0 +1,139 @@
+"use strict";
+
+/**
+ * A minimal base64 implementation for number arrays.
+ * @memberof util
+ * @namespace
+ */
+var base64 = exports;
+
+/**
+ * Calculates the byte length of a base64 encoded string.
+ * @param {string} string Base64 encoded string
+ * @returns {number} Byte length
+ */
+base64.length = function length(string) {
+    var p = string.length;
+    if (!p)
+        return 0;
+    var n = 0;
+    while (--p % 4 > 1 && string.charAt(p) === "=")
+        ++n;
+    return Math.ceil(string.length * 3) / 4 - n;
+};
+
+// Base64 encoding table
+var b64 = new Array(64);
+
+// Base64 decoding table
+var s64 = new Array(123);
+
+// 65..90, 97..122, 48..57, 43, 47
+for (var i = 0; i < 64;)
+    s64[b64[i] = i < 26 ? i + 65 : i < 52 ? i + 71 : i < 62 ? i - 4 : i - 59 | 43] = i++;
+
+/**
+ * Encodes a buffer to a base64 encoded string.
+ * @param {Uint8Array} buffer Source buffer
+ * @param {number} start Source start
+ * @param {number} end Source end
+ * @returns {string} Base64 encoded string
+ */
+base64.encode = function encode(buffer, start, end) {
+    var parts = null,
+        chunk = [];
+    var i = 0, // output index
+        j = 0, // goto index
+        t;     // temporary
+    while (start < end) {
+        var b = buffer[start++];
+        switch (j) {
+            case 0:
+                chunk[i++] = b64[b >> 2];
+                t = (b & 3) << 4;
+                j = 1;
+                break;
+            case 1:
+                chunk[i++] = b64[t | b >> 4];
+                t = (b & 15) << 2;
+                j = 2;
+                break;
+            case 2:
+                chunk[i++] = b64[t | b >> 6];
+                chunk[i++] = b64[b & 63];
+                j = 0;
+                break;
+        }
+        if (i > 8191) {
+            (parts || (parts = [])).push(String.fromCharCode.apply(String, chunk));
+            i = 0;
+        }
+    }
+    if (j) {
+        chunk[i++] = b64[t];
+        chunk[i++] = 61;
+        if (j === 1)
+            chunk[i++] = 61;
+    }
+    if (parts) {
+        if (i)
+            parts.push(String.fromCharCode.apply(String, chunk.slice(0, i)));
+        return parts.join("");
+    }
+    return String.fromCharCode.apply(String, chunk.slice(0, i));
+};
+
+var invalidEncoding = "invalid encoding";
+
+/**
+ * Decodes a base64 encoded string to a buffer.
+ * @param {string} string Source string
+ * @param {Uint8Array} buffer Destination buffer
+ * @param {number} offset Destination offset
+ * @returns {number} Number of bytes written
+ * @throws {Error} If encoding is invalid
+ */
+base64.decode = function decode(string, buffer, offset) {
+    var start = offset;
+    var j = 0, // goto index
+        t;     // temporary
+    for (var i = 0; i < string.length;) {
+        var c = string.charCodeAt(i++);
+        if (c === 61 && j > 1)
+            break;
+        if ((c = s64[c]) === undefined)
+            throw Error(invalidEncoding);
+        switch (j) {
+            case 0:
+                t = c;
+                j = 1;
+                break;
+            case 1:
+                buffer[offset++] = t << 2 | (c & 48) >> 4;
+                t = c;
+                j = 2;
+                break;
+            case 2:
+                buffer[offset++] = (t & 15) << 4 | (c & 60) >> 2;
+                t = c;
+                j = 3;
+                break;
+            case 3:
+                buffer[offset++] = (t & 3) << 6 | c;
+                j = 0;
+                break;
+        }
+    }
+    if (j === 1)
+        throw Error(invalidEncoding);
+    return offset - start;
+};
+
+/**
+ * Tests if the specified string appears to be base64 encoded.
+ * @param {string} string String to test
+ * @returns {boolean} `true` if probably base64 encoded, otherwise false
+ */
+base64.test = function test(string) {
+    return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(string);
+};
diff --git a/lib/base64/package.json b/lib/base64/package.json
new file mode 100644
index 0000000..722de85
--- /dev/null
+++ b/lib/base64/package.json
@@ -0,0 +1,21 @@
+{
+  "name": "@protobufjs/base64",
+  "description": "A minimal base64 implementation for number arrays.",
+  "version": "1.1.2",
+  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/dcodeIO/protobuf.js.git"
+  },
+  "license": "BSD-3-Clause",
+  "main": "index.js",
+  "types": "index.d.ts",
+  "devDependencies": {
+    "istanbul": "^0.4.5",
+    "tape": "^5.0.0"
+  },
+  "scripts": {
+    "test": "tape tests/*.js",
+    "coverage": "istanbul cover node_modules/tape/bin/tape tests/*.js"
+  }
+}
\ No newline at end of file
diff --git a/lib/base64/tests/index.js b/lib/base64/tests/index.js
new file mode 100644
index 0000000..6ede32c
--- /dev/null
+++ b/lib/base64/tests/index.js
@@ -0,0 +1,46 @@
+var tape = require("tape");
+
+var base64 = require("..");
+
+var strings = {
+    "": "",
+    "a": "YQ==",
+    "ab": "YWI=",
+    "abcdefg": "YWJjZGVmZw==",
+    "abcdefgh": "YWJjZGVmZ2g=",
+    "abcdefghi": "YWJjZGVmZ2hp"
+};
+
+tape.test("base64", function(test) {
+
+    Object.keys(strings).forEach(function(str) {
+        var enc = strings[str];
+
+        test.equal(base64.test(enc), true, "should detect '" + enc + "' to be base64 encoded");
+
+        var len = base64.length(enc);
+        test.equal(len, str.length, "should calculate '" + enc + "' as " + str.length + " bytes");
+
+        var buf = new Array(len);
+        var len2 = base64.decode(enc, buf, 0);
+        test.equal(len2, len, "should decode '" + enc + "' to " + len + " bytes");
+
+        test.equal(String.fromCharCode.apply(String, buf), str, "should decode '" + enc + "' to '" + str + "'");
+
+        var enc2 = base64.encode(buf, 0, buf.length);
+        test.equal(enc2, enc, "should encode '" + str + "' to '" + enc + "'");
+
+    });
+
+    test.throws(function() {
+        var buf = new Array(10);
+        base64.decode("YQ!", buf, 0);
+    }, Error, "should throw if encoding is invalid");
+
+    test.throws(function() {
+        var buf = new Array(10);
+        base64.decode("Y", buf, 0);
+    }, Error, "should throw if string is truncated");
+
+    test.end();
+});
diff --git a/lib/codegen/LICENSE b/lib/codegen/LICENSE
new file mode 100644
index 0000000..be2b397
--- /dev/null
+++ b/lib/codegen/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2016, Daniel Wirtz  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 its author, 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
diff --git a/lib/codegen/README.md b/lib/codegen/README.md
new file mode 100644
index 0000000..577c43e
--- /dev/null
+++ b/lib/codegen/README.md
@@ -0,0 +1,49 @@
+@protobufjs/codegen
+===================
+[![npm](https://img.shields.io/npm/v/@protobufjs/codegen.svg)](https://www.npmjs.com/package/@protobufjs/codegen)
+
+A minimalistic code generation utility.
+
+API
+---
+
+* **codegen([functionParams: `string[]`], [functionName: string]): `Codegen`**<br />
+  Begins generating a function.
+
+* **codegen.verbose = `false`**<br />
+  When set to true, codegen will log generated code to console. Useful for debugging.
+
+Invoking **codegen** returns an appender function that appends code to the function's body and returns itself:
+
+* **Codegen(formatString: `string`, [...formatParams: `any`]): Codegen**<br />
+  Appends code to the function's body. The format string can contain placeholders specifying the types of inserted format parameters:
+
+  * `%d`: Number (integer or floating point value)
+  * `%f`: Floating point value
+  * `%i`: Integer value
+  * `%j`: JSON.stringify'ed value
+  * `%s`: String value
+  * `%%`: Percent sign<br />
+
+* **Codegen([scope: `Object.<string,*>`]): `Function`**<br />
+  Finishes the function and returns it.
+
+* **Codegen.toString([functionNameOverride: `string`]): `string`**<br />
+  Returns the function as a string.
+
+Example
+-------
+
+```js
+var codegen = require("@protobufjs/codegen");
+
+var add = codegen(["a", "b"], "add") // A function with parameters "a" and "b" named "add"
+  ("// awesome comment")             // adds the line to the function's body
+  ("return a + b - c + %d", 1)       // replaces %d with 1 and adds the line to the body
+  ({ c: 1 });                        // adds "c" with a value of 1 to the function's scope
+
+console.log(add.toString()); // function add(a, b) { return a + b - c + 1 }
+console.log(add(1, 2));      // calculates 1 + 2 - 1 + 1 = 3
+```
+
+**License:** [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/lib/codegen/index.d.ts b/lib/codegen/index.d.ts
new file mode 100644
index 0000000..f8ed908
--- /dev/null
+++ b/lib/codegen/index.d.ts
@@ -0,0 +1,31 @@
+export = codegen;
+
+/**
+ * Appends code to the function's body.
+ * @param [formatStringOrScope] Format string or, to finish the function, an object of additional scope variables, if any
+ * @param [formatParams] Format parameters
+ * @returns Itself or the generated function if finished
+ * @throws {Error} If format parameter counts do not match
+ */
+type Codegen = (formatStringOrScope?: (string|{ [k: string]: any }), ...formatParams: any[]) => (Codegen|Function);
+
+/**
+ * Begins generating a function.
+ * @param functionParams Function parameter names
+ * @param [functionName] Function name if not anonymous
+ * @returns Appender that appends code to the function's body
+ */
+declare function codegen(functionParams: string[], functionName?: string): Codegen;
+
+/**
+ * Begins generating a function.
+ * @param [functionName] Function name if not anonymous
+ * @returns Appender that appends code to the function's body
+ */
+declare function codegen(functionName?: string): Codegen;
+
+declare namespace codegen {
+
+    /** When set to `true`, codegen will log generated code to console. Useful for debugging. */
+    let verbose: boolean;
+}
diff --git a/lib/codegen/index.js b/lib/codegen/index.js
new file mode 100644
index 0000000..af005cb
--- /dev/null
+++ b/lib/codegen/index.js
@@ -0,0 +1,99 @@
+"use strict";
+module.exports = codegen;
+
+/**
+ * Begins generating a function.
+ * @memberof util
+ * @param {string[]} functionParams Function parameter names
+ * @param {string} [functionName] Function name if not anonymous
+ * @returns {Codegen} Appender that appends code to the function's body
+ */
+function codegen(functionParams, functionName) {
+
+    /* istanbul ignore if */
+    if (typeof functionParams === "string") {
+        functionName = functionParams;
+        functionParams = undefined;
+    }
+
+    var body = [];
+
+    /**
+     * Appends code to the function's body or finishes generation.
+     * @typedef Codegen
+     * @type {function}
+     * @param {string|Object.<string,*>} [formatStringOrScope] Format string or, to finish the function, an object of additional scope variables, if any
+     * @param {...*} [formatParams] Format parameters
+     * @returns {Codegen|Function} Itself or the generated function if finished
+     * @throws {Error} If format parameter counts do not match
+     */
+
+    function Codegen(formatStringOrScope) {
+        // note that explicit array handling below makes this ~50% faster
+
+        // finish the function
+        if (typeof formatStringOrScope !== "string") {
+            var source = toString();
+            if (codegen.verbose)
+                console.log("codegen: " + source); // eslint-disable-line no-console
+            source = "return " + source;
+            if (formatStringOrScope) {
+                var scopeKeys   = Object.keys(formatStringOrScope),
+                    scopeParams = new Array(scopeKeys.length + 1),
+                    scopeValues = new Array(scopeKeys.length),
+                    scopeOffset = 0;
+                while (scopeOffset < scopeKeys.length) {
+                    scopeParams[scopeOffset] = scopeKeys[scopeOffset];
+                    scopeValues[scopeOffset] = formatStringOrScope[scopeKeys[scopeOffset++]];
+                }
+                scopeParams[scopeOffset] = source;
+                return Function.apply(null, scopeParams).apply(null, scopeValues); // eslint-disable-line no-new-func
+            }
+            return Function(source)(); // eslint-disable-line no-new-func
+        }
+
+        // otherwise append to body
+        var formatParams = new Array(arguments.length - 1),
+            formatOffset = 0;
+        while (formatOffset < formatParams.length)
+            formatParams[formatOffset] = arguments[++formatOffset];
+        formatOffset = 0;
+        formatStringOrScope = formatStringOrScope.replace(/%([%dfijs])/g, function replace($0, $1) {
+            var value = formatParams[formatOffset++];
+            switch ($1) {
+                case "d": case "f": return String(Number(value));
+                case "i": return String(Math.floor(value));
+                case "j": return JSON.stringify(value);
+                case "s": return String(value);
+            }
+            return "%";
+        });
+        if (formatOffset !== formatParams.length)
+            throw Error("parameter count mismatch");
+        body.push(formatStringOrScope);
+        return Codegen;
+    }
+
+    function toString(functionNameOverride) {
+        return "function " + (functionNameOverride || functionName || "") + "(" + (functionParams && functionParams.join(",") || "") + "){\n  " + body.join("\n  ") + "\n}";
+    }
+
+    Codegen.toString = toString;
+    return Codegen;
+}
+
+/**
+ * Begins generating a function.
+ * @memberof util
+ * @function codegen
+ * @param {string} [functionName] Function name if not anonymous
+ * @returns {Codegen} Appender that appends code to the function's body
+ * @variation 2
+ */
+
+/**
+ * When set to `true`, codegen will log generated code to console. Useful for debugging.
+ * @name util.codegen.verbose
+ * @type {boolean}
+ */
+codegen.verbose = false;
diff --git a/lib/codegen/package.json b/lib/codegen/package.json
new file mode 100644
index 0000000..4e82f95
--- /dev/null
+++ b/lib/codegen/package.json
@@ -0,0 +1,13 @@
+{
+  "name": "@protobufjs/codegen",
+  "description": "A minimalistic code generation utility.",
+  "version": "2.0.4",
+  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/dcodeIO/protobuf.js.git"
+  },
+  "license": "BSD-3-Clause",
+  "main": "index.js",
+  "types": "index.d.ts"
+}
\ No newline at end of file
diff --git a/lib/codegen/tests/index.js b/lib/codegen/tests/index.js
new file mode 100644
index 0000000..b189117
--- /dev/null
+++ b/lib/codegen/tests/index.js
@@ -0,0 +1,13 @@
+var codegen = require("..");
+
+// new require("benchmark").Suite().add("add", function() {
+
+var add = codegen(["a", "b"], "add")
+  ("// awesome comment")
+  ("return a + b - c + %d", 1)
+  ({ c: 1 });
+
+if (add(1, 2) !== 3)
+  throw Error("failed");
+
+// }).on("cycle", function(event) { process.stdout.write(String(event.target) + "\n"); }).run();
diff --git a/lib/deep-equal/LICENSE b/lib/deep-equal/LICENSE
new file mode 100644
index 0000000..30a59ef
--- /dev/null
+++ b/lib/deep-equal/LICENSE
@@ -0,0 +1,18 @@
+This software is released under the MIT license:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/lib/deep-equal/README.md b/lib/deep-equal/README.md
new file mode 100644
index 0000000..c37ebd9
--- /dev/null
+++ b/lib/deep-equal/README.md
@@ -0,0 +1,3 @@
+Forked [node-deep-equal](https://github.com/substack/node-deep-equal)@1.0.1 with monkey-patched buffer equality.
+
+License: MIT. Derived largely from node's assert module.
diff --git a/lib/deep-equal/index.js b/lib/deep-equal/index.js
new file mode 100644
index 0000000..a2fba8b
--- /dev/null
+++ b/lib/deep-equal/index.js
@@ -0,0 +1,95 @@
+var pSlice = Array.prototype.slice;
+var objectKeys = require('./lib/keys.js');
+var isArguments = require('./lib/is_arguments.js');
+
+var deepEqual = module.exports = function (actual, expected, opts) {
+  if (!opts) opts = {};
+  // 7.1. All identical values are equivalent, as determined by ===.
+  if (actual === expected) {
+    return true;
+
+  } else if (actual instanceof Date && expected instanceof Date) {
+    return actual.getTime() === expected.getTime();
+
+  // 7.3. Other pairs that do not both pass typeof value == 'object',
+  // equivalence is determined by ==.
+  } else if (!actual || !expected || typeof actual != 'object' && typeof expected != 'object') {
+    return opts.strict ? actual === expected : actual == expected;
+
+  // 7.4. For all other Object pairs, including Array objects, equivalence is
+  // determined by having the same number of owned properties (as verified
+  // with Object.prototype.hasOwnProperty.call), the same set of keys
+  // (although not necessarily the same order), equivalent values for every
+  // corresponding key, and an identical 'prototype' property. Note: this
+  // accounts for both named and indexed properties on Arrays.
+  } else {
+    return objEquiv(actual, expected, opts);
+  }
+}
+
+function isUndefinedOrNull(value) {
+  return value === null || value === undefined;
+}
+
+function isBuffer (x) {
+  if (!x || typeof x !== 'object' || typeof x.length !== 'number') return false;
+  // MONKEY PATCH: Support buffer, Uint8Array and Array alike
+  /* if (typeof x.copy !== 'function' || typeof x.slice !== 'function') {
+    return false;
+  } */
+  if (x.length > 0 && typeof x[0] !== 'number') return false;
+  return true;
+}
+
+function objEquiv(a, b, opts) {
+  var i, key;
+  if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
+    return false;
+  // an identical 'prototype' property.
+  if (a.prototype !== b.prototype) return false;
+  //~~~I've managed to break Object.keys through screwy arguments passing.
+  //   Converting to array solves the problem.
+  if (isArguments(a)) {
+    if (!isArguments(b)) {
+      return false;
+    }
+    a = pSlice.call(a);
+    b = pSlice.call(b);
+    return deepEqual(a, b, opts);
+  }
+  if (isBuffer(a)) {
+    if (!isBuffer(b)) {
+      return false;
+    }
+    if (a.length !== b.length) return false;
+    for (i = 0; i < a.length; i++) {
+      if (a[i] !== b[i]) return false;
+    }
+    return true;
+  }
+  try {
+    var ka = objectKeys(a),
+        kb = objectKeys(b);
+  } catch (e) {//happens when one is a string literal and the other isn't
+    return false;
+  }
+  // having the same number of owned properties (keys incorporates
+  // hasOwnProperty)
+  if (ka.length != kb.length)
+    return false;
+  //the same set of keys (although not necessarily the same order),
+  ka.sort();
+  kb.sort();
+  //~~~cheap key test
+  for (i = ka.length - 1; i >= 0; i--) {
+    if (ka[i] != kb[i])
+      return false;
+  }
+  //equivalent values for every corresponding key, and
+  //~~~possibly expensive deep test
+  for (i = ka.length - 1; i >= 0; i--) {
+    key = ka[i];
+    if (!deepEqual(a[key], b[key], opts)) return false;
+  }
+  return typeof a === typeof b;
+}
\ No newline at end of file
diff --git a/lib/deep-equal/lib/is_arguments.js b/lib/deep-equal/lib/is_arguments.js
new file mode 100644
index 0000000..e3fbc1f
--- /dev/null
+++ b/lib/deep-equal/lib/is_arguments.js
@@ -0,0 +1,20 @@
+var supportsArgumentsClass = (function(){
+  return Object.prototype.toString.call(arguments)
+})() == '[object Arguments]';
+
+exports = module.exports = supportsArgumentsClass ? supported : unsupported;
+
+exports.supported = supported;
+function supported(object) {
+  return Object.prototype.toString.call(object) == '[object Arguments]';
+};
+
+exports.unsupported = unsupported;
+function unsupported(object){
+  return object &&
+    typeof object == 'object' &&
+    typeof object.length == 'number' &&
+    Object.prototype.hasOwnProperty.call(object, 'callee') &&
+    !Object.prototype.propertyIsEnumerable.call(object, 'callee') ||
+    false;
+};
\ No newline at end of file
diff --git a/lib/deep-equal/lib/keys.js b/lib/deep-equal/lib/keys.js
new file mode 100644
index 0000000..6f04fcd
--- /dev/null
+++ b/lib/deep-equal/lib/keys.js
@@ -0,0 +1,9 @@
+exports = module.exports = typeof Object.keys === 'function'
+  ? Object.keys : shim;
+
+exports.shim = shim;
+function shim (obj) {
+  var keys = [];
+  for (var key in obj) keys.push(key);
+  return keys;
+}
\ No newline at end of file
diff --git a/lib/eventemitter/LICENSE b/lib/eventemitter/LICENSE
new file mode 100644
index 0000000..be2b397
--- /dev/null
+++ b/lib/eventemitter/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2016, Daniel Wirtz  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 its author, 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
diff --git a/lib/eventemitter/README.md b/lib/eventemitter/README.md
new file mode 100644
index 0000000..528e725
--- /dev/null
+++ b/lib/eventemitter/README.md
@@ -0,0 +1,22 @@
+@protobufjs/eventemitter
+========================
+[![npm](https://img.shields.io/npm/v/@protobufjs/eventemitter.svg)](https://www.npmjs.com/package/@protobufjs/eventemitter)
+
+A minimal event emitter.
+
+API
+---
+
+* **new EventEmitter()**<br />
+  Constructs a new event emitter instance.
+
+* **EventEmitter#on(evt: `string`, fn: `function`, [ctx: `Object`]): `EventEmitter`**<br />
+  Registers an event listener.
+
+* **EventEmitter#off([evt: `string`], [fn: `function`]): `EventEmitter`**<br />
+  Removes an event listener or any matching listeners if arguments are omitted.
+
+* **EventEmitter#emit(evt: `string`, ...args: `*`): `EventEmitter`**<br />
+  Emits an event by calling its listeners with the specified arguments.
+
+**License:** [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/lib/eventemitter/index.d.ts b/lib/eventemitter/index.d.ts
new file mode 100644
index 0000000..ae967ec
--- /dev/null
+++ b/lib/eventemitter/index.d.ts
@@ -0,0 +1,45 @@
+export = EventEmitter;
+
+type EventEmitterListener = (...args: any[]) => {};
+
+/**
+ * Constructs a new event emitter instance.
+ * @classdesc A minimal event emitter.
+ * @memberof util
+ * @constructor
+ */
+declare class EventEmitter {
+
+    /**
+     * Constructs a new event emitter instance.
+     * @classdesc A minimal event emitter.
+     * @memberof util
+     * @constructor
+     */
+    constructor();
+
+    /**
+     * Registers an event listener.
+     * @param {string} evt Event name
+     * @param {EventEmitterListener} fn Listener
+     * @param {*} [ctx] Listener context
+     * @returns {this} `this`
+     */
+    public on(evt: string, fn: EventEmitterListener, ctx?: any): EventEmitter;
+
+    /**
+     * Removes an event listener or any matching listeners if arguments are omitted.
+     * @param {string} [evt] Event name. Removes all listeners if omitted.
+     * @param {EventEmitterListener} [fn] Listener to remove. Removes all listeners of `evt` if omitted.
+     * @returns {this} `this`
+     */
+    public off(evt?: string, fn?: EventEmitterListener): EventEmitter;
+
+    /**
+     * Emits an event by calling its listeners with the specified arguments.
+     * @param {string} evt Event name
+     * @param {...*} args Arguments
+     * @returns {this} `this`
+     */
+    public emit(evt: string, ...args: any[]): EventEmitter;
+}
diff --git a/lib/eventemitter/index.js b/lib/eventemitter/index.js
new file mode 100644
index 0000000..ee10aa4
--- /dev/null
+++ b/lib/eventemitter/index.js
@@ -0,0 +1,84 @@
+"use strict";
+module.exports = EventEmitter;
+
+/**
+ * Constructs a new event emitter instance.
+ * @classdesc A minimal event emitter.
+ * @memberof util
+ * @constructor
+ */
+function EventEmitter() {
+
+    /**
+     * Registered listeners.
+     * @type {Object.<string,*>}
+     * @private
+     */
+    this._listeners = {};
+}
+
+/**
+ * Event listener as used by {@link util.EventEmitter}.
+ * @typedef EventEmitterListener
+ * @type {function}
+ * @param {...*} args Arguments
+ * @returns {undefined}
+ */
+
+/**
+ * Registers an event listener.
+ * @param {string} evt Event name
+ * @param {EventEmitterListener} fn Listener
+ * @param {*} [ctx] Listener context
+ * @returns {this} `this`
+ */
+EventEmitter.prototype.on = function on(evt, fn, ctx) {
+    (this._listeners[evt] || (this._listeners[evt] = [])).push({
+        fn  : fn,
+        ctx : ctx || this
+    });
+    return this;
+};
+
+/**
+ * Removes an event listener or any matching listeners if arguments are omitted.
+ * @param {string} [evt] Event name. Removes all listeners if omitted.
+ * @param {EventEmitterListener} [fn] Listener to remove. Removes all listeners of `evt` if omitted.
+ * @returns {this} `this`
+ */
+EventEmitter.prototype.off = function off(evt, fn) {
+    if (evt === undefined)
+        this._listeners = {};
+    else {
+        if (fn === undefined)
+            this._listeners[evt] = [];
+        else {
+            var listeners = this._listeners[evt];
+            for (var i = 0; i < listeners.length;)
+                if (listeners[i].fn === fn)
+                    listeners.splice(i, 1);
+                else
+                    ++i;
+        }
+    }
+    return this;
+};
+
+/**
+ * Emits an event by calling its listeners with the specified arguments.
+ * @param {string} evt Event name
+ * @param {...*} args Arguments
+ * @returns {this} `this`
+ */
+EventEmitter.prototype.emit = function emit(evt) {
+    var listeners = this._listeners[evt];
+    if (listeners) {
+        var args = [],
+            i = 1;
+        for (; i < arguments.length;)
+            args.push(arguments[i++]);
+        for (i = 0; i < listeners.length;)
+            listeners[i].fn.apply(listeners[i++].ctx, args);
+    }
+    return this;
+};
diff --git a/lib/eventemitter/package.json b/lib/eventemitter/package.json
new file mode 100644
index 0000000..e1765d0
--- /dev/null
+++ b/lib/eventemitter/package.json
@@ -0,0 +1,21 @@
+{
+  "name": "@protobufjs/eventemitter",
+  "description": "A minimal event emitter.",
+  "version": "1.1.0",
+  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/dcodeIO/protobuf.js.git"
+  },
+  "license": "BSD-3-Clause",
+  "main": "index.js",
+  "types": "index.d.ts",
+  "devDependencies": {
+    "istanbul": "^0.4.5",
+    "tape": "^5.0.0"
+  },
+  "scripts": {
+    "test": "tape tests/*.js",
+    "coverage": "istanbul cover node_modules/tape/bin/tape tests/*.js"
+  }
+}
\ No newline at end of file
diff --git a/lib/eventemitter/tests/index.js b/lib/eventemitter/tests/index.js
new file mode 100644
index 0000000..390958f
--- /dev/null
+++ b/lib/eventemitter/tests/index.js
@@ -0,0 +1,47 @@
+var tape = require("tape");
+
+var EventEmitter = require("..");
+
+tape.test("eventemitter", function(test) {
+
+    var ee = new EventEmitter();
+    var fn;
+    var ctx = {};
+
+    test.doesNotThrow(function() {
+        ee.emit("a", 1);
+        ee.off();
+        ee.off("a");
+        ee.off("a", function() {});
+    }, "should not throw if no listeners are registered");
+    
+    test.equal(ee.on("a", function(arg1) {
+        test.equal(this, ctx, "should be called with this = ctx");
+        test.equal(arg1, 1, "should be called with arg1 = 1");
+    }, ctx), ee, "should return itself when registering events");
+    ee.emit("a", 1);
+
+    ee.off("a");
+    test.same(ee._listeners, { a: [] }, "should remove all listeners of the respective event when calling off(evt)");
+
+    ee.off();
+    test.same(ee._listeners, {}, "should remove all listeners when just calling off()");
+
+    ee.on("a", fn = function(arg1) {
+        test.equal(this, ctx, "should be called with this = ctx");
+        test.equal(arg1, 1, "should be called with arg1 = 1");
+    }, ctx).emit("a", 1);
+
+    ee.off("a", fn);
+    test.same(ee._listeners, { a: [] }, "should remove the exact listener when calling off(evt, fn)");
+
+    ee.on("a", function() {
+        test.equal(this, ee, "should be called with this = ee");
+    }).emit("a");
+
+    test.doesNotThrow(function() {
+        ee.off("a", fn);
+    }, "should not throw if no such listener is found");
+
+    test.end();
+});
diff --git a/lib/fetch/LICENSE b/lib/fetch/LICENSE
new file mode 100644
index 0000000..be2b397
--- /dev/null
+++ b/lib/fetch/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2016, Daniel Wirtz  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 its author, 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
diff --git a/lib/fetch/README.md b/lib/fetch/README.md
new file mode 100644
index 0000000..1ebf4d4
--- /dev/null
+++ b/lib/fetch/README.md
@@ -0,0 +1,13 @@
+@protobufjs/fetch
+=================
+[![npm](https://img.shields.io/npm/v/@protobufjs/fetch.svg)](https://www.npmjs.com/package/@protobufjs/fetch)
+
+Fetches the contents of a file accross node and browsers.
+
+API
+---
+
+* **fetch(path: `string`, [options: { binary: boolean } ], [callback: `function(error: ?Error, [contents: string])`]): `Promise<string|Uint8Array>|undefined`**
+  Fetches the contents of a file.
+
+**License:** [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/lib/fetch/index.d.ts b/lib/fetch/index.d.ts
new file mode 100644
index 0000000..a3c5838
--- /dev/null
+++ b/lib/fetch/index.d.ts
@@ -0,0 +1,56 @@
+export = fetch;
+
+/**
+ * Node-style callback as used by {@link util.fetch}.
+ * @typedef FetchCallback
+ * @type {function}
+ * @param {?Error} error Error, if any, otherwise `null`
+ * @param {string} [contents] File contents, if there hasn't been an error
+ * @returns {undefined}
+ */
+type FetchCallback = (error: Error, contents?: string) => void;
+
+/**
+ * Options as used by {@link util.fetch}.
+ * @typedef IFetchOptions
+ * @type {Object}
+ * @property {boolean} [binary=false] Whether expecting a binary response
+ * @property {boolean} [xhr=false] If `true`, forces the use of XMLHttpRequest
+ */
+
+interface IFetchOptions {
+    binary?: boolean;
+    xhr?: boolean;
+}
+
+/**
+ * Fetches the contents of a file.
+ * @memberof util
+ * @param {string} filename File path or url
+ * @param {IFetchOptions} options Fetch options
+ * @param {FetchCallback} callback Callback function
+ * @returns {undefined}
+ */
+declare function fetch(filename: string, options: IFetchOptions, callback: FetchCallback): void;
+
+/**
+ * Fetches the contents of a file.
+ * @name util.fetch
+ * @function
+ * @param {string} path File path or url
+ * @param {FetchCallback} callback Callback function
+ * @returns {undefined}
+ * @variation 2
+ */
+declare function fetch(path: string, callback: FetchCallback): void;
+
+/**
+ * Fetches the contents of a file.
+ * @name util.fetch
+ * @function
+ * @param {string} path File path or url
+ * @param {IFetchOptions} [options] Fetch options
+ * @returns {Promise<string|Uint8Array>} Promise
+ * @variation 3
+ */
+declare function fetch(path: string, options?: IFetchOptions): Promise<(string|Uint8Array)>;
diff --git a/lib/fetch/index.js b/lib/fetch/index.js
new file mode 100644
index 0000000..03431d4
--- /dev/null
+++ b/lib/fetch/index.js
@@ -0,0 +1,114 @@
+"use strict";
+module.exports = fetch;
+
+var asPromise = require("@protobufjs/aspromise"),
+    inquire   = require("@protobufjs/inquire");
+
+var fs = inquire("fs");
+
+/**
+ * Node-style callback as used by {@link util.fetch}.
+ * @typedef FetchCallback
+ * @type {function}
+ * @param {?Error} error Error, if any, otherwise `null`
+ * @param {string} [contents] File contents, if there hasn't been an error
+ * @returns {undefined}
+ */
+
+/**
+ * Options as used by {@link util.fetch}.
+ * @interface IFetchOptions
+ * @property {boolean} [binary=false] Whether expecting a binary response
+ * @property {boolean} [xhr=false] If `true`, forces the use of XMLHttpRequest
+ */
+
+/**
+ * Fetches the contents of a file.
+ * @memberof util
+ * @param {string} filename File path or url
+ * @param {IFetchOptions} options Fetch options
+ * @param {FetchCallback} callback Callback function
+ * @returns {undefined}
+ */
+function fetch(filename, options, callback) {
+    if (typeof options === "function") {
+        callback = options;
+        options = {};
+    } else if (!options)
+        options = {};
+
+    if (!callback)
+        return asPromise(fetch, this, filename, options); // eslint-disable-line no-invalid-this
+
+    // if a node-like filesystem is present, try it first but fall back to XHR if nothing is found.
+    if (!options.xhr && fs && fs.readFile)
+        return fs.readFile(filename, function fetchReadFileCallback(err, contents) {
+            return err && typeof XMLHttpRequest !== "undefined"
+                ? fetch.xhr(filename, options, callback)
+                : err
+                ? callback(err)
+                : callback(null, options.binary ? contents : contents.toString("utf8"));
+        });
+
+    // use the XHR version otherwise.
+    return fetch.xhr(filename, options, callback);
+}
+
+/**
+ * Fetches the contents of a file.
+ * @name util.fetch
+ * @function
+ * @param {string} path File path or url
+ * @param {FetchCallback} callback Callback function
+ * @returns {undefined}
+ * @variation 2
+ */
+
+/**
+ * Fetches the contents of a file.
+ * @name util.fetch
+ * @function
+ * @param {string} path File path or url
+ * @param {IFetchOptions} [options] Fetch options
+ * @returns {Promise<string|Uint8Array>} Promise
+ * @variation 3
+ */
+
+/**/
+fetch.xhr = function fetch_xhr(filename, options, callback) {
+    var xhr = new XMLHttpRequest();
+    xhr.onreadystatechange /* works everywhere */ = function fetchOnReadyStateChange() {
+
+        if (xhr.readyState !== 4)
+            return undefined;
+
+        // local cors security errors return status 0 / empty string, too. afaik this cannot be
+        // reliably distinguished from an actually empty file for security reasons. feel free
+        // to send a pull request if you are aware of a solution.
+        if (xhr.status !== 0 && xhr.status !== 200)
+            return callback(Error("status " + xhr.status));
+
+        // if binary data is expected, make sure that some sort of array is returned, even if
+        // ArrayBuffers are not supported. the binary string fallback, however, is unsafe.
+        if (options.binary) {
+            var buffer = xhr.response;
+            if (!buffer) {
+                buffer = [];
+                for (var i = 0; i < xhr.responseText.length; ++i)
+                    buffer.push(xhr.responseText.charCodeAt(i) & 255);
+            }
+            return callback(null, typeof Uint8Array !== "undefined" ? new Uint8Array(buffer) : buffer);
+        }
+        return callback(null, xhr.responseText);
+    };
+
+    if (options.binary) {
+        // ref: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data#Receiving_binary_data_in_older_browsers
+        if ("overrideMimeType" in xhr)
+            xhr.overrideMimeType("text/plain; charset=x-user-defined");
+        xhr.responseType = "arraybuffer";
+    }
+
+    xhr.open("GET", filename);
+    xhr.send();
+};
diff --git a/lib/fetch/package.json b/lib/fetch/package.json
new file mode 100644
index 0000000..6e31f2a
--- /dev/null
+++ b/lib/fetch/package.json
@@ -0,0 +1,25 @@
+{
+  "name": "@protobufjs/fetch",
+  "description": "Fetches the contents of a file accross node and browsers.",
+  "version": "1.1.1",
+  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/dcodeIO/protobuf.js.git"
+  },
+  "dependencies": {
+    "@protobufjs/aspromise": "^1.1.1",
+    "@protobufjs/inquire": "^1.1.0"
+  },
+  "license": "BSD-3-Clause",
+  "main": "index.js",
+  "types": "index.d.ts",
+  "devDependencies": {
+    "istanbul": "^0.4.5",
+    "tape": "^5.0.0"
+  },
+  "scripts": {
+    "test": "tape tests/*.js",
+    "coverage": "istanbul cover node_modules/tape/bin/tape tests/*.js"
+  }
+}
\ No newline at end of file
diff --git a/lib/fetch/tests/data/file.txt b/lib/fetch/tests/data/file.txt
new file mode 100644
index 0000000..4c33073
--- /dev/null
+++ b/lib/fetch/tests/data/file.txt
@@ -0,0 +1 @@
+file.txt
\ No newline at end of file
diff --git a/lib/fetch/tests/index.js b/lib/fetch/tests/index.js
new file mode 100644
index 0000000..81b3e48
--- /dev/null
+++ b/lib/fetch/tests/index.js
@@ -0,0 +1,158 @@
+var tape = require("tape");
+
+var fetch = require("..");
+
+tape.test("fetch", function(test) {
+
+    if (typeof Promise !== "undefined")
+        test.test(test.name + " - promise", function(test) {
+            var promise = fetch("NOTFOUND");
+            test.plan(2);
+            test.ok(promise instanceof Promise, "should return a promise if callback has been omitted");
+            promise
+            .then(function() {
+                test.fail("should not resolve");
+            })
+            .catch(function(err) {
+                test.ok(err, "should reject with an error");
+            });
+        });
+
+    test.test(test.name + " - node fs", function(test) {
+
+        test.test(test.name + " - string", function(test) {
+            test.plan(2);
+            fetch(require.resolve("./data/file.txt"), function(err, contents) {
+                test.notOk(err, "should not return an error");
+                test.equal(contents, "file.txt", "should return contents as a string");
+            });
+        });
+
+        test.test(test.name + " - binary", function(test) {
+            test.plan(2);
+            fetch(require.resolve("./data/file.txt"), { binary: true }, function(err, contents) {
+                test.notOk(err, "should not return an error");
+                test.same(contents, new Buffer("file.txt", "utf8"), "should return contents as a Buffer");
+            });
+        });
+
+        test.test(test.name + " - fallback", function(test) {
+            test.plan(2);
+            global.XMLHttpRequest = fakeXHR(0);
+            fetch("file.txt", function(err, contents) {
+                delete global.XMLHttpRequest;
+                test.notOk(err, "should not return an error");
+                test.same(contents, "file.txt", "should return contents as a string");
+            });
+        });
+
+        test.end();
+    });
+
+    test.test(test.name + " - XMLHttpRequest", function(test) {
+
+        test.test(test.name + " - 404", function(test) {
+            global.XMLHttpRequest = fakeXHR(404);
+            fetch("file.txt", { xhr: true }, function(err) {
+                delete global.XMLHttpRequest;
+                test.ok(err, "should return an error");
+                test.end();
+            });
+        });
+
+        test.test(test.name + " - string", function(test) {
+            global.XMLHttpRequest = fakeXHR(0);
+            test.plan(2);
+            fetch("file.txt", { xhr: true }, function(err, contents) {
+                delete global.XMLHttpRequest;
+                test.notOk(err, "should not return an error");
+                test.equal(contents, "file.txt", "should return contents as a string");
+            });
+        });
+
+        test.test(test.name + " - binary", function(test) {
+            global.XMLHttpRequest = fakeXHR(200);
+            test.plan(2);
+            fetch("file.txt", { xhr: true, binary: true }, function(err, contents) {
+                delete global.XMLHttpRequest;
+                test.notOk(err, "should not return an error");
+                test.same(contents, new Uint8Array([0x66, 0x69, 0x6c, 0x65, 0x2e, 0x74, 0x78, 0x74]), "should return contents as an Uint8Array");
+            });
+        });
+
+    });
+
+    test.test(test.name + " - XMLHttpRequest (ancient)", function(test) {
+
+        test.test(test.name + " - string", function(test) {
+            global.XMLHttpRequest = fakeXHR(0, true);
+            test.plan(2);
+            fetch("file.txt", { xhr: true }, function(err, contents) {
+                delete global.XMLHttpRequest;
+                test.notOk(err, "should not return an error");
+                test.equal(contents, "file.txt", "should return contents as a string");
+            });
+        });
+
+        test.test(test.name + " - binary", function(test) {
+            global.XMLHttpRequest = fakeXHR(200, true);
+            var U8 = global.Uint8Array;
+            delete global.Uint8Array;
+            test.plan(2);
+            fetch("file.txt", { xhr: true, binary: true }, function(err, contents) {
+                delete global.XMLHttpRequest;
+                global.Uint8Array = U8;
+                test.notOk(err, "should not return an error");
+                test.same(contents, [0x66, 0x69, 0x6c, 0x65, 0x2e, 0x74, 0x78, 0x74], "should return contents as an Array");
+            });
+        });
+
+    });
+
+});
+
+function fakeXHR(status, ancient) {
+
+    var UNSENT = 0,
+        OPENED = 1,
+        HEADERS_RECEIVED = 2,
+        LOADING = 3,
+        DONE = 4;
+
+    function XMLHttpRequest() {
+        this.status = 0;
+        this.readyState = UNSENT;
+    }
+    if (!ancient)
+        XMLHttpRequest.prototype.overrideMimeType = function(mimeType) {
+            this._mimeType = mimeType;
+        };
+    XMLHttpRequest.prototype.open = function open(method, path) {
+        this._method = method;
+        this._path = path;
+        this.readyState = OPENED;
+    };
+    XMLHttpRequest.prototype.send = function send() {
+        var self = this;
+        setTimeout(function() {
+            self.onreadystatechange(); // opened
+            self.readyState = HEADERS_RECEIVED;
+            self.onreadystatechange();
+            self.readyState = LOADING;
+            self.onreadystatechange();
+            self.readyState = DONE;
+            self.status = status;
+            if (self.responseType === "arraybuffer" && !ancient) {
+                var buf = new Buffer(self._path, "utf8");
+                var abuf = new ArrayBuffer(buf.length);
+                var view = new Uint8Array(abuf);
+                for (var i = 0; i < buf.length; ++i)
+                    view[i] = buf[i];
+                self.response = abuf;
+            } else
+                self.responseText = self._path;
+            self.onreadystatechange();
+        });
+    };
+    return XMLHttpRequest;
+}
\ No newline at end of file
diff --git a/lib/float/LICENSE b/lib/float/LICENSE
new file mode 100644
index 0000000..be2b397
--- /dev/null
+++ b/lib/float/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2016, Daniel Wirtz  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 its author, 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
diff --git a/lib/float/README.md b/lib/float/README.md
new file mode 100644
index 0000000..c55d285
--- /dev/null
+++ b/lib/float/README.md
@@ -0,0 +1,102 @@
+@protobufjs/float
+=================
+[![npm](https://img.shields.io/npm/v/@protobufjs/float.svg)](https://www.npmjs.com/package/@protobufjs/float)
+
+Reads / writes floats / doubles from / to buffers in both modern and ancient browsers. Fast.
+
+API
+---
+
+* **writeFloatLE(val: `number`, buf: `Uint8Array`, pos: `number`)**<br />
+  Writes a 32 bit float to a buffer using little endian byte order.
+
+* **writeFloatBE(val: `number`, buf: `Uint8Array`, pos: `number`)**<br />
+  Writes a 32 bit float to a buffer using big endian byte order.
+
+* **readFloatLE(buf: `Uint8Array`, pos: `number`): `number`**<br />
+  Reads a 32 bit float from a buffer using little endian byte order.
+
+* **readFloatBE(buf: `Uint8Array`, pos: `number`): `number`**<br />
+  Reads a 32 bit float from a buffer using big endian byte order.
+
+* **writeDoubleLE(val: `number`, buf: `Uint8Array`, pos: `number`)**<br />
+  Writes a 64 bit double to a buffer using little endian byte order.
+
+* **writeDoubleBE(val: `number`, buf: `Uint8Array`, pos: `number`)**<br />
+  Writes a 64 bit double to a buffer using big endian byte order.
+
+* **readDoubleLE(buf: `Uint8Array`, pos: `number`): `number`**<br />
+  Reads a 64 bit double from a buffer using little endian byte order.
+
+* **readDoubleBE(buf: `Uint8Array`, pos: `number`): `number`**<br />
+  Reads a 64 bit double from a buffer using big endian byte order.
+
+Performance
+-----------
+There is a simple benchmark included comparing raw read/write performance of this library (float), float's fallback for old browsers, the [ieee754](https://www.npmjs.com/package/ieee754) module and node's [buffer](https://nodejs.org/api/buffer.html). On an i7-2600k running node 6.9.1 it yields:
+
+```
+benchmarking writeFloat performance ...
+
+float x 42,741,625 ops/sec ±1.75% (81 runs sampled)
+float (fallback) x 11,272,532 ops/sec ±1.12% (85 runs sampled)
+ieee754 x 8,653,337 ops/sec ±1.18% (84 runs sampled)
+buffer x 12,412,414 ops/sec ±1.41% (83 runs sampled)
+buffer (noAssert) x 13,471,149 ops/sec ±1.09% (84 runs sampled)
+
+               float was fastest
+    float (fallback) was 73.5% slower
+             ieee754 was 79.6% slower
+              buffer was 70.9% slower
+   buffer (noAssert) was 68.3% slower
+
+benchmarking readFloat performance ...
+
+float x 44,382,729 ops/sec ±1.70% (84 runs sampled)
+float (fallback) x 20,925,938 ops/sec ±0.86% (87 runs sampled)
+ieee754 x 17,189,009 ops/sec ±1.01% (87 runs sampled)
+buffer x 10,518,437 ops/sec ±1.04% (83 runs sampled)
+buffer (noAssert) x 11,031,636 ops/sec ±1.15% (87 runs sampled)
+
+               float was fastest
+    float (fallback) was 52.5% slower
+             ieee754 was 61.0% slower
+              buffer was 76.1% slower
+   buffer (noAssert) was 75.0% slower
+
+benchmarking writeDouble performance ...
+
+float x 38,624,906 ops/sec ±0.93% (83 runs sampled)
+float (fallback) x 10,457,811 ops/sec ±1.54% (85 runs sampled)
+ieee754 x 7,681,130 ops/sec ±1.11% (83 runs sampled)
+buffer x 12,657,876 ops/sec ±1.03% (83 runs sampled)
+buffer (noAssert) x 13,372,795 ops/sec ±0.84% (85 runs sampled)
+
+               float was fastest
+    float (fallback) was 73.1% slower
+             ieee754 was 80.1% slower
+              buffer was 67.3% slower
+   buffer (noAssert) was 65.3% slower
+
+benchmarking readDouble performance ...
+
+float x 40,527,888 ops/sec ±1.05% (84 runs sampled)
+float (fallback) x 18,696,480 ops/sec ±0.84% (86 runs sampled)
+ieee754 x 14,074,028 ops/sec ±1.04% (87 runs sampled)
+buffer x 10,092,367 ops/sec ±1.15% (84 runs sampled)
+buffer (noAssert) x 10,623,793 ops/sec ±0.96% (84 runs sampled)
+
+               float was fastest
+    float (fallback) was 53.8% slower
+             ieee754 was 65.3% slower
+              buffer was 75.1% slower
+   buffer (noAssert) was 73.8% slower
+```
+
+To run it yourself:
+
+```
+$> npm run bench
+```
+
+**License:** [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/lib/float/bench/index.js b/lib/float/bench/index.js
new file mode 100644
index 0000000..911f461
--- /dev/null
+++ b/lib/float/bench/index.js
@@ -0,0 +1,87 @@
+"use strict";
+
+var float = require(".."),
+    ieee754 = require("ieee754"),
+    newSuite = require("./suite");
+
+var F32 = Float32Array;
+var F64 = Float64Array;
+delete global.Float32Array;
+delete global.Float64Array;
+var floatFallback = float({});
+global.Float32Array = F32;
+global.Float64Array = F64;
+
+var buf = new Buffer(8);
+
+newSuite("writeFloat")
+.add("float", function() {
+    float.writeFloatLE(0.1, buf, 0);
+})
+.add("float (fallback)", function() {
+    floatFallback.writeFloatLE(0.1, buf, 0);
+})
+.add("ieee754", function() {
+    ieee754.write(buf, 0.1, 0, true, 23, 4);
+})
+.add("buffer", function() {
+    buf.writeFloatLE(0.1, 0);
+})
+.add("buffer (noAssert)", function() {
+    buf.writeFloatLE(0.1, 0, true);
+})
+.run();
+
+newSuite("readFloat")
+.add("float", function() {
+    float.readFloatLE(buf, 0);
+})
+.add("float (fallback)", function() {
+    floatFallback.readFloatLE(buf, 0);
+})
+.add("ieee754", function() {
+    ieee754.read(buf, 0, true, 23, 4);
+})
+.add("buffer", function() {
+    buf.readFloatLE(0);
+})
+.add("buffer (noAssert)", function() {
+    buf.readFloatLE(0, true);
+})
+.run();
+
+newSuite("writeDouble")
+.add("float", function() {
+    float.writeDoubleLE(0.1, buf, 0);
+})
+.add("float (fallback)", function() {
+    floatFallback.writeDoubleLE(0.1, buf, 0);
+})
+.add("ieee754", function() {
+    ieee754.write(buf, 0.1, 0, true, 52, 8);
+})
+.add("buffer", function() {
+    buf.writeDoubleLE(0.1, 0);
+})
+.add("buffer (noAssert)", function() {
+    buf.writeDoubleLE(0.1, 0, true);
+})
+.run();
+
+newSuite("readDouble")
+.add("float", function() {
+    float.readDoubleLE(buf, 0);
+})
+.add("float (fallback)", function() {
+    floatFallback.readDoubleLE(buf, 0);
+})
+.add("ieee754", function() {
+    ieee754.read(buf, 0, true, 52, 8);
+})
+.add("buffer", function() {
+    buf.readDoubleLE(0);
+})
+.add("buffer (noAssert)", function() {
+    buf.readDoubleLE(0, true);
+})
+.run();
diff --git a/lib/float/bench/suite.js b/lib/float/bench/suite.js
new file mode 100644
index 0000000..28cbc1a
--- /dev/null
+++ b/lib/float/bench/suite.js
@@ -0,0 +1,46 @@
+"use strict";
+module.exports = newSuite;
+
+var benchmark = require("benchmark"),
+    chalk     = require("chalk");
+
+var padSize = 20;
+
+function newSuite(name) {
+    var benches = [];
+    return new benchmark.Suite(name)
+    .on("add", function(event) {
+        benches.push(event.target);
+    })
+    .on("start", function() {
+        process.stdout.write("benchmarking " + name + " performance ...\n\n");
+    })
+    .on("cycle", function(event) {
+        process.stdout.write(String(event.target) + "\n");
+    })
+    .on("complete", function() {
+        if (benches.length > 1) {
+            var fastest = this.filter("fastest"), // eslint-disable-line no-invalid-this
+                fastestHz = getHz(fastest[0]);
+            process.stdout.write("\n" + chalk.white(pad(fastest[0].name, padSize)) + " was " + chalk.green("fastest") + "\n");
+            benches.forEach(function(bench) {
+                if (fastest.indexOf(bench) === 0)
+                    return;
+                var hz = hz = getHz(bench);
+                var percent = (1 - hz / fastestHz) * 100;
+                process.stdout.write(chalk.white(pad(bench.name, padSize)) + " was " + chalk.red(percent.toFixed(1) + "% slower") + "\n");
+            });
+        }
+        process.stdout.write("\n");
+    });
+}
+
+function getHz(bench) {
+    return 1 / (bench.stats.mean + bench.stats.moe);
+}
+
+function pad(str, len, l) {
+    while (str.length < len)
+        str = l ? str + " " : " " + str;
+    return str;
+}
diff --git a/lib/float/index.d.ts b/lib/float/index.d.ts
new file mode 100644
index 0000000..ab05de3
--- /dev/null
+++ b/lib/float/index.d.ts
@@ -0,0 +1,83 @@
+/**
+ * Writes a 32 bit float to a buffer using little endian byte order.
+ * @name writeFloatLE
+ * @function
+ * @param {number} val Value to write
+ * @param {Uint8Array} buf Target buffer
+ * @param {number} pos Target buffer offset
+ * @returns {undefined}
+ */
+export function writeFloatLE(val: number, buf: Uint8Array, pos: number): void;
+
+/**
+ * Writes a 32 bit float to a buffer using big endian byte order.
+ * @name writeFloatBE
+ * @function
+ * @param {number} val Value to write
+ * @param {Uint8Array} buf Target buffer
+ * @param {number} pos Target buffer offset
+ * @returns {undefined}
+ */
+export function writeFloatBE(val: number, buf: Uint8Array, pos: number): void;
+
+/**
+ * Reads a 32 bit float from a buffer using little endian byte order.
+ * @name readFloatLE
+ * @function
+ * @param {Uint8Array} buf Source buffer
+ * @param {number} pos Source buffer offset
+ * @returns {number} Value read
+ */
+export function readFloatLE(buf: Uint8Array, pos: number): number;
+
+/**
+ * Reads a 32 bit float from a buffer using big endian byte order.
+ * @name readFloatBE
+ * @function
+ * @param {Uint8Array} buf Source buffer
+ * @param {number} pos Source buffer offset
+ * @returns {number} Value read
+ */
+export function readFloatBE(buf: Uint8Array, pos: number): number;
+
+/**
+ * Writes a 64 bit double to a buffer using little endian byte order.
+ * @name writeDoubleLE
+ * @function
+ * @param {number} val Value to write
+ * @param {Uint8Array} buf Target buffer
+ * @param {number} pos Target buffer offset
+ * @returns {undefined}
+ */
+export function writeDoubleLE(val: number, buf: Uint8Array, pos: number): void;
+
+/**
+ * Writes a 64 bit double to a buffer using big endian byte order.
+ * @name writeDoubleBE
+ * @function
+ * @param {number} val Value to write
+ * @param {Uint8Array} buf Target buffer
+ * @param {number} pos Target buffer offset
+ * @returns {undefined}
+ */
+export function writeDoubleBE(val: number, buf: Uint8Array, pos: number): void;
+
+/**
+ * Reads a 64 bit double from a buffer using little endian byte order.
+ * @name readDoubleLE
+ * @function
+ * @param {Uint8Array} buf Source buffer
+ * @param {number} pos Source buffer offset
+ * @returns {number} Value read
+ */
+export function readDoubleLE(buf: Uint8Array, pos: number): number;
+
+/**
+ * Reads a 64 bit double from a buffer using big endian byte order.
+ * @name readDoubleBE
+ * @function
+ * @param {Uint8Array} buf Source buffer
+ * @param {number} pos Source buffer offset
+ * @returns {number} Value read
+ */
+export function readDoubleBE(buf: Uint8Array, pos: number): number;
diff --git a/lib/float/index.js b/lib/float/index.js
new file mode 100644
index 0000000..52ba3aa
--- /dev/null
+++ b/lib/float/index.js
@@ -0,0 +1,335 @@
+"use strict";
+
+module.exports = factory(factory);
+
+/**
+ * Reads / writes floats / doubles from / to buffers.
+ * @name util.float
+ * @namespace
+ */
+
+/**
+ * Writes a 32 bit float to a buffer using little endian byte order.
+ * @name util.float.writeFloatLE
+ * @function
+ * @param {number} val Value to write
+ * @param {Uint8Array} buf Target buffer
+ * @param {number} pos Target buffer offset
+ * @returns {undefined}
+ */
+
+/**
+ * Writes a 32 bit float to a buffer using big endian byte order.
+ * @name util.float.writeFloatBE
+ * @function
+ * @param {number} val Value to write
+ * @param {Uint8Array} buf Target buffer
+ * @param {number} pos Target buffer offset
+ * @returns {undefined}
+ */
+
+/**
+ * Reads a 32 bit float from a buffer using little endian byte order.
+ * @name util.float.readFloatLE
+ * @function
+ * @param {Uint8Array} buf Source buffer
+ * @param {number} pos Source buffer offset
+ * @returns {number} Value read
+ */
+
+/**
+ * Reads a 32 bit float from a buffer using big endian byte order.
+ * @name util.float.readFloatBE
+ * @function
+ * @param {Uint8Array} buf Source buffer
+ * @param {number} pos Source buffer offset
+ * @returns {number} Value read
+ */
+
+/**
+ * Writes a 64 bit double to a buffer using little endian byte order.
+ * @name util.float.writeDoubleLE
+ * @function
+ * @param {number} val Value to write
+ * @param {Uint8Array} buf Target buffer
+ * @param {number} pos Target buffer offset
+ * @returns {undefined}
+ */
+
+/**
+ * Writes a 64 bit double to a buffer using big endian byte order.
+ * @name util.float.writeDoubleBE
+ * @function
+ * @param {number} val Value to write
+ * @param {Uint8Array} buf Target buffer
+ * @param {number} pos Target buffer offset
+ * @returns {undefined}
+ */
+
+/**
+ * Reads a 64 bit double from a buffer using little endian byte order.
+ * @name util.float.readDoubleLE
+ * @function
+ * @param {Uint8Array} buf Source buffer
+ * @param {number} pos Source buffer offset
+ * @returns {number} Value read
+ */
+
+/**
+ * Reads a 64 bit double from a buffer using big endian byte order.
+ * @name util.float.readDoubleBE
+ * @function
+ * @param {Uint8Array} buf Source buffer
+ * @param {number} pos Source buffer offset
+ * @returns {number} Value read
+ */
+
+// Factory function for the purpose of node-based testing in modified global environments
+function factory(exports) {
+
+    // float: typed array
+    if (typeof Float32Array !== "undefined") (function() {
+
+        var f32 = new Float32Array([ -0 ]),
+            f8b = new Uint8Array(f32.buffer),
+            le  = f8b[3] === 128;
+
+        function writeFloat_f32_cpy(val, buf, pos) {
+            f32[0] = val;
+            buf[pos    ] = f8b[0];
+            buf[pos + 1] = f8b[1];
+            buf[pos + 2] = f8b[2];
+            buf[pos + 3] = f8b[3];
+        }
+
+        function writeFloat_f32_rev(val, buf, pos) {
+            f32[0] = val;
+            buf[pos    ] = f8b[3];
+            buf[pos + 1] = f8b[2];
+            buf[pos + 2] = f8b[1];
+            buf[pos + 3] = f8b[0];
+        }
+
+        /* istanbul ignore next */
+        exports.writeFloatLE = le ? writeFloat_f32_cpy : writeFloat_f32_rev;
+        /* istanbul ignore next */
+        exports.writeFloatBE = le ? writeFloat_f32_rev : writeFloat_f32_cpy;
+
+        function readFloat_f32_cpy(buf, pos) {
+            f8b[0] = buf[pos    ];
+            f8b[1] = buf[pos + 1];
+            f8b[2] = buf[pos + 2];
+            f8b[3] = buf[pos + 3];
+            return f32[0];
+        }
+
+        function readFloat_f32_rev(buf, pos) {
+            f8b[3] = buf[pos    ];
+            f8b[2] = buf[pos + 1];
+            f8b[1] = buf[pos + 2];
+            f8b[0] = buf[pos + 3];
+            return f32[0];
+        }
+
+        /* istanbul ignore next */
+        exports.readFloatLE = le ? readFloat_f32_cpy : readFloat_f32_rev;
+        /* istanbul ignore next */
+        exports.readFloatBE = le ? readFloat_f32_rev : readFloat_f32_cpy;
+
+    // float: ieee754
+    })(); else (function() {
+
+        function writeFloat_ieee754(writeUint, val, buf, pos) {
+            var sign = val < 0 ? 1 : 0;
+            if (sign)
+                val = -val;
+            if (val === 0)
+                writeUint(1 / val > 0 ? /* positive */ 0 : /* negative 0 */ 2147483648, buf, pos);
+            else if (isNaN(val))
+                writeUint(2143289344, buf, pos);
+            else if (val > 3.4028234663852886e+38) // +-Infinity
+                writeUint((sign << 31 | 2139095040) >>> 0, buf, pos);
+            else if (val < 1.1754943508222875e-38) // denormal
+                writeUint((sign << 31 | Math.round(val / 1.401298464324817e-45)) >>> 0, buf, pos);
+            else {
+                var exponent = Math.floor(Math.log(val) / Math.LN2),
+                    mantissa = Math.round(val * Math.pow(2, -exponent) * 8388608) & 8388607;
+                writeUint((sign << 31 | exponent + 127 << 23 | mantissa) >>> 0, buf, pos);
+            }
+        }
+
+        exports.writeFloatLE = writeFloat_ieee754.bind(null, writeUintLE);
+        exports.writeFloatBE = writeFloat_ieee754.bind(null, writeUintBE);
+
+        function readFloat_ieee754(readUint, buf, pos) {
+            var uint = readUint(buf, pos),
+                sign = (uint >> 31) * 2 + 1,
+                exponent = uint >>> 23 & 255,
+                mantissa = uint & 8388607;
+            return exponent === 255
+                ? mantissa
+                ? NaN
+                : sign * Infinity
+                : exponent === 0 // denormal
+                ? sign * 1.401298464324817e-45 * mantissa
+                : sign * Math.pow(2, exponent - 150) * (mantissa + 8388608);
+        }
+
+        exports.readFloatLE = readFloat_ieee754.bind(null, readUintLE);
+        exports.readFloatBE = readFloat_ieee754.bind(null, readUintBE);
+
+    })();
+
+    // double: typed array
+    if (typeof Float64Array !== "undefined") (function() {
+
+        var f64 = new Float64Array([-0]),
+            f8b = new Uint8Array(f64.buffer),
+            le  = f8b[7] === 128;
+
+        function writeDouble_f64_cpy(val, buf, pos) {
+            f64[0] = val;
+            buf[pos    ] = f8b[0];
+            buf[pos + 1] = f8b[1];
+            buf[pos + 2] = f8b[2];
+            buf[pos + 3] = f8b[3];
+            buf[pos + 4] = f8b[4];
+            buf[pos + 5] = f8b[5];
+            buf[pos + 6] = f8b[6];
+            buf[pos + 7] = f8b[7];
+        }
+
+        function writeDouble_f64_rev(val, buf, pos) {
+            f64[0] = val;
+            buf[pos    ] = f8b[7];
+            buf[pos + 1] = f8b[6];
+            buf[pos + 2] = f8b[5];
+            buf[pos + 3] = f8b[4];
+            buf[pos + 4] = f8b[3];
+            buf[pos + 5] = f8b[2];
+            buf[pos + 6] = f8b[1];
+            buf[pos + 7] = f8b[0];
+        }
+
+        /* istanbul ignore next */
+        exports.writeDoubleLE = le ? writeDouble_f64_cpy : writeDouble_f64_rev;
+        /* istanbul ignore next */
+        exports.writeDoubleBE = le ? writeDouble_f64_rev : writeDouble_f64_cpy;
+
+        function readDouble_f64_cpy(buf, pos) {
+            f8b[0] = buf[pos    ];
+            f8b[1] = buf[pos + 1];
+            f8b[2] = buf[pos + 2];
+            f8b[3] = buf[pos + 3];
+            f8b[4] = buf[pos + 4];
+            f8b[5] = buf[pos + 5];
+            f8b[6] = buf[pos + 6];
+            f8b[7] = buf[pos + 7];
+            return f64[0];
+        }
+
+        function readDouble_f64_rev(buf, pos) {
+            f8b[7] = buf[pos    ];
+            f8b[6] = buf[pos + 1];
+            f8b[5] = buf[pos + 2];
+            f8b[4] = buf[pos + 3];
+            f8b[3] = buf[pos + 4];
+            f8b[2] = buf[pos + 5];
+            f8b[1] = buf[pos + 6];
+            f8b[0] = buf[pos + 7];
+            return f64[0];
+        }
+
+        /* istanbul ignore next */
+        exports.readDoubleLE = le ? readDouble_f64_cpy : readDouble_f64_rev;
+        /* istanbul ignore next */
+        exports.readDoubleBE = le ? readDouble_f64_rev : readDouble_f64_cpy;
+
+    // double: ieee754
+    })(); else (function() {
+
+        function writeDouble_ieee754(writeUint, off0, off1, val, buf, pos) {
+            var sign = val < 0 ? 1 : 0;
+            if (sign)
+                val = -val;
+            if (val === 0) {
+                writeUint(0, buf, pos + off0);
+                writeUint(1 / val > 0 ? /* positive */ 0 : /* negative 0 */ 2147483648, buf, pos + off1);
+            } else if (isNaN(val)) {
+                writeUint(0, buf, pos + off0);
+                writeUint(2146959360, buf, pos + off1);
+            } else if (val > 1.7976931348623157e+308) { // +-Infinity
+                writeUint(0, buf, pos + off0);
+                writeUint((sign << 31 | 2146435072) >>> 0, buf, pos + off1);
+            } else {
+                var mantissa;
+                if (val < 2.2250738585072014e-308) { // denormal
+                    mantissa = val / 5e-324;
+                    writeUint(mantissa >>> 0, buf, pos + off0);
+                    writeUint((sign << 31 | mantissa / 4294967296) >>> 0, buf, pos + off1);
+                } else {
+                    var exponent = Math.floor(Math.log(val) / Math.LN2);
+                    if (exponent === 1024)
+                        exponent = 1023;
+                    mantissa = val * Math.pow(2, -exponent);
+                    writeUint(mantissa * 4503599627370496 >>> 0, buf, pos + off0);
+                    writeUint((sign << 31 | exponent + 1023 << 20 | mantissa * 1048576 & 1048575) >>> 0, buf, pos + off1);
+                }
+            }
+        }
+
+        exports.writeDoubleLE = writeDouble_ieee754.bind(null, writeUintLE, 0, 4);
+        exports.writeDoubleBE = writeDouble_ieee754.bind(null, writeUintBE, 4, 0);
+
+        function readDouble_ieee754(readUint, off0, off1, buf, pos) {
+            var lo = readUint(buf, pos + off0),
+                hi = readUint(buf, pos + off1);
+            var sign = (hi >> 31) * 2 + 1,
+                exponent = hi >>> 20 & 2047,
+                mantissa = 4294967296 * (hi & 1048575) + lo;
+            return exponent === 2047
+                ? mantissa
+                ? NaN
+                : sign * Infinity
+                : exponent === 0 // denormal
+                ? sign * 5e-324 * mantissa
+                : sign * Math.pow(2, exponent - 1075) * (mantissa + 4503599627370496);
+        }
+
+        exports.readDoubleLE = readDouble_ieee754.bind(null, readUintLE, 0, 4);
+        exports.readDoubleBE = readDouble_ieee754.bind(null, readUintBE, 4, 0);
+
+    })();
+
+    return exports;
+}
+
+// uint helpers
+
+function writeUintLE(val, buf, pos) {
+    buf[pos    ] =  val        & 255;
+    buf[pos + 1] =  val >>> 8  & 255;
+    buf[pos + 2] =  val >>> 16 & 255;
+    buf[pos + 3] =  val >>> 24;
+}
+
+function writeUintBE(val, buf, pos) {
+    buf[pos    ] =  val >>> 24;
+    buf[pos + 1] =  val >>> 16 & 255;
+    buf[pos + 2] =  val >>> 8  & 255;
+    buf[pos + 3] =  val        & 255;
+}
+
+function readUintLE(buf, pos) {
+    return (buf[pos    ]
+          | buf[pos + 1] << 8
+          | buf[pos + 2] << 16
+          | buf[pos + 3] << 24) >>> 0;
+}
+
+function readUintBE(buf, pos) {
+    return (buf[pos    ] << 24
+          | buf[pos + 1] << 16
+          | buf[pos + 2] << 8
+          | buf[pos + 3]) >>> 0;
+}
diff --git a/lib/float/package.json b/lib/float/package.json
new file mode 100644
index 0000000..98ae51d
--- /dev/null
+++ b/lib/float/package.json
@@ -0,0 +1,26 @@
+{
+  "name": "@protobufjs/float",
+  "description": "Reads / writes floats / doubles from / to buffers in both modern and ancient browsers.",
+  "version": "1.0.2",
+  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/dcodeIO/protobuf.js.git"
+  },
+  "dependencies": {},
+  "license": "BSD-3-Clause",
+  "main": "index.js",
+  "types": "index.d.ts",
+  "devDependencies": {
+    "benchmark": "^2.1.4",
+    "chalk": "^4.0.0",
+    "ieee754": "^1.1.8",
+    "istanbul": "^0.4.5",
+    "tape": "^5.0.0"
+  },
+  "scripts": {
+    "test": "tape tests/*.js",
+    "coverage": "istanbul cover node_modules/tape/bin/tape tests/*.js",
+    "bench": "node bench"
+  }
+}
\ No newline at end of file
diff --git a/lib/float/tests/index.js b/lib/float/tests/index.js
new file mode 100644
index 0000000..62f0827
--- /dev/null
+++ b/lib/float/tests/index.js
@@ -0,0 +1,100 @@
+var tape = require("tape");
+
+var float = require("..");
+
+tape.test("float", function(test) {
+
+    // default
+    test.test(test.name + " - typed array", function(test) {
+        runTest(float, test);
+    });
+
+    // ieee754
+    test.test(test.name + " - fallback", function(test) {
+        var F32 = global.Float32Array,
+            F64 = global.Float64Array;
+        delete global.Float32Array;
+        delete global.Float64Array;
+        runTest(float({}), test);
+        global.Float32Array = F32;
+        global.Float64Array = F64;
+    });
+});
+
+function runTest(float, test) {
+
+    var common = [
+        0,
+        -0,
+        Infinity,
+        -Infinity,
+        0.125,
+        1024.5,
+        -4096.5,
+        NaN
+    ];
+
+    test.test(test.name + " - using 32 bits", function(test) {
+        common.concat([
+            3.4028234663852886e+38,
+            1.1754943508222875e-38,
+            1.1754946310819804e-39
+        ])
+        .forEach(function(value) {
+            var strval = value === 0 && 1 / value < 0 ? "-0" : value.toString();
+            test.ok(
+                checkValue(value, 4, float.readFloatLE, float.writeFloatLE, Buffer.prototype.writeFloatLE),
+                "should write and read back " + strval + " (32 bit LE)"
+            );
+            test.ok(
+                checkValue(value, 4, float.readFloatBE, float.writeFloatBE, Buffer.prototype.writeFloatBE),
+                "should write and read back " + strval + " (32 bit BE)"
+            );
+        });
+        test.end();
+    });
+
+    test.test(test.name + " - using 64 bits", function(test) {
+        common.concat([
+            1.7976931348623157e+308,
+            2.2250738585072014e-308,
+            2.2250738585072014e-309
+        ])
+        .forEach(function(value) {
+            var strval = value === 0 && 1 / value < 0 ? "-0" : value.toString();
+            test.ok(
+                checkValue(value, 8, float.readDoubleLE, float.writeDoubleLE, Buffer.prototype.writeDoubleLE),
+                "should write and read back " + strval + " (64 bit LE)"
+            );
+            test.ok(
+                checkValue(value, 8, float.readDoubleBE, float.writeDoubleBE, Buffer.prototype.writeDoubleBE),
+                "should write and read back " + strval + " (64 bit BE)"
+            );
+        });
+        test.end();
+    });
+
+    test.end();
+}
+
+function checkValue(value, size, read, write, write_comp) {
+    var buffer = new Buffer(size);
+    write(value, buffer, 0);
+    var value_comp = read(buffer, 0);
+    var strval = value === 0 && 1 / value < 0 ? "-0" : value.toString();
+    if (value !== value) {
+        if (value_comp === value_comp)
+            return false;
+    } else if (value_comp !== value)
+        return false;
+
+    var buffer_comp = new Buffer(size);
+    write_comp.call(buffer_comp, value, 0);
+    for (var i = 0; i < size; ++i)
+        if (buffer[i] !== buffer_comp[i]) {
+            console.error(">", buffer, buffer_comp);
+            return false;
+        }
+
+    return true;
+}
\ No newline at end of file
diff --git a/lib/inquire/LICENSE b/lib/inquire/LICENSE
new file mode 100644
index 0000000..be2b397
--- /dev/null
+++ b/lib/inquire/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2016, Daniel Wirtz  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 its author, 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
diff --git a/lib/inquire/README.md b/lib/inquire/README.md
new file mode 100644
index 0000000..3eabd86
--- /dev/null
+++ b/lib/inquire/README.md
@@ -0,0 +1,13 @@
+@protobufjs/inquire
+===================
+[![npm](https://img.shields.io/npm/v/@protobufjs/inquire.svg)](https://www.npmjs.com/package/@protobufjs/inquire)
+
+Requires a module only if available and hides the require call from bundlers.
+
+API
+---
+
+* **inquire(moduleName: `string`): `?Object`**<br />
+  Requires a module only if available.
+
+**License:** [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/lib/inquire/index.d.ts b/lib/inquire/index.d.ts
new file mode 100644
index 0000000..ac49c6b
--- /dev/null
+++ b/lib/inquire/index.d.ts
@@ -0,0 +1,9 @@
+export = inquire;
+
+/**
+ * Requires a module only if available.
+ * @memberof util
+ * @param {string} moduleName Module to require
+ * @returns {?Object} Required module if available and not empty, otherwise `null`
+ */
+declare function inquire(moduleName: string): object;
diff --git a/lib/inquire/index.js b/lib/inquire/index.js
new file mode 100644
index 0000000..259011b
--- /dev/null
+++ b/lib/inquire/index.js
@@ -0,0 +1,32 @@
+"use strict";
+module.exports = inquire;
+
+/**
+ * Requires a module only if available.
+ * @memberof util
+ * @param {string} moduleName Module to require
+ * @returns {?Object} Required module if available and not empty, otherwise `null`
+ */
+function inquire(moduleName) {
+    try {
+        var mod = eval("quire".replace(/^/,"re"))(moduleName); // eslint-disable-line no-eval
+        if (mod && (mod.length || Object.keys(mod).length))
+            return mod;
+    } catch (e) {} // eslint-disable-line no-empty
+    return null;
+}
+
+/*
+// maybe worth a shot to prevent renaming issues:
+// see: https://github.com/webpack/webpack/blob/master/lib/dependencies/CommonJsRequireDependencyParserPlugin.js
+// triggers on:
+// - expression require.cache
+// - expression require (???)
+// - call require
+// - call require:commonjs:item
+// - call require:commonjs:context
+
+Object.defineProperty(Function.prototype, "__self", { get: function() { return this; } });
+var r = require.__self;
+delete Function.prototype.__self;
+*/
diff --git a/lib/inquire/package.json b/lib/inquire/package.json
new file mode 100644
index 0000000..564a99b
--- /dev/null
+++ b/lib/inquire/package.json
@@ -0,0 +1,21 @@
+{
+  "name": "@protobufjs/inquire",
+  "description": "Requires a module only if available and hides the require call from bundlers.",
+  "version": "1.1.0",
+  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/dcodeIO/protobuf.js.git"
+  },
+  "license": "BSD-3-Clause",
+  "main": "index.js",
+  "types": "index.d.ts",
+  "devDependencies": {
+    "istanbul": "^0.4.5",
+    "tape": "^5.0.0"
+  },
+  "scripts": {
+    "test": "tape tests/*.js",
+    "coverage": "istanbul cover node_modules/tape/bin/tape tests/*.js"
+  }
+}
\ No newline at end of file
diff --git a/lib/inquire/tests/data/array.js b/lib/inquire/tests/data/array.js
new file mode 100644
index 0000000..0847b28
--- /dev/null
+++ b/lib/inquire/tests/data/array.js
@@ -0,0 +1 @@
+module.exports = [1];
diff --git a/lib/inquire/tests/data/emptyArray.js b/lib/inquire/tests/data/emptyArray.js
new file mode 100644
index 0000000..e0a30c5
--- /dev/null
+++ b/lib/inquire/tests/data/emptyArray.js
@@ -0,0 +1 @@
+module.exports = [];
diff --git a/lib/inquire/tests/data/emptyObject.js b/lib/inquire/tests/data/emptyObject.js
new file mode 100644
index 0000000..f053ebf
--- /dev/null
+++ b/lib/inquire/tests/data/emptyObject.js
@@ -0,0 +1 @@
+module.exports = {};
diff --git a/lib/inquire/tests/data/object.js b/lib/inquire/tests/data/object.js
new file mode 100644
index 0000000..3b75bca
--- /dev/null
+++ b/lib/inquire/tests/data/object.js
@@ -0,0 +1 @@
+module.exports = { a: 1 };
diff --git a/lib/inquire/tests/index.js b/lib/inquire/tests/index.js
new file mode 100644
index 0000000..4a555ca
--- /dev/null
+++ b/lib/inquire/tests/index.js
@@ -0,0 +1,20 @@
+var tape = require("tape");
+
+var inquire = require("..");
+
+tape.test("inquire", function(test) {
+
+    test.equal(inquire("buffer").Buffer, Buffer, "should be able to require \"buffer\"");
+
+    test.equal(inquire("%invalid"), null, "should not be able to require \"%invalid\"");
+
+    test.equal(inquire("./tests/data/emptyObject"), null, "should return null when requiring a module exporting an empty object");
+
+    test.equal(inquire("./tests/data/emptyArray"), null, "should return null when requiring a module exporting an empty array");
+
+    test.same(inquire("./tests/data/object"), { a: 1 }, "should return the object if a non-empty object");
+
+    test.same(inquire("./tests/data/array"), [ 1 ], "should return the module if a non-empty array");
+
+    test.end();
+});
diff --git a/lib/path/LICENSE b/lib/path/LICENSE
new file mode 100644
index 0000000..be2b397
--- /dev/null
+++ b/lib/path/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2016, Daniel Wirtz  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 its author, 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
diff --git a/lib/path/README.md b/lib/path/README.md
new file mode 100644
index 0000000..1c1a2ba
--- /dev/null
+++ b/lib/path/README.md
@@ -0,0 +1,19 @@
+@protobufjs/path
+================
+[![npm](https://img.shields.io/npm/v/@protobufjs/path.svg)](https://www.npmjs.com/package/@protobufjs/path)
+
+A minimal path module to resolve Unix, Windows and URL paths alike.
+
+API
+---
+
+* **path.isAbsolute(path: `string`): `boolean`**<br />
+  Tests if the specified path is absolute.
+
+* **path.normalize(path: `string`): `string`**<br />
+  Normalizes the specified path.
+
+* **path.resolve(originPath: `string`, includePath: `string`, [alreadyNormalized=false: `boolean`]): `string`**<br />
+  Resolves the specified include path against the specified origin path.
+
+**License:** [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/lib/path/index.d.ts b/lib/path/index.d.ts
new file mode 100644
index 0000000..b664d81
--- /dev/null
+++ b/lib/path/index.d.ts
@@ -0,0 +1,22 @@
+/**
+ * Tests if the specified path is absolute.
+ * @param {string} path Path to test
+ * @returns {boolean} `true` if path is absolute
+ */
+export function isAbsolute(path: string): boolean;
+
+/**
+ * Normalizes the specified path.
+ * @param {string} path Path to normalize
+ * @returns {string} Normalized path
+ */
+export function normalize(path: string): string;
+
+/**
+ * Resolves the specified include path against the specified origin path.
+ * @param {string} originPath Path to the origin file
+ * @param {string} includePath Include path relative to origin path
+ * @param {boolean} [alreadyNormalized=false] `true` if both paths are already known to be normalized
+ * @returns {string} Path to the include file
+ */
+export function resolve(originPath: string, includePath: string, alreadyNormalized?: boolean): string;
diff --git a/lib/path/index.js b/lib/path/index.js
new file mode 100644
index 0000000..8c7ee12
--- /dev/null
+++ b/lib/path/index.js
@@ -0,0 +1,72 @@
+"use strict";
+
+/**
+ * A minimal path module to resolve Unix, Windows and URL paths alike.
+ * @memberof util
+ * @namespace
+ */
+var path = exports;
+
+var isAbsolute =
+/**
+ * Tests if the specified path is absolute.
+ * @param {string} path Path to test
+ * @returns {boolean} `true` if path is absolute
+ */
+path.isAbsolute = function isAbsolute(path) {
+    return /^(?:\/|\w+:|\\\\\w+)/.test(path);
+};
+
+var normalize =
+/**
+ * Normalizes the specified path.
+ * @param {string} path Path to normalize
+ * @returns {string} Normalized path
+ */
+path.normalize = function normalize(path) {
+    var firstTwoCharacters = path.substring(0,2);
+    var uncPrefix = "";
+    if (firstTwoCharacters === "\\\\") {
+        uncPrefix = firstTwoCharacters;
+        path = path.substring(2);
+    }
+
+    path = path.replace(/\\/g, "/")
+               .replace(/\/{2,}/g, "/");
+    var parts    = path.split("/"),
+        absolute = isAbsolute(path),
+        prefix   = "";
+    if (absolute)
+        prefix = parts.shift() + "/";
+    for (var i = 0; i < parts.length;) {
+        if (parts[i] === "..") {
+            if (i > 0 && parts[i - 1] !== "..")
+                parts.splice(--i, 2);
+            else if (absolute)
+                parts.splice(i, 1);
+            else
+                ++i;
+        } else if (parts[i] === ".")
+            parts.splice(i, 1);
+        else
+            ++i;
+    }
+    return uncPrefix + prefix + parts.join("/");
+};
+
+/**
+ * Resolves the specified include path against the specified origin path.
+ * @param {string} originPath Path to the origin file
+ * @param {string} includePath Include path relative to origin path
+ * @param {boolean} [alreadyNormalized=false] `true` if both paths are already known to be normalized
+ * @returns {string} Path to the include file
+ */
+path.resolve = function resolve(originPath, includePath, alreadyNormalized) {
+    if (!alreadyNormalized)
+        includePath = normalize(includePath);
+    if (isAbsolute(includePath))
+        return includePath;
+    if (!alreadyNormalized)
+        originPath = normalize(originPath);
+    return (originPath = originPath.replace(/(?:\/|^)[^/]+$/, "")).length ? normalize(originPath + "/" + includePath) : includePath;
+};
diff --git a/lib/path/package.json b/lib/path/package.json
new file mode 100644
index 0000000..c93bb85
--- /dev/null
+++ b/lib/path/package.json
@@ -0,0 +1,21 @@
+{
+  "name": "@protobufjs/path",
+  "description": "A minimal path module to resolve Unix, Windows and URL paths alike.",
+  "version": "1.1.2",
+  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/dcodeIO/protobuf.js.git"
+  },
+  "license": "BSD-3-Clause",
+  "main": "index.js",
+  "types": "index.d.ts",
+  "devDependencies": {
+    "istanbul": "^0.4.5",
+    "tape": "^5.0.0"
+  },
+  "scripts": {
+    "test": "tape tests/*.js",
+    "coverage": "istanbul cover node_modules/tape/bin/tape tests/*.js"
+  }
+}
\ No newline at end of file
diff --git a/lib/path/tests/index.js b/lib/path/tests/index.js
new file mode 100644
index 0000000..6b61556
--- /dev/null
+++ b/lib/path/tests/index.js
@@ -0,0 +1,76 @@
+var tape = require("tape");
+
+var path = require("..");
+
+tape.test("path", function(test) {
+
+    test.ok(path.isAbsolute("X:\\some\\path\\file.js"), "should identify absolute windows paths");
+    test.ok(path.isAbsolute("/some/path/file.js"), "should identify absolute unix paths");
+
+    test.notOk(path.isAbsolute("some\\path\\file.js"), "should identify relative windows paths");
+    test.notOk(path.isAbsolute("some/path/file.js"), "should identify relative unix paths");
+
+    test.ok(path.isAbsolute("\\\\some-unc\\path\\file.js"), "should identify windows unc paths");
+
+    var paths = [
+        {
+            actual: "X:\\some\\..\\.\\path\\\\file.js",
+            normal: "X:/path/file.js",
+            resolve: {
+                origin: "X:/path/origin.js",
+                expected: "X:/path/file.js"
+            }
+        }, {
+            actual: "some\\..\\.\\path\\\\file.js",
+            normal: "path/file.js",
+            resolve: {
+                origin: "X:/path/origin.js",
+                expected: "X:/path/path/file.js"
+            }
+        }, {
+            actual: "/some/.././path//file.js",
+            normal: "/path/file.js",
+            resolve: {
+                origin: "/path/origin.js",
+                expected: "/path/file.js"
+            }
+        }, {
+            actual: "some/.././path//file.js",
+            normal: "path/file.js",
+            resolve: {
+                origin: "",
+                expected: "path/file.js"
+            }
+        }, {
+            actual: ".././path//file.js",
+            normal: "../path/file.js"
+        }, {
+            actual: "/.././path//file.js",
+            normal: "/path/file.js"
+        }, {
+            actual: "\\\\some-unc\\path\\file.js",
+            normal: "\\\\some-unc/path/file.js",
+            resolve: {
+                origin: "\\\\some-unc\\path\\origin.js",
+                expected: "\\\\some-unc/path/file.js"
+            }
+        }, {
+            actual: "\\\\some-unc\\path\\..\\file.js",
+            normal: "\\\\some-unc/file.js",
+            resolve: {
+                origin: "\\\\some-unc\\path\\..\\origin.js",
+                expected: "\\\\some-unc/file.js"
+            }
+        }
+    ];
+
+    paths.forEach(function(p) {
+        test.equal(path.normalize(p.actual), p.normal, "should normalize " + p.actual);
+        if (p.resolve) {
+            test.equal(path.resolve(p.resolve.origin, p.actual), p.resolve.expected, "should resolve " + p.actual);
+            test.equal(path.resolve(p.resolve.origin, p.normal, true), p.resolve.expected, "should resolve " + p.normal + " (already normalized)");
+        }
+    });
+
+    test.end();
+});
diff --git a/lib/polyfill.js b/lib/polyfill.js
new file mode 100644
index 0000000..10ddf91
--- /dev/null
+++ b/lib/polyfill.js
@@ -0,0 +1,177 @@
+// This file exists for testing purposes but can also be used as a reference for polyfilling non-ES5 environments.
+// ref: https://github.com/inexorabletash/polyfill/blob/master/es5.js (public domain)
+
+// ES5 15.2.3.5 Object.create ( O [, Properties] )
+if (typeof Object.create !== "function") {
+  Object.create = function (prototype, properties) {
+    if (typeof prototype !== "object") { throw TypeError(); }
+    function Ctor() {}
+    Ctor.prototype = prototype;
+    var o = new Ctor();
+    if (prototype) { o.constructor = Ctor; }
+    if (properties !== undefined) {
+      if (properties !== Object(properties)) { throw TypeError(); }
+      Object.defineProperties(o, properties);
+    }
+    return o;
+  };
+}
+
+// ES 15.2.3.6 Object.defineProperty ( O, P, Attributes )
+// Partial support for most common case - getters, setters, and values
+(function() {
+  if (!Object.defineProperty ||
+      !(function () { try { Object.defineProperty({}, 'x', {}); return true; } catch (e) { return false; } } ())) {
+    var orig = Object.defineProperty;
+    Object.defineProperty = function (o, prop, desc) {
+      // In IE8 try built-in implementation for defining properties on DOM prototypes.
+      if (orig) { try { return orig(o, prop, desc); } catch (e) {} }
+
+      if (o !== Object(o)) { throw TypeError("Object.defineProperty called on non-object"); }
+      if (Object.prototype.__defineGetter__ && ('get' in desc)) {
+        Object.prototype.__defineGetter__.call(o, prop, desc.get);
+      }
+      if (Object.prototype.__defineSetter__ && ('set' in desc)) {
+        Object.prototype.__defineSetter__.call(o, prop, desc.set);
+      }
+      if ('value' in desc) {
+        o[prop] = desc.value;
+      }
+      return o;
+    };
+  }
+}());
+
+// ES 15.2.3.7 Object.defineProperties ( O, Properties )
+if (typeof Object.defineProperties !== "function") {
+  Object.defineProperties = function (o, properties) {
+    if (o !== Object(o)) { throw TypeError("Object.defineProperties called on non-object"); }
+    var name;
+    for (name in properties) {
+      if (Object.prototype.hasOwnProperty.call(properties, name)) {
+        Object.defineProperty(o, name, properties[name]);
+      }
+    }
+    return o;
+  };
+}
+
+// ES5 15.2.3.14 Object.keys ( O )
+// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys
+if (!Object.keys) {
+  Object.keys = function (o) {
+    if (o !== Object(o)) { throw TypeError('Object.keys called on non-object'); }
+    var ret = [], p;
+    for (p in o) {
+      if (Object.prototype.hasOwnProperty.call(o, p)) {
+        ret.push(p);
+      }
+    }
+    return ret;
+  };
+}
+
+// ES5 15.4.3.2 Array.isArray ( arg )
+// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
+if (!Array.isArray)
+  Array.isArray = function (o) { return Boolean(o && Object.prototype.toString.call(Object(o)) === '[object Array]'); };
+
+// ES5 15.4.4.14 Array.prototype.indexOf ( searchElement [ , fromIndex ] )
+// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
+if (!Array.prototype.indexOf) {
+  Array.prototype.indexOf = function (searchElement /*, fromIndex */) {
+    if (this === void 0 || this === null) { throw TypeError(); }
+
+    var t = Object(this);
+    var len = t.length >>> 0;
+    if (len === 0) { return -1; }
+
+    var n = 0;
+    if (arguments.length > 0) {
+      n = Number(arguments[1]);
+      if (isNaN(n)) {
+        n = 0;
+      } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
+        n = (n > 0 || -1) * Math.floor(Math.abs(n));
+      }
+    }
+
+    if (n >= len) { return -1; }
+
+    var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
+
+    for (; k < len; k++) {
+      if (k in t && t[k] === searchElement) {
+        return k;
+      }
+    }
+    return -1;
+  };
+}
+
+// ES5 15.4.4.18 Array.prototype.forEach ( callbackfn [ , thisArg ] )
+// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach
+if (!Array.prototype.forEach) {
+  Array.prototype.forEach = function (fun /*, thisp */) {
+    if (this === void 0 || this === null) { throw TypeError(); }
+
+    var t = Object(this);
+    var len = t.length >>> 0;
+    if (typeof fun !== "function") { throw TypeError(); }
+
+    var thisp = arguments[1], i;
+    for (i = 0; i < len; i++) {
+      if (i in t) {
+        fun.call(thisp, t[i], i, t);
+      }
+    }
+  };
+}
+
+
+// ES5 15.4.4.19 Array.prototype.map ( callbackfn [ , thisArg ] )
+// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/Map
+if (!Array.prototype.map) {
+  Array.prototype.map = function (fun /*, thisp */) {
+    if (this === void 0 || this === null) { throw TypeError(); }
+
+    var t = Object(this);
+    var len = t.length >>> 0;
+    if (typeof fun !== "function") { throw TypeError(); }
+
+    var res = []; res.length = len;
+    var thisp = arguments[1], i;
+    for (i = 0; i < len; i++) {
+      if (i in t) {
+        res[i] = fun.call(thisp, t[i], i, t);
+      }
+    }
+
+    return res;
+  };
+}
+
+// ES5 15.4.4.20 Array.prototype.filter ( callbackfn [ , thisArg ] )
+// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/Filter
+if (!Array.prototype.filter) {
+  Array.prototype.filter = function (fun /*, thisp */) {
+    if (this === void 0 || this === null) { throw TypeError(); }
+
+    var t = Object(this);
+    var len = t.length >>> 0;
+    if (typeof fun !== "function") { throw TypeError(); }
+
+    var res = [];
+    var thisp = arguments[1], i;
+    for (i = 0; i < len; i++) {
+      if (i in t) {
+        var val = t[i]; // in case fun mutates this
+        if (fun.call(thisp, val, i, t)) {
+          res.push(val);
+        }
+      }
+    }
+
+    return res;
+  };
+}
diff --git a/lib/pool/LICENSE b/lib/pool/LICENSE
new file mode 100644
index 0000000..be2b397
--- /dev/null
+++ b/lib/pool/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2016, Daniel Wirtz  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 its author, 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
diff --git a/lib/pool/README.md b/lib/pool/README.md
new file mode 100644
index 0000000..9fb0e97
--- /dev/null
+++ b/lib/pool/README.md
@@ -0,0 +1,13 @@
+@protobufjs/pool
+================
+[![npm](https://img.shields.io/npm/v/@protobufjs/pool.svg)](https://www.npmjs.com/package/@protobufjs/pool)
+
+A general purpose buffer pool.
+
+API
+---
+
+* **pool(alloc: `function(size: number): Uint8Array`, slice: `function(this: Uint8Array, start: number, end: number): Uint8Array`, [size=8192: `number`]): `function(size: number): Uint8Array`**<br />
+  Creates a pooled allocator.
+
+**License:** [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/lib/pool/index.d.ts b/lib/pool/index.d.ts
new file mode 100644
index 0000000..23fe38c
--- /dev/null
+++ b/lib/pool/index.d.ts
@@ -0,0 +1,32 @@
+export = pool;
+
+/**
+ * An allocator as used by {@link util.pool}.
+ * @typedef PoolAllocator
+ * @type {function}
+ * @param {number} size Buffer size
+ * @returns {Uint8Array} Buffer
+ */
+type PoolAllocator = (size: number) => Uint8Array;
+
+/**
+ * A slicer as used by {@link util.pool}.
+ * @typedef PoolSlicer
+ * @type {function}
+ * @param {number} start Start offset
+ * @param {number} end End offset
+ * @returns {Uint8Array} Buffer slice
+ * @this {Uint8Array}
+ */
+type PoolSlicer = (this: Uint8Array, start: number, end: number) => Uint8Array;
+
+/**
+ * A general purpose buffer pool.
+ * @memberof util
+ * @function
+ * @param {PoolAllocator} alloc Allocator
+ * @param {PoolSlicer} slice Slicer
+ * @param {number} [size=8192] Slab size
+ * @returns {PoolAllocator} Pooled allocator
+ */
+declare function pool(alloc: PoolAllocator, slice: PoolSlicer, size?: number): PoolAllocator;
diff --git a/lib/pool/index.js b/lib/pool/index.js
new file mode 100644
index 0000000..6c666f6
--- /dev/null
+++ b/lib/pool/index.js
@@ -0,0 +1,48 @@
+"use strict";
+module.exports = pool;
+
+/**
+ * An allocator as used by {@link util.pool}.
+ * @typedef PoolAllocator
+ * @type {function}
+ * @param {number} size Buffer size
+ * @returns {Uint8Array} Buffer
+ */
+
+/**
+ * A slicer as used by {@link util.pool}.
+ * @typedef PoolSlicer
+ * @type {function}
+ * @param {number} start Start offset
+ * @param {number} end End offset
+ * @returns {Uint8Array} Buffer slice
+ * @this {Uint8Array}
+ */
+
+/**
+ * A general purpose buffer pool.
+ * @memberof util
+ * @function
+ * @param {PoolAllocator} alloc Allocator
+ * @param {PoolSlicer} slice Slicer
+ * @param {number} [size=8192] Slab size
+ * @returns {PoolAllocator} Pooled allocator
+ */
+function pool(alloc, slice, size) {
+    var SIZE   = size || 8192;
+    var MAX    = SIZE >>> 1;
+    var slab   = null;
+    var offset = SIZE;
+    return function pool_alloc(size) {
+        if (size < 1 || size > MAX)
+            return alloc(size);
+        if (offset + size > SIZE) {
+            slab = alloc(SIZE);
+            offset = 0;
+        }
+        var buf = slice.call(slab, offset, offset += size);
+        if (offset & 7) // align to 32 bit
+            offset = (offset | 7) + 1;
+        return buf;
+    };
+}
diff --git a/lib/pool/package.json b/lib/pool/package.json
new file mode 100644
index 0000000..4c42083
--- /dev/null
+++ b/lib/pool/package.json
@@ -0,0 +1,21 @@
+{
+  "name": "@protobufjs/pool",
+  "description": "A general purpose buffer pool.",
+  "version": "1.1.0",
+  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/dcodeIO/protobuf.js.git"
+  },
+  "license": "BSD-3-Clause",
+  "main": "index.js",
+  "types": "index.d.ts",
+  "devDependencies": {
+    "istanbul": "^0.4.5",
+    "tape": "^5.0.0"
+  },
+  "scripts": {
+    "test": "tape tests/*.js",
+    "coverage": "istanbul cover node_modules/tape/bin/tape tests/*.js"
+  }
+}
diff --git a/lib/pool/tests/index.js b/lib/pool/tests/index.js
new file mode 100644
index 0000000..59aa73f
--- /dev/null
+++ b/lib/pool/tests/index.js
@@ -0,0 +1,32 @@
+var tape = require("tape");
+
+var pool = require("..");
+
+tape.test("pool", function(test) {
+
+    var alloc = pool(function(size) { return new Uint8Array(size); }, Uint8Array.prototype.subarray);
+
+    var buf1 = alloc(0);
+    test.equal(buf1.length, 0, "should allocate a buffer of size 0");
+
+    var buf2 = alloc(1);
+    test.equal(buf2.length, 1, "should allocate a buffer of size 1 (initializes slab)");
+
+    test.notEqual(buf2.buffer, buf1.buffer, "should not reference the same backing buffer if previous buffer had size 0");
+    test.equal(buf2.byteOffset, 0, "should allocate at byteOffset 0 when using a new slab");
+
+    buf1 = alloc(1);
+    test.equal(buf1.buffer, buf2.buffer, "should reference the same backing buffer when allocating a chunk fitting into the slab");
+    test.equal(buf1.byteOffset, 8, "should align slices to 32 bit and this allocate at byteOffset 8");
+
+    var buf3 = alloc(4097);
+    test.notEqual(buf3.buffer, buf2.buffer, "should not reference the same backing buffer when allocating a buffer larger than half the backing buffer's size");
+
+    buf2 = alloc(4096);
+    test.equal(buf2.buffer, buf1.buffer, "should reference the same backing buffer when allocating a buffer smaller or equal than half the backing buffer's size");
+
+    buf1 = alloc(4096);
+    test.notEqual(buf1.buffer, buf2.buffer, "should not reference the same backing buffer when the slab is exhausted (initializes new slab)");
+
+    test.end();
+});
\ No newline at end of file
diff --git a/lib/prelude.js b/lib/prelude.js
new file mode 100644
index 0000000..3c26686
--- /dev/null
+++ b/lib/prelude.js
@@ -0,0 +1,34 @@
+(function prelude(modules, cache, entries) {
+
+    // This is the prelude used to bundle protobuf.js for the browser. Wraps up the CommonJS
+    // sources through a conflict-free require shim and is again wrapped within an iife that
+    // provides a minification-friendly `undefined` var plus a global "use strict" directive
+    // so that minification can remove the directives of each module.
+
+    function $require(name) {
+        var $module = cache[name];
+        if (!$module)
+            modules[name][0].call($module = cache[name] = { exports: {} }, $require, $module, $module.exports);
+        return $module.exports;
+    }
+
+    var protobuf = $require(entries[0]);
+
+    // Expose globally
+    protobuf.util.global.protobuf = protobuf;
+
+    // Be nice to AMD
+    if (typeof define === "function" && define.amd)
+        define(["long"], function(Long) {
+            if (Long && Long.isLong) {
+                protobuf.util.Long = Long;
+                protobuf.configure();
+            }
+            return protobuf;
+        });
+
+    // Be nice to CommonJS
+    if (typeof module === "object" && module && module.exports)
+        module.exports = protobuf;
+
+})/* end of prelude */
\ No newline at end of file
diff --git a/lib/tape-adapter.js b/lib/tape-adapter.js
new file mode 100644
index 0000000..a4c9aa2
--- /dev/null
+++ b/lib/tape-adapter.js
@@ -0,0 +1,22 @@
+var tape = require("tape");
+
+var Test = tape.Test;
+
+// some ancient environments have invalid own properties on buffers so that deepEqual doesn't work.
+// the following uses a monkey-patched deepEqual implementation for all kinds of number arrays.
+
+var deepEqual = require("./deep-equal");
+
+Test.prototype.deepEqual
+= Test.prototype.deepEquals
+= Test.prototype.isEquivalent
+= Test.prototype.same
+= function (a, b, msg, extra) {
+    this._assert(deepEqual(a, b, { strict: true }), {
+        message : msg || "should be equivalent",
+        operator : "deepEqual",
+        actual : a,
+        expected : b,
+        extra : extra
+    });
+};
diff --git a/lib/utf8/LICENSE b/lib/utf8/LICENSE
new file mode 100644
index 0000000..be2b397
--- /dev/null
+++ b/lib/utf8/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2016, Daniel Wirtz  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 its author, 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
diff --git a/lib/utf8/README.md b/lib/utf8/README.md
new file mode 100644
index 0000000..c936d9b
--- /dev/null
+++ b/lib/utf8/README.md
@@ -0,0 +1,20 @@
+@protobufjs/utf8
+================
+[![npm](https://img.shields.io/npm/v/@protobufjs/utf8.svg)](https://www.npmjs.com/package/@protobufjs/utf8)
+
+A minimal UTF8 implementation for number arrays.
+
+API
+---
+
+* **utf8.length(string: `string`): `number`**<br />
+  Calculates the UTF8 byte length of a string.
+
+* **utf8.read(buffer: `Uint8Array`, start: `number`, end: `number`): `string`**<br />
+  Reads UTF8 bytes as a string.
+
+* **utf8.write(string: `string`, buffer: `Uint8Array`, offset: `number`): `number`**<br />
+  Writes a string as UTF8 bytes.
+
+
+**License:** [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/lib/utf8/index.d.ts b/lib/utf8/index.d.ts
new file mode 100644
index 0000000..2f1d0ab
--- /dev/null
+++ b/lib/utf8/index.d.ts
@@ -0,0 +1,24 @@
+/**
+ * Calculates the UTF8 byte length of a string.
+ * @param {string} string String
+ * @returns {number} Byte length
+ */
+export function length(string: string): number;
+
+/**
+ * Reads UTF8 bytes as a string.
+ * @param {Uint8Array} buffer Source buffer
+ * @param {number} start Source start
+ * @param {number} end Source end
+ * @returns {string} String read
+ */
+export function read(buffer: Uint8Array, start: number, end: number): string;
+
+/**
+ * Writes a string as UTF8 bytes.
+ * @param {string} string Source string
+ * @param {Uint8Array} buffer Destination buffer
+ * @param {number} offset Destination offset
+ * @returns {number} Bytes written
+ */
+export function write(string: string, buffer: Uint8Array, offset: number): number;
diff --git a/lib/utf8/index.js b/lib/utf8/index.js
new file mode 100644
index 0000000..bb4a0e8
--- /dev/null
+++ b/lib/utf8/index.js
@@ -0,0 +1,96 @@
+"use strict";
+
+/**
+ * A minimal UTF8 implementation for number arrays.
+ * @memberof util
+ * @namespace
+ */
+var utf8 = exports;
+
+/**
+ * Calculates the UTF8 byte length of a string.
+ * @param {string} string String
+ * @returns {number} Byte length
+ */
+utf8.length = function utf8_length(string) {
+    var len = 0,
+        c = 0;
+    for (var i = 0; i < string.length; ++i) {
+        c = string.charCodeAt(i);
+        if (c < 128)
+            len += 1;
+        else if (c < 2048)
+            len += 2;
+        else if ((c & 0xFC00) === 0xD800 && (string.charCodeAt(i + 1) & 0xFC00) === 0xDC00) {
+            ++i;
+            len += 4;
+        } else
+            len += 3;
+    }
+    return len;
+};
+
+/**
+ * Reads UTF8 bytes as a string.
+ * @param {Uint8Array} buffer Source buffer
+ * @param {number} start Source start
+ * @param {number} end Source end
+ * @returns {string} String read
+ */
+utf8.read = function utf8_read(buffer, start, end) {
+    if (end - start < 1) {
+        return "";
+    }
+
+    var str = "";
+    for (var i = start; i < end;) {
+        var t = buffer[i++];
+        if (t <= 0x7F) {
+            str += String.fromCharCode(t);
+        } else if (t >= 0xC0 && t < 0xE0) {
+            str += String.fromCharCode((t & 0x1F) << 6 | buffer[i++] & 0x3F);
+        } else if (t >= 0xE0 && t < 0xF0) {
+            str += String.fromCharCode((t & 0xF) << 12 | (buffer[i++] & 0x3F) << 6 | buffer[i++] & 0x3F);
+        } else if (t >= 0xF0) {
+            var t2 = ((t & 7) << 18 | (buffer[i++] & 0x3F) << 12 | (buffer[i++] & 0x3F) << 6 | buffer[i++] & 0x3F) - 0x10000;
+            str += String.fromCharCode(0xD800 + (t2 >> 10));
+            str += String.fromCharCode(0xDC00 + (t2 & 0x3FF));
+        }
+    }
+
+    return str;
+};
+
+/**
+ * Writes a string as UTF8 bytes.
+ * @param {string} string Source string
+ * @param {Uint8Array} buffer Destination buffer
+ * @param {number} offset Destination offset
+ * @returns {number} Bytes written
+ */
+utf8.write = function utf8_write(string, buffer, offset) {
+    var start = offset,
+        c1, // character 1
+        c2; // character 2
+    for (var i = 0; i < string.length; ++i) {
+        c1 = string.charCodeAt(i);
+        if (c1 < 128) {
+            buffer[offset++] = c1;
+        } else if (c1 < 2048) {
+            buffer[offset++] = c1 >> 6       | 192;
+            buffer[offset++] = c1       & 63 | 128;
+        } else if ((c1 & 0xFC00) === 0xD800 && ((c2 = string.charCodeAt(i + 1)) & 0xFC00) === 0xDC00) {
+            c1 = 0x10000 + ((c1 & 0x03FF) << 10) + (c2 & 0x03FF);
+            ++i;
+            buffer[offset++] = c1 >> 18      | 240;
+            buffer[offset++] = c1 >> 12 & 63 | 128;
+            buffer[offset++] = c1 >> 6  & 63 | 128;
+            buffer[offset++] = c1       & 63 | 128;
+        } else {
+            buffer[offset++] = c1 >> 12      | 224;
+            buffer[offset++] = c1 >> 6  & 63 | 128;
+            buffer[offset++] = c1       & 63 | 128;
+        }
+    }
+    return offset - start;
+};
diff --git a/lib/utf8/package.json b/lib/utf8/package.json
new file mode 100644
index 0000000..0eeb53a
--- /dev/null
+++ b/lib/utf8/package.json
@@ -0,0 +1,21 @@
+{
+  "name": "@protobufjs/utf8",
+  "description": "A minimal UTF8 implementation for number arrays.",
+  "version": "1.1.0",
+  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/dcodeIO/protobuf.js.git"
+  },
+  "license": "BSD-3-Clause",
+  "main": "index.js",
+  "types": "index.d.ts",
+  "devDependencies": {
+    "istanbul": "^0.4.5",
+    "tape": "^5.0.0"
+  },
+  "scripts": {
+    "test": "tape tests/*.js",
+    "coverage": "istanbul cover node_modules/tape/bin/tape tests/*.js"
+  }
+}
diff --git a/lib/utf8/tests/data/surrogate_pair_bug.txt b/lib/utf8/tests/data/surrogate_pair_bug.txt
new file mode 100644
index 0000000..8dc49d0
--- /dev/null
+++ b/lib/utf8/tests/data/surrogate_pair_bug.txt
@@ -0,0 +1,207 @@
+this file demonstrates a bug in the utf8_read function. xxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+📅
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
diff --git a/lib/utf8/tests/data/utf8.txt b/lib/utf8/tests/data/utf8.txt
new file mode 100644
index 0000000..580b4c4
--- /dev/null
+++ b/lib/utf8/tests/data/utf8.txt
@@ -0,0 +1,216 @@
+UTF-8 encoded sample plain-text file
+‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+
+Markus Kuhn [ˈmaʳkʊs kuːn] <http://www.cl.cam.ac.uk/~mgk25/> — 2002-07-25 CC BY
+
+
+The ASCII compatible UTF-8 encoding used in this plain-text file
+is defined in Unicode, ISO 10646-1, and RFC 2279.
+
+
+Using Unicode/UTF-8, you can write in emails and source code things such as
+
+Mathematics and sciences:
+
+  ∮ E⋅da = Q,  n → ∞, ∑ f(i) = ∏ g(i),      ⎧⎡⎛┌─────┐⎞⎤⎫
+                                            ⎪⎢⎜│a²+b³ ⎟⎥⎪
+  ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β),    ⎪⎢⎜│───── ⎟⎥⎪
+                                            ⎪⎢⎜⎷ c₈   ⎟⎥⎪
+  ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ,                   ⎨⎢⎜       ⎟⎥⎬
+                                            ⎪⎢⎜ ∞     ⎟⎥⎪
+  ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫),      ⎪⎢⎜ ⎲     ⎟⎥⎪
+                                            ⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪
+  2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm     ⎩⎣⎝i=1    ⎠⎦⎭
+
+Linguistics and dictionaries:
+
+  ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn
+  Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ]
+
+APL:
+
+  ((V⍳V)=⍳⍴V)/V←,V    ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈
+
+Nicer typography in plain text files:
+
+  ╔══════════════════════════════════════════╗
+  ║                                          ║
+  ║   • ‘single’ and “double” quotes         ║
+  ║                                          ║
+  ║   • Curly apostrophes: “We’ve been here” ║
+  ║                                          ║
+  ║   • Latin-1 apostrophe and accents: '´`  ║
+  ║                                          ║
+  ║   • ‚deutsche‘ „Anführungszeichen“       ║
+  ║                                          ║
+  ║   • †, ‡, ‰, •, 3–4, —, −5/+5, ™, …      ║
+  ║                                          ║
+  ║   • ASCII safety test: 1lI|, 0OD, 8B     ║
+  ║                      ╭─────────╮         ║
+  ║   • the euro symbol: │ 14.95 € │         ║
+  ║                      ╰─────────╯         ║
+  ╚══════════════════════════════════════════╝
+
+Combining characters:
+
+  STARGΛ̊TE SG-1, a = v̇ = r̈, a⃑ ⊥ b⃑
+
+Greek (in Polytonic):
+
+  The Greek anthem:
+
+  Σὲ γνωρίζω ἀπὸ τὴν κόψη
+  τοῦ σπαθιοῦ τὴν τρομερή,
+  σὲ γνωρίζω ἀπὸ τὴν ὄψη
+  ποὺ μὲ βία μετράει τὴ γῆ.
+
+  ᾿Απ᾿ τὰ κόκκαλα βγαλμένη
+  τῶν ῾Ελλήνων τὰ ἱερά
+  καὶ σὰν πρῶτα ἀνδρειωμένη
+  χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά!
+
+  From a speech of Demosthenes in the 4th century BC:
+
+  Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι,
+  ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς
+  λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ
+  τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿
+  εἰς τοῦτο προήκοντα,  ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ
+  πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν
+  οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι,
+  οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν
+  ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον
+  τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι
+  γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν
+  προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους
+  σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ
+  τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ
+  τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς
+  τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον.
+
+  Δημοσθένους, Γ´ ᾿Ολυνθιακὸς
+
+Georgian:
+
+  From a Unicode conference invitation:
+
+  გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო
+  კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს,
+  ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს
+  ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი,
+  ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება
+  ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში,
+  ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში.
+
+Russian:
+
+  From a Unicode conference invitation:
+
+  Зарегистрируйтесь сейчас на Десятую Международную Конференцию по
+  Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии.
+  Конференция соберет широкий круг экспертов по  вопросам глобального
+  Интернета и Unicode, локализации и интернационализации, воплощению и
+  применению Unicode в различных операционных системах и программных
+  приложениях, шрифтах, верстке и многоязычных компьютерных системах.
+
+Thai (UCS Level 2):
+
+  Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese
+  classic 'San Gua'):
+
+  [----------------------------|------------------------]
+    ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช  พระปกเกศกองบู๊กู้ขึ้นใหม่
+  สิบสองกษัตริย์ก่อนหน้าแลถัดไป       สององค์ไซร้โง่เขลาเบาปัญญา
+    ทรงนับถือขันทีเป็นที่พึ่ง           บ้านเมืองจึงวิปริตเป็นนักหนา
+  โฮจิ๋นเรียกทัพทั่วหัวเมืองมา         หมายจะฆ่ามดชั่วตัวสำคัญ
+    เหมือนขับไสไล่เสือจากเคหา      รับหมาป่าเข้ามาเลยอาสัญ
+  ฝ่ายอ้องอุ้นยุแยกให้แตกกัน          ใช้สาวนั้นเป็นชนวนชื่นชวนใจ
+    พลันลิฉุยกุยกีกลับก่อเหตุ          ช่างอาเพศจริงหนาฟ้าร้องไห้
+  ต้องรบราฆ่าฟันจนบรรลัย           ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ
+
+  (The above is a two-column text. If combining characters are handled
+  correctly, the lines of the second column should be aligned with the
+  | character above.)
+
+Ethiopian:
+
+  Proverbs in the Amharic language:
+
+  ሰማይ አይታረስ ንጉሥ አይከሰስ።
+  ብላ ካለኝ እንደአባቴ በቆመጠኝ።
+  ጌጥ ያለቤቱ ቁምጥና ነው።
+  ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው።
+  የአፍ ወለምታ በቅቤ አይታሽም።
+  አይጥ በበላ ዳዋ ተመታ።
+  ሲተረጉሙ ይደረግሙ።
+  ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል።
+  ድር ቢያብር አንበሳ ያስር።
+  ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም።
+  እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም።
+  የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ።
+  ሥራ ከመፍታት ልጄን ላፋታት።
+  ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል።
+  የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ።
+  ተንጋሎ ቢተፉ ተመልሶ ባፉ።
+  ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው።
+  እግርህን በፍራሽህ ልክ ዘርጋ።
+
+Runes:
+
+  ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ
+
+  (Old English, which transcribed into Latin reads 'He cwaeth that he
+  bude thaem lande northweardum with tha Westsae.' and means 'He said
+  that he lived in the northern land near the Western Sea.')
+
+Braille:
+
+  ⡌⠁⠧⠑ ⠼⠁⠒  ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌
+
+  ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞
+  ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎
+  ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂
+  ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙
+  ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑
+  ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲
+
+  ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲
+
+  ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹
+  ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞
+  ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕
+  ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹
+  ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎
+  ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎
+  ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳
+  ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞
+  ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲
+
+  (The first couple of paragraphs of "A Christmas Carol" by Dickens)
+
+Compact font selection example text:
+
+  ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789
+  abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ
+  –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд
+  ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა
+
+Greetings in various languages:
+
+  Hello world, Καλημέρα κόσμε, コンニチハ
+
+Box drawing alignment tests:                                          █
+                                                                      ▉
+  ╔══╦══╗  ┌──┬──┐  ╭──┬──╮  ╭──┬──╮  ┏━━┳━━┓  ┎┒┏┑   ╷  ╻ ┏┯┓ ┌┰┐    ▊ ╱╲╱╲╳╳╳
+  ║┌─╨─┐║  │╔═╧═╗│  │╒═╪═╕│  │╓─╁─╖│  ┃┌─╂─┐┃  ┗╃╄┙  ╶┼╴╺╋╸┠┼┨ ┝╋┥    ▋ ╲╱╲╱╳╳╳
+  ║│╲ ╱│║  │║   ║│  ││ │ ││  │║ ┃ ║│  ┃│ ╿ │┃  ┍╅╆┓   ╵  ╹ ┗┷┛ └┸┘    ▌ ╱╲╱╲╳╳╳
+  ╠╡ ╳ ╞╣  ├╢   ╟┤  ├┼─┼─┼┤  ├╫─╂─╫┤  ┣┿╾┼╼┿┫  ┕┛┖┚     ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳
+  ║│╱ ╲│║  │║   ║│  ││ │ ││  │║ ┃ ║│  ┃│ ╽ │┃  ░░▒▒▓▓██ ┊  ┆ ╎ ╏  ┇ ┋ ▎
+  ║└─╥─┘║  │╚═╤═╝│  │╘═╪═╛│  │╙─╀─╜│  ┃└─╂─┘┃  ░░▒▒▓▓██ ┊  ┆ ╎ ╏  ┇ ┋ ▏
+  ╚══╩══╝  └──┴──┘  ╰──┴──╯  ╰──┴──╯  ┗━━┻━━┛  ▗▄▖▛▀▜   └╌╌┘ ╎ ┗╍╍┛ ┋  ▁▂▃▄▅▆▇█
+                                               ▝▀▘▙▄▟
+
+Surrogates:
+
+𠜎 𠜱 𠝹 𠱓 𠱸 𠲖 𠳏 𠳕 𠴕 𠵼 𠵿 𠸎 𠸏 𠹷 𠺝 𠺢 𠻗 𠻹 𠻺 𠼭 𠼮 𠽌 𠾴 𠾼 𠿪 𡁜 𡁯 𡁵 𡁶 𡁻 𡃁
+𡃉 𡇙 𢃇 𢞵 𢫕 𢭃 𢯊 𢱑 𢱕 𢳂 𢴈 𢵌 𢵧 𢺳 𣲷 𤓓 𤶸 𤷪 𥄫 𦉘 𦟌 𦧲 𦧺 𧨾 𨅝 𨈇 𨋢 𨳊 𨳍 𨳒 𩶘
diff --git a/lib/utf8/tests/index.js b/lib/utf8/tests/index.js
new file mode 100644
index 0000000..c436c2a
--- /dev/null
+++ b/lib/utf8/tests/index.js
@@ -0,0 +1,63 @@
+var tape = require("tape");
+
+var utf8 = require("..");
+
+var data = require("fs").readFileSync(require.resolve("./data/utf8.txt")),
+    dataStr = data.toString("utf8");
+
+var surrogatePairErr = require("fs").readFileSync(require.resolve("./data/surrogate_pair_bug.txt")),
+    surrogatePairErrStr = data.toString("utf8");
+
+tape.test("utf8", function(test) {
+
+    test.test(test.name + " - length", function(test) {
+        test.equal(utf8.length(""), 0, "should return a byte length of zero for an empty string");
+
+        test.equal(utf8.length(dataStr), Buffer.byteLength(dataStr), "should return the same byte length as node buffers");
+
+        test.end();
+    });
+
+    test.test(test.name + " - read", function(test) {
+        var comp = utf8.read([], 0, 0);
+        test.equal(comp, "", "should decode an empty buffer to an empty string");
+
+        comp = utf8.read(data, 0, data.length);
+        test.equal(comp, data.toString("utf8"), "should decode to the same byte data as node buffers");
+
+        var longData = Buffer.concat([data, data, data, data]);
+        comp = utf8.read(longData, 0, longData.length);
+        test.equal(comp, longData.toString("utf8"), "should decode to the same byte data as node buffers (long)");
+
+        var chunkData = new Buffer(data.toString("utf8").substring(0, 8192));
+        comp = utf8.read(chunkData, 0, chunkData.length);
+        test.equal(comp, chunkData.toString("utf8"), "should decode to the same byte data as node buffers (chunk size)");
+
+        comp = utf8.read(surrogatePairErr, 0, surrogatePairErr.length);
+        test.equal(comp, surrogatePairErr.toString("utf8"), "should decode to the same byte data as node buffers (surrogate pair over chunk)");
+
+        test.end();
+    });
+
+    test.test(test.name + " - write", function(test) {
+        var buf = new Buffer(0);
+        test.equal(utf8.write("", buf, 0), 0, "should encode an empty string to an empty buffer");
+
+        var len = utf8.length(dataStr);
+        buf = new Buffer(len);
+        test.equal(utf8.write(dataStr, buf, 0), len, "should encode to exactly " + len + " bytes");
+
+        test.equal(buf.length, data.length, "should encode to a buffer length equal to that of node buffers");
+
+        for (var i = 0; i < buf.length; ++i) {
+            if (buf[i] !== data[i]) {
+                test.fail("should encode to the same buffer data as node buffers (offset " + i + ")");
+                return;
+            }
+        }
+        test.pass("should encode to the same buffer data as node buffers");
+
+        test.end();
+    });
+
+});
diff --git a/light.d.ts b/light.d.ts
new file mode 100644
index 0000000..d83e7f9
--- /dev/null
+++ b/light.d.ts
@@ -0,0 +1,2 @@
+export as namespace protobuf;
+export * from "./index";
diff --git a/light.js b/light.js
new file mode 100644
index 0000000..1209e64
--- /dev/null
+++ b/light.js
@@ -0,0 +1,4 @@
+// light library entry point.
+
+"use strict";
+module.exports = require("./src/index-light");
\ No newline at end of file
diff --git a/minimal.d.ts b/minimal.d.ts
new file mode 100644
index 0000000..d83e7f9
--- /dev/null
+++ b/minimal.d.ts
@@ -0,0 +1,2 @@
+export as namespace protobuf;
+export * from "./index";
diff --git a/minimal.js b/minimal.js
new file mode 100644
index 0000000..1f35ec9
--- /dev/null
+++ b/minimal.js
@@ -0,0 +1,4 @@
+// minimal library entry point.
+
+"use strict";
+module.exports = require("./src/index-minimal");
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..a907103
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,19613 @@
+{
+  "name": "protobufjs",
+  "version": "7.2.2",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "protobufjs",
+      "version": "7.2.2",
+      "hasInstallScript": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/node": ">=13.7.0",
+        "long": "^5.0.0"
+      },
+      "devDependencies": {
+        "benchmark": "^2.1.4",
+        "browserify": "^17.0.0",
+        "browserify-wrap": "^1.0.2",
+        "bundle-collapser": "^1.3.0",
+        "chalk": "^4.0.0",
+        "escodegen": "^1.13.0",
+        "eslint": "^8.15.0",
+        "espree": "^9.0.0",
+        "estraverse": "^5.1.0",
+        "gh-pages": "^4.0.0",
+        "git-raw-commits": "^2.0.3",
+        "git-semver-tags": "^4.0.0",
+        "google-protobuf": "^3.11.3",
+        "gulp": "^4.0.2",
+        "gulp-header": "^2.0.9",
+        "gulp-if": "^3.0.0",
+        "gulp-sourcemaps": "^3.0.0",
+        "gulp-uglify": "^3.0.2",
+        "jaguarjs-jsdoc": "github:dcodeIO/jaguarjs-jsdoc",
+        "jsdoc": "^4.0.0",
+        "minimist": "^1.2.0",
+        "nyc": "^15.0.0",
+        "reflect-metadata": "^0.1.13",
+        "tape": "^5.0.0",
+        "tslint": "^6.0.0",
+        "typescript": "^3.7.5",
+        "uglify-js": "^3.7.7",
+        "vinyl-buffer": "^1.0.1",
+        "vinyl-fs": "^3.0.3",
+        "vinyl-source-stream": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/@ampproject/remapping": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
+      "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.1.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+      "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/highlight": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.13.tgz",
+      "integrity": "sha512-5yUzC5LqyTFp2HLmDoxGQelcdYgSpP9xsnMWBphAscOdFrHSAVbLNzWiy32sVNDqJRDiJK6klfDnAgu6PAGSHw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.13.tgz",
+      "integrity": "sha512-ZisbOvRRusFktksHSG6pjj1CSvkPkcZq/KHD45LAkVP/oiHJkNBZWfpvlLmX8OtHDG8IuzsFlVRWo08w7Qxn0A==",
+      "dev": true,
+      "dependencies": {
+        "@ampproject/remapping": "^2.1.0",
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.18.13",
+        "@babel/helper-compilation-targets": "^7.18.9",
+        "@babel/helper-module-transforms": "^7.18.9",
+        "@babel/helpers": "^7.18.9",
+        "@babel/parser": "^7.18.13",
+        "@babel/template": "^7.18.10",
+        "@babel/traverse": "^7.18.13",
+        "@babel/types": "^7.18.13",
+        "convert-source-map": "^1.7.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.1",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/core/node_modules/convert-source-map": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
+      "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "~5.1.1"
+      }
+    },
+    "node_modules/@babel/core/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
+    },
+    "node_modules/@babel/generator": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.13.tgz",
+      "integrity": "sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.18.13",
+        "@jridgewell/gen-mapping": "^0.3.2",
+        "jsesc": "^2.5.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+      "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/set-array": "^1.0.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz",
+      "integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/compat-data": "^7.18.8",
+        "@babel/helper-validator-option": "^7.18.6",
+        "browserslist": "^4.20.2",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-environment-visitor": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
+      "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-function-name": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz",
+      "integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==",
+      "dev": true,
+      "dependencies": {
+        "@babel/template": "^7.18.6",
+        "@babel/types": "^7.18.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-hoist-variables": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
+      "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
+      "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz",
+      "integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-simple-access": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/helper-validator-identifier": "^7.18.6",
+        "@babel/template": "^7.18.6",
+        "@babel/traverse": "^7.18.9",
+        "@babel/types": "^7.18.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-simple-access": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz",
+      "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-split-export-declaration": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
+      "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.18.10",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz",
+      "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz",
+      "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
+      "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz",
+      "integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/template": "^7.18.6",
+        "@babel/traverse": "^7.18.9",
+        "@babel/types": "^7.18.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/highlight": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+      "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.18.6",
+        "chalk": "^2.0.0",
+        "js-tokens": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+      "dev": true
+    },
+    "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.13.tgz",
+      "integrity": "sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==",
+      "dev": true,
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/template": {
+      "version": "7.18.10",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz",
+      "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.18.6",
+        "@babel/parser": "^7.18.10",
+        "@babel/types": "^7.18.10"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.13.tgz",
+      "integrity": "sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.18.13",
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-function-name": "^7.18.9",
+        "@babel/helper-hoist-variables": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/parser": "^7.18.13",
+        "@babel/types": "^7.18.13",
+        "debug": "^4.1.0",
+        "globals": "^11.1.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse/node_modules/globals": {
+      "version": "11.12.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.13.tgz",
+      "integrity": "sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.18.10",
+        "@babel/helper-validator-identifier": "^7.18.6",
+        "to-fast-properties": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@eslint/eslintrc": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
+      "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==",
+      "dev": true,
+      "dependencies": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^9.3.2",
+        "globals": "^13.15.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@gulp-sourcemaps/identity-map": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-2.0.1.tgz",
+      "integrity": "sha512-Tb+nSISZku+eQ4X1lAkevcQa+jknn/OVUgZ3XCxEKIsLsqYuPoJwJOPQeaOk75X3WPftb29GWY1eqE7GLsXb1Q==",
+      "dev": true,
+      "dependencies": {
+        "acorn": "^6.4.1",
+        "normalize-path": "^3.0.0",
+        "postcss": "^7.0.16",
+        "source-map": "^0.6.0",
+        "through2": "^3.0.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/@gulp-sourcemaps/identity-map/node_modules/acorn": {
+      "version": "6.4.2",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
+      "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
+      "dev": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/@gulp-sourcemaps/identity-map/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@gulp-sourcemaps/identity-map/node_modules/through2": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
+      "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.4",
+        "readable-stream": "2 || 3"
+      }
+    },
+    "node_modules/@gulp-sourcemaps/map-sources": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz",
+      "integrity": "sha512-o/EatdaGt8+x2qpb0vFLC/2Gug/xYPRXb6a+ET1wGYKozKN3krDWC/zZFZAtrzxJHuDL12mwdfEFKcKMNvc55A==",
+      "dev": true,
+      "dependencies": {
+        "normalize-path": "^2.0.1",
+        "through2": "^2.0.3"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/@gulp-sourcemaps/map-sources/node_modules/normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
+      "dev": true,
+      "dependencies": {
+        "remove-trailing-separator": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@humanwhocodes/config-array": {
+      "version": "0.10.4",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz",
+      "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==",
+      "dev": true,
+      "dependencies": {
+        "@humanwhocodes/object-schema": "^1.2.1",
+        "debug": "^4.1.1",
+        "minimatch": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=10.10.0"
+      }
+    },
+    "node_modules/@humanwhocodes/gitignore-to-minimatch": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz",
+      "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@humanwhocodes/object-schema": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+      "dev": true
+    },
+    "node_modules/@istanbuljs/load-nyc-config": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+      "dev": true,
+      "dependencies": {
+        "camelcase": "^5.3.1",
+        "find-up": "^4.1.0",
+        "get-package-type": "^0.1.0",
+        "js-yaml": "^3.13.1",
+        "resolve-from": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/schema": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+      "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
+      "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/set-array": "^1.0.0",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/set-array": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+      "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.4.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+      "dev": true
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.15",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz",
+      "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.0.3",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      }
+    },
+    "node_modules/@jsdoc/salty": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.1.tgz",
+      "integrity": "sha512-JXwylDNSHa549N9uceDYu8D4GMXwSo3H8CCPYEQqxhhHpxD28+lRl2b3bS/caaPj5w1YD3SWtrficJNTnUjGpg==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.21"
+      },
+      "engines": {
+        "node": ">=v12.0.0"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@protobufjs/aspromise": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
+    },
+    "node_modules/@protobufjs/base64": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
+    },
+    "node_modules/@protobufjs/codegen": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
+    },
+    "node_modules/@protobufjs/eventemitter": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
+    },
+    "node_modules/@protobufjs/fetch": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.1",
+        "@protobufjs/inquire": "^1.1.0"
+      }
+    },
+    "node_modules/@protobufjs/float": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
+    },
+    "node_modules/@protobufjs/inquire": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
+    },
+    "node_modules/@protobufjs/path": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
+    },
+    "node_modules/@protobufjs/pool": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
+    },
+    "node_modules/@protobufjs/utf8": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
+    },
+    "node_modules/@types/linkify-it": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz",
+      "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==",
+      "dev": true
+    },
+    "node_modules/@types/markdown-it": {
+      "version": "12.2.3",
+      "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz",
+      "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/linkify-it": "*",
+        "@types/mdurl": "*"
+      }
+    },
+    "node_modules/@types/mdurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz",
+      "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==",
+      "dev": true
+    },
+    "node_modules/@types/minimist": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz",
+      "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==",
+      "dev": true
+    },
+    "node_modules/@types/node": {
+      "version": "18.7.13",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.13.tgz",
+      "integrity": "sha512-46yIhxSe5xEaJZXWdIBP7GU4HDTG8/eo0qd9atdiL+lFpA03y8KS+lkTN834TWJj5767GbWv4n/P6efyTFt1Dw=="
+    },
+    "node_modules/@types/normalize-package-data": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz",
+      "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==",
+      "dev": true
+    },
+    "node_modules/acorn": {
+      "version": "7.4.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+      "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+      "dev": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/acorn-node": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
+      "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
+      "dev": true,
+      "dependencies": {
+        "acorn": "^7.0.0",
+        "acorn-walk": "^7.0.0",
+        "xtend": "^4.0.2"
+      }
+    },
+    "node_modules/acorn-walk": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
+      "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/aggregate-error": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+      "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+      "dev": true,
+      "dependencies": {
+        "clean-stack": "^2.0.0",
+        "indent-string": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ansi-colors": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
+      "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-wrap": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/ansi-gray": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz",
+      "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==",
+      "dev": true,
+      "dependencies": {
+        "ansi-wrap": "0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/ansi-wrap": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
+      "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+      "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+      "dev": true,
+      "dependencies": {
+        "micromatch": "^3.1.4",
+        "normalize-path": "^2.1.1"
+      }
+    },
+    "node_modules/anymatch/node_modules/define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/anymatch/node_modules/extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+      "dev": true,
+      "dependencies": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/anymatch/node_modules/is-accessor-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+      "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/anymatch/node_modules/is-data-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+      "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/anymatch/node_modules/is-descriptor": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+      "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+      "dev": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^1.0.0",
+        "is-data-descriptor": "^1.0.0",
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/anymatch/node_modules/is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/anymatch/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/anymatch/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/anymatch/node_modules/micromatch": {
+      "version": "3.1.10",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+      "dev": true,
+      "dependencies": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "braces": "^2.3.1",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "extglob": "^2.0.4",
+        "fragment-cache": "^0.2.1",
+        "kind-of": "^6.0.2",
+        "nanomatch": "^1.2.9",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/anymatch/node_modules/normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
+      "dev": true,
+      "dependencies": {
+        "remove-trailing-separator": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/append-buffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz",
+      "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==",
+      "dev": true,
+      "dependencies": {
+        "buffer-equal": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/append-transform": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz",
+      "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==",
+      "dev": true,
+      "dependencies": {
+        "default-require-extensions": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/archy": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
+      "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==",
+      "dev": true
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
+    "node_modules/arr-diff": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+      "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/arr-filter": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz",
+      "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==",
+      "dev": true,
+      "dependencies": {
+        "make-iterator": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/arr-map": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz",
+      "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==",
+      "dev": true,
+      "dependencies": {
+        "make-iterator": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/arr-union": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+      "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/array-each": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
+      "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/array-initial": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz",
+      "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==",
+      "dev": true,
+      "dependencies": {
+        "array-slice": "^1.0.0",
+        "is-number": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/array-initial/node_modules/is-number": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+      "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/array-last": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz",
+      "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==",
+      "dev": true,
+      "dependencies": {
+        "is-number": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/array-last/node_modules/is-number": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+      "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/array-slice": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
+      "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/array-sort": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz",
+      "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==",
+      "dev": true,
+      "dependencies": {
+        "default-compare": "^1.0.0",
+        "get-value": "^2.0.6",
+        "kind-of": "^5.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/array-union": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/array-uniq": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+      "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/array-unique": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+      "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/array.prototype.every": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/array.prototype.every/-/array.prototype.every-1.1.3.tgz",
+      "integrity": "sha512-vWnriJI//SOMOWtXbU/VXhJ/InfnNHPF6BLKn5WfY8xXy+NWql0fUy20GO3sdqBhCAO+qw8S/E5nJiZX+QFdCA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.19.0",
+        "is-string": "^1.0.7"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/arrify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+      "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/asn1.js": {
+      "version": "5.4.1",
+      "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
+      "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
+      "dev": true,
+      "dependencies": {
+        "bn.js": "^4.0.0",
+        "inherits": "^2.0.1",
+        "minimalistic-assert": "^1.0.0",
+        "safer-buffer": "^2.1.0"
+      }
+    },
+    "node_modules/asn1.js/node_modules/bn.js": {
+      "version": "4.12.0",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+      "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+      "dev": true
+    },
+    "node_modules/assert": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
+      "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
+      "dev": true,
+      "dependencies": {
+        "object-assign": "^4.1.1",
+        "util": "0.10.3"
+      }
+    },
+    "node_modules/assert/node_modules/inherits": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+      "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==",
+      "dev": true
+    },
+    "node_modules/assert/node_modules/util": {
+      "version": "0.10.3",
+      "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+      "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "2.0.1"
+      }
+    },
+    "node_modules/assign-symbols": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+      "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/async": {
+      "version": "2.6.4",
+      "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
+      "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.14"
+      }
+    },
+    "node_modules/async-done": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz",
+      "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==",
+      "dev": true,
+      "dependencies": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.2",
+        "process-nextick-args": "^2.0.0",
+        "stream-exhaust": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/async-each": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+      "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
+      "dev": true
+    },
+    "node_modules/async-settle": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz",
+      "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==",
+      "dev": true,
+      "dependencies": {
+        "async-done": "^1.2.2"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "dev": true,
+      "bin": {
+        "atob": "bin/atob.js"
+      },
+      "engines": {
+        "node": ">= 4.5.0"
+      }
+    },
+    "node_modules/available-typed-arrays": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
+      "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/bach": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz",
+      "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==",
+      "dev": true,
+      "dependencies": {
+        "arr-filter": "^1.1.1",
+        "arr-flatten": "^1.0.1",
+        "arr-map": "^2.0.0",
+        "array-each": "^1.0.0",
+        "array-initial": "^1.0.0",
+        "array-last": "^1.1.1",
+        "async-done": "^1.2.2",
+        "async-settle": "^1.0.0",
+        "now-and-later": "^2.0.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true
+    },
+    "node_modules/base": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+      "dev": true,
+      "dependencies": {
+        "cache-base": "^1.0.1",
+        "class-utils": "^0.3.5",
+        "component-emitter": "^1.2.1",
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.1",
+        "mixin-deep": "^1.2.0",
+        "pascalcase": "^0.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/base/node_modules/define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+      "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+      "dev": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/base/node_modules/is-accessor-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+      "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/base/node_modules/is-data-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+      "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/base/node_modules/is-descriptor": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+      "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+      "dev": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^1.0.0",
+        "is-data-descriptor": "^1.0.0",
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/base/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/benchmark": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz",
+      "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.4",
+        "platform": "^1.3.3"
+      }
+    },
+    "node_modules/binary-extensions": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+      "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/bindings": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "file-uri-to-path": "1.0.0"
+      }
+    },
+    "node_modules/bl": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz",
+      "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==",
+      "dev": true,
+      "dependencies": {
+        "readable-stream": "^2.3.5",
+        "safe-buffer": "^5.1.1"
+      }
+    },
+    "node_modules/bluebird": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+      "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+      "dev": true
+    },
+    "node_modules/bn.js": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+      "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
+      "dev": true
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+      "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+      "dev": true,
+      "dependencies": {
+        "arr-flatten": "^1.1.0",
+        "array-unique": "^0.3.2",
+        "extend-shallow": "^2.0.1",
+        "fill-range": "^4.0.0",
+        "isobject": "^3.0.1",
+        "repeat-element": "^1.1.2",
+        "snapdragon": "^0.8.1",
+        "snapdragon-node": "^2.0.1",
+        "split-string": "^3.0.2",
+        "to-regex": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/brorand": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+      "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==",
+      "dev": true
+    },
+    "node_modules/browser-pack": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz",
+      "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==",
+      "dev": true,
+      "dependencies": {
+        "combine-source-map": "~0.8.0",
+        "defined": "^1.0.0",
+        "JSONStream": "^1.0.3",
+        "safe-buffer": "^5.1.1",
+        "through2": "^2.0.0",
+        "umd": "^3.0.0"
+      },
+      "bin": {
+        "browser-pack": "bin/cmd.js"
+      }
+    },
+    "node_modules/browser-resolve": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz",
+      "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==",
+      "dev": true,
+      "dependencies": {
+        "resolve": "^1.17.0"
+      }
+    },
+    "node_modules/browser-unpack": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/browser-unpack/-/browser-unpack-1.4.2.tgz",
+      "integrity": "sha512-uHkiY4bmXjjBBWoKH1aRnEGTQxUUCCcVtoJfH9w1lmGGjETY4u93Zk+GRYkCE/SRMrdoMTINQ/1/manr/3aMVA==",
+      "dev": true,
+      "dependencies": {
+        "acorn-node": "^1.5.2",
+        "concat-stream": "^1.5.0",
+        "minimist": "^1.1.1"
+      },
+      "bin": {
+        "browser-unpack": "bin/cmd.js"
+      }
+    },
+    "node_modules/browserify": {
+      "version": "17.0.0",
+      "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.0.tgz",
+      "integrity": "sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w==",
+      "dev": true,
+      "dependencies": {
+        "assert": "^1.4.0",
+        "browser-pack": "^6.0.1",
+        "browser-resolve": "^2.0.0",
+        "browserify-zlib": "~0.2.0",
+        "buffer": "~5.2.1",
+        "cached-path-relative": "^1.0.0",
+        "concat-stream": "^1.6.0",
+        "console-browserify": "^1.1.0",
+        "constants-browserify": "~1.0.0",
+        "crypto-browserify": "^3.0.0",
+        "defined": "^1.0.0",
+        "deps-sort": "^2.0.1",
+        "domain-browser": "^1.2.0",
+        "duplexer2": "~0.1.2",
+        "events": "^3.0.0",
+        "glob": "^7.1.0",
+        "has": "^1.0.0",
+        "htmlescape": "^1.1.0",
+        "https-browserify": "^1.0.0",
+        "inherits": "~2.0.1",
+        "insert-module-globals": "^7.2.1",
+        "JSONStream": "^1.0.3",
+        "labeled-stream-splicer": "^2.0.0",
+        "mkdirp-classic": "^0.5.2",
+        "module-deps": "^6.2.3",
+        "os-browserify": "~0.3.0",
+        "parents": "^1.0.1",
+        "path-browserify": "^1.0.0",
+        "process": "~0.11.0",
+        "punycode": "^1.3.2",
+        "querystring-es3": "~0.2.0",
+        "read-only-stream": "^2.0.0",
+        "readable-stream": "^2.0.2",
+        "resolve": "^1.1.4",
+        "shasum-object": "^1.0.0",
+        "shell-quote": "^1.6.1",
+        "stream-browserify": "^3.0.0",
+        "stream-http": "^3.0.0",
+        "string_decoder": "^1.1.1",
+        "subarg": "^1.0.0",
+        "syntax-error": "^1.1.1",
+        "through2": "^2.0.0",
+        "timers-browserify": "^1.0.1",
+        "tty-browserify": "0.0.1",
+        "url": "~0.11.0",
+        "util": "~0.12.0",
+        "vm-browserify": "^1.0.0",
+        "xtend": "^4.0.0"
+      },
+      "bin": {
+        "browserify": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/browserify-aes": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+      "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+      "dev": true,
+      "dependencies": {
+        "buffer-xor": "^1.0.3",
+        "cipher-base": "^1.0.0",
+        "create-hash": "^1.1.0",
+        "evp_bytestokey": "^1.0.3",
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/browserify-cipher": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
+      "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
+      "dev": true,
+      "dependencies": {
+        "browserify-aes": "^1.0.4",
+        "browserify-des": "^1.0.0",
+        "evp_bytestokey": "^1.0.0"
+      }
+    },
+    "node_modules/browserify-des": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
+      "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
+      "dev": true,
+      "dependencies": {
+        "cipher-base": "^1.0.1",
+        "des.js": "^1.0.0",
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      }
+    },
+    "node_modules/browserify-rsa": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
+      "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
+      "dev": true,
+      "dependencies": {
+        "bn.js": "^5.0.0",
+        "randombytes": "^2.0.1"
+      }
+    },
+    "node_modules/browserify-sign": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
+      "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
+      "dev": true,
+      "dependencies": {
+        "bn.js": "^5.1.1",
+        "browserify-rsa": "^4.0.1",
+        "create-hash": "^1.2.0",
+        "create-hmac": "^1.1.7",
+        "elliptic": "^6.5.3",
+        "inherits": "^2.0.4",
+        "parse-asn1": "^5.1.5",
+        "readable-stream": "^3.6.0",
+        "safe-buffer": "^5.2.0"
+      }
+    },
+    "node_modules/browserify-sign/node_modules/readable-stream": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/browserify-wrap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/browserify-wrap/-/browserify-wrap-1.0.2.tgz",
+      "integrity": "sha512-WzNdGOw6UzwTwupeBa8Og8RLt4izpal6ss9GqcqPue95qS+r4IHkn9qVnIYW5QNcQnyk3b1+36xFdFAbiKJ98g==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/browserify-zlib": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+      "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+      "dev": true,
+      "dependencies": {
+        "pako": "~1.0.5"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.21.3",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz",
+      "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        }
+      ],
+      "dependencies": {
+        "caniuse-lite": "^1.0.30001370",
+        "electron-to-chromium": "^1.4.202",
+        "node-releases": "^2.0.6",
+        "update-browserslist-db": "^1.0.5"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz",
+      "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==",
+      "dev": true,
+      "dependencies": {
+        "base64-js": "^1.0.2",
+        "ieee754": "^1.1.4"
+      }
+    },
+    "node_modules/buffer-equal": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz",
+      "integrity": "sha512-tcBWO2Dl4e7Asr9hTGcpVrCe+F7DubpmqWCTbj4FHLmjqO2hIaC383acQubWtRJhdceqs5uBHs6Es+Sk//RKiQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true
+    },
+    "node_modules/buffer-xor": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+      "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==",
+      "dev": true
+    },
+    "node_modules/builtin-modules": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+      "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/builtin-status-codes": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+      "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==",
+      "dev": true
+    },
+    "node_modules/bundle-collapser": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/bundle-collapser/-/bundle-collapser-1.4.0.tgz",
+      "integrity": "sha512-Gd3K3+3KI1Utuk+gwAvuOVOjT/2XLGL8tU6FwDKk04LlOZkYfT0pwQllsG1Dv8RRhgcjNxZSDmmSXb0AOkwSwg==",
+      "dev": true,
+      "dependencies": {
+        "browser-pack": "^6.0.2",
+        "browser-unpack": "^1.1.0",
+        "concat-stream": "^1.5.0",
+        "falafel": "^2.1.0",
+        "minimist": "^1.1.1",
+        "through2": "^2.0.0"
+      },
+      "bin": {
+        "bundle-collapser": "bin/cmd.js"
+      }
+    },
+    "node_modules/cache-base": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+      "dev": true,
+      "dependencies": {
+        "collection-visit": "^1.0.0",
+        "component-emitter": "^1.2.1",
+        "get-value": "^2.0.6",
+        "has-value": "^1.0.0",
+        "isobject": "^3.0.1",
+        "set-value": "^2.0.0",
+        "to-object-path": "^0.3.0",
+        "union-value": "^1.0.0",
+        "unset-value": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/cached-path-relative": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.1.0.tgz",
+      "integrity": "sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA==",
+      "dev": true
+    },
+    "node_modules/caching-transform": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
+      "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==",
+      "dev": true,
+      "dependencies": {
+        "hasha": "^5.0.0",
+        "make-dir": "^3.0.0",
+        "package-hash": "^4.0.0",
+        "write-file-atomic": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/call-bind": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+      "dev": true,
+      "dependencies": {
+        "function-bind": "^1.1.1",
+        "get-intrinsic": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/camelcase-keys": {
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
+      "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
+      "dev": true,
+      "dependencies": {
+        "camelcase": "^5.3.1",
+        "map-obj": "^4.0.0",
+        "quick-lru": "^4.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001383",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001383.tgz",
+      "integrity": "sha512-swMpEoTp5vDoGBZsYZX7L7nXHe6dsHxi9o6/LKf/f0LukVtnrxly5GVb/fWdCDTqi/yw6Km6tiJ0pmBacm0gbg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        }
+      ]
+    },
+    "node_modules/catharsis": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
+      "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.15"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+      "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
+      "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies",
+      "dev": true,
+      "dependencies": {
+        "anymatch": "^2.0.0",
+        "async-each": "^1.0.1",
+        "braces": "^2.3.2",
+        "glob-parent": "^3.1.0",
+        "inherits": "^2.0.3",
+        "is-binary-path": "^1.0.0",
+        "is-glob": "^4.0.0",
+        "normalize-path": "^3.0.0",
+        "path-is-absolute": "^1.0.0",
+        "readdirp": "^2.2.1",
+        "upath": "^1.1.1"
+      },
+      "optionalDependencies": {
+        "fsevents": "^1.2.7"
+      }
+    },
+    "node_modules/chokidar/node_modules/glob-parent": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+      "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^3.1.0",
+        "path-dirname": "^1.0.0"
+      }
+    },
+    "node_modules/chokidar/node_modules/glob-parent/node_modules/is-glob": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+      "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
+      "dev": true,
+      "dependencies": {
+        "is-extglob": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/cipher-base": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+      "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/class-utils": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+      "dev": true,
+      "dependencies": {
+        "arr-union": "^3.1.0",
+        "define-property": "^0.2.5",
+        "isobject": "^3.0.0",
+        "static-extend": "^0.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/clean-stack": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+      "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/cliui": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+      "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1",
+        "wrap-ansi": "^2.0.0"
+      }
+    },
+    "node_modules/cliui/node_modules/ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/cliui/node_modules/strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/clone": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+      "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/clone-buffer": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
+      "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/clone-stats": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
+      "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==",
+      "dev": true
+    },
+    "node_modules/cloneable-readable": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz",
+      "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.1",
+        "process-nextick-args": "^2.0.0",
+        "readable-stream": "^2.3.5"
+      }
+    },
+    "node_modules/code-point-at": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+      "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/collection-map": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz",
+      "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==",
+      "dev": true,
+      "dependencies": {
+        "arr-map": "^2.0.2",
+        "for-own": "^1.0.0",
+        "make-iterator": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/collection-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+      "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==",
+      "dev": true,
+      "dependencies": {
+        "map-visit": "^1.0.0",
+        "object-visit": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/color-support": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+      "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+      "dev": true,
+      "bin": {
+        "color-support": "bin.js"
+      }
+    },
+    "node_modules/combine-source-map": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz",
+      "integrity": "sha512-UlxQ9Vw0b/Bt/KYwCFqdEwsQ1eL8d1gibiFb7lxQJFdvTgc2hIZi6ugsg+kyhzhPV+QEpUiEIwInIAIrgoEkrg==",
+      "dev": true,
+      "dependencies": {
+        "convert-source-map": "~1.1.0",
+        "inline-source-map": "~0.6.0",
+        "lodash.memoize": "~3.0.3",
+        "source-map": "~0.5.3"
+      }
+    },
+    "node_modules/commander": {
+      "version": "2.20.3",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+      "dev": true
+    },
+    "node_modules/commondir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+      "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
+      "dev": true
+    },
+    "node_modules/component-emitter": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+      "dev": true
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true
+    },
+    "node_modules/concat-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "dev": true,
+      "engines": [
+        "node >= 0.8"
+      ],
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.2.2",
+        "typedarray": "^0.0.6"
+      }
+    },
+    "node_modules/concat-with-sourcemaps": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz",
+      "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==",
+      "dev": true,
+      "dependencies": {
+        "source-map": "^0.6.1"
+      }
+    },
+    "node_modules/concat-with-sourcemaps/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/console-browserify": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
+      "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==",
+      "dev": true
+    },
+    "node_modules/constants-browserify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+      "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==",
+      "dev": true
+    },
+    "node_modules/convert-source-map": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
+      "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==",
+      "dev": true
+    },
+    "node_modules/copy-descriptor": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+      "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/copy-props": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz",
+      "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==",
+      "dev": true,
+      "dependencies": {
+        "each-props": "^1.3.2",
+        "is-plain-object": "^5.0.0"
+      }
+    },
+    "node_modules/core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+      "dev": true
+    },
+    "node_modules/create-ecdh": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
+      "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
+      "dev": true,
+      "dependencies": {
+        "bn.js": "^4.1.0",
+        "elliptic": "^6.5.3"
+      }
+    },
+    "node_modules/create-ecdh/node_modules/bn.js": {
+      "version": "4.12.0",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+      "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+      "dev": true
+    },
+    "node_modules/create-hash": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+      "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+      "dev": true,
+      "dependencies": {
+        "cipher-base": "^1.0.1",
+        "inherits": "^2.0.1",
+        "md5.js": "^1.3.4",
+        "ripemd160": "^2.0.1",
+        "sha.js": "^2.4.0"
+      }
+    },
+    "node_modules/create-hmac": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+      "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+      "dev": true,
+      "dependencies": {
+        "cipher-base": "^1.0.3",
+        "create-hash": "^1.1.0",
+        "inherits": "^2.0.1",
+        "ripemd160": "^2.0.0",
+        "safe-buffer": "^5.0.1",
+        "sha.js": "^2.4.8"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+      "dev": true,
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/crypto-browserify": {
+      "version": "3.12.0",
+      "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+      "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+      "dev": true,
+      "dependencies": {
+        "browserify-cipher": "^1.0.0",
+        "browserify-sign": "^4.0.0",
+        "create-ecdh": "^4.0.0",
+        "create-hash": "^1.1.0",
+        "create-hmac": "^1.1.0",
+        "diffie-hellman": "^5.0.0",
+        "inherits": "^2.0.1",
+        "pbkdf2": "^3.0.3",
+        "public-encrypt": "^4.0.0",
+        "randombytes": "^2.0.0",
+        "randomfill": "^1.0.3"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/css": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz",
+      "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.4",
+        "source-map": "^0.6.1",
+        "source-map-resolve": "^0.6.0"
+      }
+    },
+    "node_modules/css/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/d": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+      "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+      "dev": true,
+      "dependencies": {
+        "es5-ext": "^0.10.50",
+        "type": "^1.0.1"
+      }
+    },
+    "node_modules/dargs": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz",
+      "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/dash-ast": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz",
+      "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==",
+      "dev": true
+    },
+    "node_modules/debug": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/debug-fabulous": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz",
+      "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==",
+      "dev": true,
+      "dependencies": {
+        "debug": "3.X",
+        "memoizee": "0.4.X",
+        "object-assign": "4.X"
+      }
+    },
+    "node_modules/debug-fabulous/node_modules/debug": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/decamelize-keys": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
+      "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==",
+      "dev": true,
+      "dependencies": {
+        "decamelize": "^1.1.0",
+        "map-obj": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/decamelize-keys/node_modules/map-obj": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+      "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/decode-uri-component": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
+      "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/deep-equal": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz",
+      "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.0",
+        "es-get-iterator": "^1.1.1",
+        "get-intrinsic": "^1.0.1",
+        "is-arguments": "^1.0.4",
+        "is-date-object": "^1.0.2",
+        "is-regex": "^1.1.1",
+        "isarray": "^2.0.5",
+        "object-is": "^1.1.4",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.2",
+        "regexp.prototype.flags": "^1.3.0",
+        "side-channel": "^1.0.3",
+        "which-boxed-primitive": "^1.0.1",
+        "which-collection": "^1.0.1",
+        "which-typed-array": "^1.1.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/deep-is": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+      "dev": true
+    },
+    "node_modules/default-compare": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz",
+      "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^5.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/default-require-extensions": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz",
+      "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==",
+      "dev": true,
+      "dependencies": {
+        "strip-bom": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/default-resolution": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz",
+      "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/define-properties": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
+      "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
+      "dev": true,
+      "dependencies": {
+        "has-property-descriptors": "^1.0.0",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/define-property": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+      "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+      "dev": true,
+      "dependencies": {
+        "is-descriptor": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/defined": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+      "integrity": "sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==",
+      "dev": true
+    },
+    "node_modules/deps-sort": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz",
+      "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==",
+      "dev": true,
+      "dependencies": {
+        "JSONStream": "^1.0.3",
+        "shasum-object": "^1.0.0",
+        "subarg": "^1.0.0",
+        "through2": "^2.0.0"
+      },
+      "bin": {
+        "deps-sort": "bin/cmd.js"
+      }
+    },
+    "node_modules/des.js": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
+      "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.1",
+        "minimalistic-assert": "^1.0.0"
+      }
+    },
+    "node_modules/detect-file": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+      "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/detect-newline": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
+      "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/detective": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz",
+      "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==",
+      "dev": true,
+      "dependencies": {
+        "acorn-node": "^1.8.2",
+        "defined": "^1.0.0",
+        "minimist": "^1.2.6"
+      },
+      "bin": {
+        "detective": "bin/detective.js"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/diff": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
+    "node_modules/diffie-hellman": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+      "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
+      "dev": true,
+      "dependencies": {
+        "bn.js": "^4.1.0",
+        "miller-rabin": "^4.0.0",
+        "randombytes": "^2.0.0"
+      }
+    },
+    "node_modules/diffie-hellman/node_modules/bn.js": {
+      "version": "4.12.0",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+      "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+      "dev": true
+    },
+    "node_modules/dir-glob": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+      "dev": true,
+      "dependencies": {
+        "path-type": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+      "dev": true,
+      "dependencies": {
+        "esutils": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/domain-browser": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
+      "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4",
+        "npm": ">=1.2"
+      }
+    },
+    "node_modules/dotignore": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz",
+      "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==",
+      "dev": true,
+      "dependencies": {
+        "minimatch": "^3.0.4"
+      },
+      "bin": {
+        "ignored": "bin/ignored"
+      }
+    },
+    "node_modules/duplexer2": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+      "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
+      "dev": true,
+      "dependencies": {
+        "readable-stream": "^2.0.2"
+      }
+    },
+    "node_modules/duplexify": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz",
+      "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==",
+      "dev": true,
+      "dependencies": {
+        "end-of-stream": "^1.4.1",
+        "inherits": "^2.0.3",
+        "readable-stream": "^3.1.1",
+        "stream-shift": "^1.0.0"
+      }
+    },
+    "node_modules/duplexify/node_modules/readable-stream": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/each-props": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz",
+      "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==",
+      "dev": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.1",
+        "object.defaults": "^1.1.0"
+      }
+    },
+    "node_modules/each-props/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.4.232",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.232.tgz",
+      "integrity": "sha512-nd+FW8xHjM+PxNWG44nKnwHaBDdVpJUZuI2sS2JJPt/QpdombnmoCRWEEQNnzaktdIQhsNWdD+dlqxwO8Bn99g==",
+      "dev": true
+    },
+    "node_modules/elliptic": {
+      "version": "6.5.4",
+      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
+      "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
+      "dev": true,
+      "dependencies": {
+        "bn.js": "^4.11.9",
+        "brorand": "^1.1.0",
+        "hash.js": "^1.0.0",
+        "hmac-drbg": "^1.0.1",
+        "inherits": "^2.0.4",
+        "minimalistic-assert": "^1.0.1",
+        "minimalistic-crypto-utils": "^1.0.1"
+      }
+    },
+    "node_modules/elliptic/node_modules/bn.js": {
+      "version": "4.12.0",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+      "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+      "dev": true
+    },
+    "node_modules/email-addresses": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
+      "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==",
+      "dev": true
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "node_modules/end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+      "dev": true,
+      "dependencies": {
+        "once": "^1.4.0"
+      }
+    },
+    "node_modules/entities": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+      "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dev": true,
+      "dependencies": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "node_modules/es-abstract": {
+      "version": "1.20.1",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz",
+      "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "es-to-primitive": "^1.2.1",
+        "function-bind": "^1.1.1",
+        "function.prototype.name": "^1.1.5",
+        "get-intrinsic": "^1.1.1",
+        "get-symbol-description": "^1.0.0",
+        "has": "^1.0.3",
+        "has-property-descriptors": "^1.0.0",
+        "has-symbols": "^1.0.3",
+        "internal-slot": "^1.0.3",
+        "is-callable": "^1.2.4",
+        "is-negative-zero": "^2.0.2",
+        "is-regex": "^1.1.4",
+        "is-shared-array-buffer": "^1.0.2",
+        "is-string": "^1.0.7",
+        "is-weakref": "^1.0.2",
+        "object-inspect": "^1.12.0",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.2",
+        "regexp.prototype.flags": "^1.4.3",
+        "string.prototype.trimend": "^1.0.5",
+        "string.prototype.trimstart": "^1.0.5",
+        "unbox-primitive": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/es-get-iterator": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz",
+      "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.0",
+        "has-symbols": "^1.0.1",
+        "is-arguments": "^1.1.0",
+        "is-map": "^2.0.2",
+        "is-set": "^2.0.2",
+        "is-string": "^1.0.5",
+        "isarray": "^2.0.5"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/es-to-primitive": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+      "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+      "dev": true,
+      "dependencies": {
+        "is-callable": "^1.1.4",
+        "is-date-object": "^1.0.1",
+        "is-symbol": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/es5-ext": {
+      "version": "0.10.62",
+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
+      "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "dependencies": {
+        "es6-iterator": "^2.0.3",
+        "es6-symbol": "^3.1.3",
+        "next-tick": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/es6-error": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
+      "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
+      "dev": true
+    },
+    "node_modules/es6-iterator": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+      "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+      "dev": true,
+      "dependencies": {
+        "d": "1",
+        "es5-ext": "^0.10.35",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "node_modules/es6-symbol": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+      "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+      "dev": true,
+      "dependencies": {
+        "d": "^1.0.1",
+        "ext": "^1.1.2"
+      }
+    },
+    "node_modules/es6-weak-map": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
+      "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
+      "dev": true,
+      "dependencies": {
+        "d": "1",
+        "es5-ext": "^0.10.46",
+        "es6-iterator": "^2.0.3",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/escodegen": {
+      "version": "1.14.3",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
+      "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
+      "dev": true,
+      "dependencies": {
+        "esprima": "^4.0.1",
+        "estraverse": "^4.2.0",
+        "esutils": "^2.0.2",
+        "optionator": "^0.8.1"
+      },
+      "bin": {
+        "escodegen": "bin/escodegen.js",
+        "esgenerate": "bin/esgenerate.js"
+      },
+      "engines": {
+        "node": ">=4.0"
+      },
+      "optionalDependencies": {
+        "source-map": "~0.6.1"
+      }
+    },
+    "node_modules/escodegen/node_modules/estraverse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/escodegen/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "optional": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/eslint": {
+      "version": "8.22.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz",
+      "integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==",
+      "dev": true,
+      "dependencies": {
+        "@eslint/eslintrc": "^1.3.0",
+        "@humanwhocodes/config-array": "^0.10.4",
+        "@humanwhocodes/gitignore-to-minimatch": "^1.0.2",
+        "ajv": "^6.10.0",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.2",
+        "debug": "^4.3.2",
+        "doctrine": "^3.0.0",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^7.1.1",
+        "eslint-utils": "^3.0.0",
+        "eslint-visitor-keys": "^3.3.0",
+        "espree": "^9.3.3",
+        "esquery": "^1.4.0",
+        "esutils": "^2.0.2",
+        "fast-deep-equal": "^3.1.3",
+        "file-entry-cache": "^6.0.1",
+        "find-up": "^5.0.0",
+        "functional-red-black-tree": "^1.0.1",
+        "glob-parent": "^6.0.1",
+        "globals": "^13.15.0",
+        "globby": "^11.1.0",
+        "grapheme-splitter": "^1.0.4",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.0.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "js-yaml": "^4.1.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.4.1",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.1",
+        "regexpp": "^3.2.0",
+        "strip-ansi": "^6.0.1",
+        "strip-json-comments": "^3.1.0",
+        "text-table": "^0.2.0",
+        "v8-compile-cache": "^2.0.3"
+      },
+      "bin": {
+        "eslint": "bin/eslint.js"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint-scope": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+      "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+      "dev": true,
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/eslint-utils": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+      "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+      "dev": true,
+      "dependencies": {
+        "eslint-visitor-keys": "^2.0.0"
+      },
+      "engines": {
+        "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/mysticatea"
+      },
+      "peerDependencies": {
+        "eslint": ">=5"
+      }
+    },
+    "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+      "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/eslint-visitor-keys": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+      "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+      "dev": true,
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/eslint/node_modules/optionator": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+      "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+      "dev": true,
+      "dependencies": {
+        "deep-is": "^0.1.3",
+        "fast-levenshtein": "^2.0.6",
+        "levn": "^0.4.1",
+        "prelude-ls": "^1.2.1",
+        "type-check": "^0.4.0",
+        "word-wrap": "^1.2.3"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/espree": {
+      "version": "9.4.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz",
+      "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==",
+      "dev": true,
+      "dependencies": {
+        "acorn": "^8.8.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/espree/node_modules/acorn": {
+      "version": "8.8.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
+      "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
+      "dev": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true,
+      "bin": {
+        "esparse": "bin/esparse.js",
+        "esvalidate": "bin/esvalidate.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/esquery": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+      "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+      "dev": true,
+      "dependencies": {
+        "estraverse": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/esrecurse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+      "dev": true,
+      "dependencies": {
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/event-emitter": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+      "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
+      "dev": true,
+      "dependencies": {
+        "d": "1",
+        "es5-ext": "~0.10.14"
+      }
+    },
+    "node_modules/events": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+      "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.x"
+      }
+    },
+    "node_modules/evp_bytestokey": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+      "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+      "dev": true,
+      "dependencies": {
+        "md5.js": "^1.3.4",
+        "safe-buffer": "^5.1.1"
+      }
+    },
+    "node_modules/expand-brackets": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+      "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^2.3.3",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "posix-character-classes": "^0.1.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-brackets/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/expand-brackets/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/expand-tilde": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+      "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==",
+      "dev": true,
+      "dependencies": {
+        "homedir-polyfill": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/ext": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz",
+      "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==",
+      "dev": true,
+      "dependencies": {
+        "type": "^2.5.0"
+      }
+    },
+    "node_modules/ext/node_modules/type": {
+      "version": "2.7.2",
+      "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
+      "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==",
+      "dev": true
+    },
+    "node_modules/extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true
+    },
+    "node_modules/extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+      "dev": true,
+      "dependencies": {
+        "is-extendable": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extglob": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+      "dev": true,
+      "dependencies": {
+        "array-unique": "^0.3.2",
+        "define-property": "^1.0.0",
+        "expand-brackets": "^2.1.4",
+        "extend-shallow": "^2.0.1",
+        "fragment-cache": "^0.2.1",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extglob/node_modules/define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+      "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+      "dev": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extglob/node_modules/is-accessor-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+      "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extglob/node_modules/is-data-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+      "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extglob/node_modules/is-descriptor": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+      "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+      "dev": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^1.0.0",
+        "is-data-descriptor": "^1.0.0",
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extglob/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/falafel": {
+      "version": "2.2.5",
+      "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.2.5.tgz",
+      "integrity": "sha512-HuC1qF9iTnHDnML9YZAdCDQwT0yKl/U55K4XSUXqGAA2GLoafFgWRqdAbhWJxXaYD4pyoVxAJ8wH670jMpI9DQ==",
+      "dev": true,
+      "dependencies": {
+        "acorn": "^7.1.1",
+        "isarray": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/fancy-log": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz",
+      "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==",
+      "dev": true,
+      "dependencies": {
+        "ansi-gray": "^0.1.1",
+        "color-support": "^1.1.3",
+        "parse-node-version": "^1.0.0",
+        "time-stamp": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true
+    },
+    "node_modules/fast-glob": {
+      "version": "3.2.11",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
+      "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-glob/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true
+    },
+    "node_modules/fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+      "dev": true
+    },
+    "node_modules/fast-safe-stringify": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
+      "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
+      "dev": true
+    },
+    "node_modules/fastq": {
+      "version": "1.13.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
+      "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
+      "dev": true,
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/file-entry-cache": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+      "dev": true,
+      "dependencies": {
+        "flat-cache": "^3.0.4"
+      },
+      "engines": {
+        "node": "^10.12.0 || >=12.0.0"
+      }
+    },
+    "node_modules/file-uri-to-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+      "dev": true,
+      "optional": true
+    },
+    "node_modules/filename-reserved-regex": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
+      "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/filenamify": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz",
+      "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==",
+      "dev": true,
+      "dependencies": {
+        "filename-reserved-regex": "^2.0.0",
+        "strip-outer": "^1.0.1",
+        "trim-repeated": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+      "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
+      "dev": true,
+      "dependencies": {
+        "extend-shallow": "^2.0.1",
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1",
+        "to-regex-range": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/find-cache-dir": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
+      "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
+      "dev": true,
+      "dependencies": {
+        "commondir": "^1.0.1",
+        "make-dir": "^3.0.2",
+        "pkg-dir": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/avajs/find-cache-dir?sponsor=1"
+      }
+    },
+    "node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/findup-sync": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
+      "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==",
+      "dev": true,
+      "dependencies": {
+        "detect-file": "^1.0.0",
+        "is-glob": "^4.0.0",
+        "micromatch": "^3.0.4",
+        "resolve-dir": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/findup-sync/node_modules/define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/findup-sync/node_modules/extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+      "dev": true,
+      "dependencies": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/findup-sync/node_modules/is-accessor-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+      "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/findup-sync/node_modules/is-data-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+      "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/findup-sync/node_modules/is-descriptor": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+      "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+      "dev": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^1.0.0",
+        "is-data-descriptor": "^1.0.0",
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/findup-sync/node_modules/is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/findup-sync/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/findup-sync/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/findup-sync/node_modules/micromatch": {
+      "version": "3.1.10",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+      "dev": true,
+      "dependencies": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "braces": "^2.3.1",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "extglob": "^2.0.4",
+        "fragment-cache": "^0.2.1",
+        "kind-of": "^6.0.2",
+        "nanomatch": "^1.2.9",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/fined": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz",
+      "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==",
+      "dev": true,
+      "dependencies": {
+        "expand-tilde": "^2.0.2",
+        "is-plain-object": "^2.0.3",
+        "object.defaults": "^1.1.0",
+        "object.pick": "^1.2.0",
+        "parse-filepath": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/fined/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/flagged-respawn": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz",
+      "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/flat-cache": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+      "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+      "dev": true,
+      "dependencies": {
+        "flatted": "^3.1.0",
+        "rimraf": "^3.0.2"
+      },
+      "engines": {
+        "node": "^10.12.0 || >=12.0.0"
+      }
+    },
+    "node_modules/flatted": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+      "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+      "dev": true
+    },
+    "node_modules/flush-write-stream": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
+      "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.3.6"
+      }
+    },
+    "node_modules/for-each": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+      "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+      "dev": true,
+      "dependencies": {
+        "is-callable": "^1.1.3"
+      }
+    },
+    "node_modules/for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/for-own": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+      "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==",
+      "dev": true,
+      "dependencies": {
+        "for-in": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/foreground-child": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
+      "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
+      "dev": true,
+      "dependencies": {
+        "cross-spawn": "^7.0.0",
+        "signal-exit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/fork-stream": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz",
+      "integrity": "sha512-Pqq5NnT78ehvUnAk/We/Jr22vSvanRlFTpAmQ88xBY/M1TlHe+P0ILuEyXS595ysdGfaj22634LBkGMA2GTcpA==",
+      "dev": true
+    },
+    "node_modules/fragment-cache": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+      "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==",
+      "dev": true,
+      "dependencies": {
+        "map-cache": "^0.2.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/fromentries": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz",
+      "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/fs-extra": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+      "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=6 <7 || >=8"
+      }
+    },
+    "node_modules/fs-mkdirp-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz",
+      "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.11",
+        "through2": "^2.0.3"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+      "dev": true
+    },
+    "node_modules/fsevents": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+      "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+      "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "dependencies": {
+        "bindings": "^1.5.0",
+        "nan": "^2.12.1"
+      },
+      "engines": {
+        "node": ">= 4.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
+    },
+    "node_modules/function.prototype.name": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
+      "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.19.0",
+        "functions-have-names": "^1.2.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/functional-red-black-tree": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+      "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
+      "dev": true
+    },
+    "node_modules/functions-have-names": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/get-assigned-identifiers": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz",
+      "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==",
+      "dev": true
+    },
+    "node_modules/get-caller-file": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+      "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
+      "dev": true
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz",
+      "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==",
+      "dev": true,
+      "dependencies": {
+        "function-bind": "^1.1.1",
+        "has": "^1.0.3",
+        "has-symbols": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-package-type": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+      "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/get-symbol-description": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
+      "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-value": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+      "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/gh-pages": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-4.0.0.tgz",
+      "integrity": "sha512-p8S0T3aGJc68MtwOcZusul5qPSNZCalap3NWbhRUZYu1YOdp+EjZ+4kPmRM8h3NNRdqw00yuevRjlkuSzCn7iQ==",
+      "dev": true,
+      "dependencies": {
+        "async": "^2.6.1",
+        "commander": "^2.18.0",
+        "email-addresses": "^3.0.1",
+        "filenamify": "^4.3.0",
+        "find-cache-dir": "^3.3.1",
+        "fs-extra": "^8.1.0",
+        "globby": "^6.1.0"
+      },
+      "bin": {
+        "gh-pages": "bin/gh-pages.js",
+        "gh-pages-clean": "bin/gh-pages-clean.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/gh-pages/node_modules/array-union": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+      "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
+      "dev": true,
+      "dependencies": {
+        "array-uniq": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/gh-pages/node_modules/globby": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+      "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==",
+      "dev": true,
+      "dependencies": {
+        "array-union": "^1.0.1",
+        "glob": "^7.0.3",
+        "object-assign": "^4.0.1",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/git-raw-commits": {
+      "version": "2.0.11",
+      "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz",
+      "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==",
+      "dev": true,
+      "dependencies": {
+        "dargs": "^7.0.0",
+        "lodash": "^4.17.15",
+        "meow": "^8.0.0",
+        "split2": "^3.0.0",
+        "through2": "^4.0.0"
+      },
+      "bin": {
+        "git-raw-commits": "cli.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/git-raw-commits/node_modules/readable-stream": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/git-raw-commits/node_modules/through2": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz",
+      "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==",
+      "dev": true,
+      "dependencies": {
+        "readable-stream": "3"
+      }
+    },
+    "node_modules/git-semver-tags": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz",
+      "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==",
+      "dev": true,
+      "dependencies": {
+        "meow": "^8.0.0",
+        "semver": "^6.0.0"
+      },
+      "bin": {
+        "git-semver-tags": "cli.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/glob-stream": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz",
+      "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==",
+      "dev": true,
+      "dependencies": {
+        "extend": "^3.0.0",
+        "glob": "^7.1.1",
+        "glob-parent": "^3.1.0",
+        "is-negated-glob": "^1.0.0",
+        "ordered-read-streams": "^1.0.0",
+        "pumpify": "^1.3.5",
+        "readable-stream": "^2.1.5",
+        "remove-trailing-separator": "^1.0.1",
+        "to-absolute-glob": "^2.0.0",
+        "unique-stream": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/glob-stream/node_modules/glob-parent": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+      "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^3.1.0",
+        "path-dirname": "^1.0.0"
+      }
+    },
+    "node_modules/glob-stream/node_modules/is-glob": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+      "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
+      "dev": true,
+      "dependencies": {
+        "is-extglob": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/glob-watcher": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz",
+      "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==",
+      "dev": true,
+      "dependencies": {
+        "anymatch": "^2.0.0",
+        "async-done": "^1.2.0",
+        "chokidar": "^2.0.0",
+        "is-negated-glob": "^1.0.0",
+        "just-debounce": "^1.0.0",
+        "normalize-path": "^3.0.0",
+        "object.defaults": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/global-modules": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+      "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+      "dev": true,
+      "dependencies": {
+        "global-prefix": "^1.0.1",
+        "is-windows": "^1.0.1",
+        "resolve-dir": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/global-prefix": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+      "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==",
+      "dev": true,
+      "dependencies": {
+        "expand-tilde": "^2.0.2",
+        "homedir-polyfill": "^1.0.1",
+        "ini": "^1.3.4",
+        "is-windows": "^1.0.1",
+        "which": "^1.2.14"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/global-prefix/node_modules/which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "which": "bin/which"
+      }
+    },
+    "node_modules/globals": {
+      "version": "13.17.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
+      "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
+      "dev": true,
+      "dependencies": {
+        "type-fest": "^0.20.2"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/globby": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+      "dev": true,
+      "dependencies": {
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/glogg": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz",
+      "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==",
+      "dev": true,
+      "dependencies": {
+        "sparkles": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/google-protobuf": {
+      "version": "3.21.0",
+      "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.0.tgz",
+      "integrity": "sha512-byR7MBTK4tZ5PZEb+u5ZTzpt4SfrTxv5682MjPlHN16XeqgZE2/8HOIWeiXe8JKnT9OVbtBGhbq8mtvkK8cd5g==",
+      "dev": true
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.10",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+      "dev": true
+    },
+    "node_modules/grapheme-splitter": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+      "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+      "dev": true
+    },
+    "node_modules/gulp": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz",
+      "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==",
+      "dev": true,
+      "dependencies": {
+        "glob-watcher": "^5.0.3",
+        "gulp-cli": "^2.2.0",
+        "undertaker": "^1.2.1",
+        "vinyl-fs": "^3.0.0"
+      },
+      "bin": {
+        "gulp": "bin/gulp.js"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/gulp-cli": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz",
+      "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-colors": "^1.0.1",
+        "archy": "^1.0.0",
+        "array-sort": "^1.0.0",
+        "color-support": "^1.1.3",
+        "concat-stream": "^1.6.0",
+        "copy-props": "^2.0.1",
+        "fancy-log": "^1.3.2",
+        "gulplog": "^1.0.0",
+        "interpret": "^1.4.0",
+        "isobject": "^3.0.1",
+        "liftoff": "^3.1.0",
+        "matchdep": "^2.0.0",
+        "mute-stdout": "^1.0.0",
+        "pretty-hrtime": "^1.0.0",
+        "replace-homedir": "^1.0.0",
+        "semver-greatest-satisfied-range": "^1.1.0",
+        "v8flags": "^3.2.0",
+        "yargs": "^7.1.0"
+      },
+      "bin": {
+        "gulp": "bin/gulp.js"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/gulp-header": {
+      "version": "2.0.9",
+      "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-2.0.9.tgz",
+      "integrity": "sha512-LMGiBx+qH8giwrOuuZXSGvswcIUh0OiioNkUpLhNyvaC6/Ga8X6cfAeme2L5PqsbXMhL8o8b/OmVqIQdxprhcQ==",
+      "dev": true,
+      "dependencies": {
+        "concat-with-sourcemaps": "^1.1.0",
+        "lodash.template": "^4.5.0",
+        "map-stream": "0.0.7",
+        "through2": "^2.0.0"
+      }
+    },
+    "node_modules/gulp-if": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/gulp-if/-/gulp-if-3.0.0.tgz",
+      "integrity": "sha512-fCUEngzNiEZEK2YuPm+sdMpO6ukb8+/qzbGfJBXyNOXz85bCG7yBI+pPSl+N90d7gnLvMsarthsAImx0qy7BAw==",
+      "dev": true,
+      "dependencies": {
+        "gulp-match": "^1.1.0",
+        "ternary-stream": "^3.0.0",
+        "through2": "^3.0.1"
+      }
+    },
+    "node_modules/gulp-if/node_modules/through2": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
+      "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.4",
+        "readable-stream": "2 || 3"
+      }
+    },
+    "node_modules/gulp-match": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/gulp-match/-/gulp-match-1.1.0.tgz",
+      "integrity": "sha512-DlyVxa1Gj24DitY2OjEsS+X6tDpretuxD6wTfhXE/Rw2hweqc1f6D/XtsJmoiCwLWfXgR87W9ozEityPCVzGtQ==",
+      "dev": true,
+      "dependencies": {
+        "minimatch": "^3.0.3"
+      }
+    },
+    "node_modules/gulp-sourcemaps": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-3.0.0.tgz",
+      "integrity": "sha512-RqvUckJkuYqy4VaIH60RMal4ZtG0IbQ6PXMNkNsshEGJ9cldUPRb/YCgboYae+CLAs1HQNb4ADTKCx65HInquQ==",
+      "dev": true,
+      "dependencies": {
+        "@gulp-sourcemaps/identity-map": "^2.0.1",
+        "@gulp-sourcemaps/map-sources": "^1.0.0",
+        "acorn": "^6.4.1",
+        "convert-source-map": "^1.0.0",
+        "css": "^3.0.0",
+        "debug-fabulous": "^1.0.0",
+        "detect-newline": "^2.0.0",
+        "graceful-fs": "^4.0.0",
+        "source-map": "^0.6.0",
+        "strip-bom-string": "^1.0.0",
+        "through2": "^2.0.0"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/gulp-sourcemaps/node_modules/acorn": {
+      "version": "6.4.2",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
+      "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
+      "dev": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/gulp-sourcemaps/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/gulp-uglify": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.2.tgz",
+      "integrity": "sha512-gk1dhB74AkV2kzqPMQBLA3jPoIAPd/nlNzP2XMDSG8XZrqnlCiDGAqC+rZOumzFvB5zOphlFh6yr3lgcAb/OOg==",
+      "dev": true,
+      "dependencies": {
+        "array-each": "^1.0.1",
+        "extend-shallow": "^3.0.2",
+        "gulplog": "^1.0.0",
+        "has-gulplog": "^0.1.0",
+        "isobject": "^3.0.1",
+        "make-error-cause": "^1.1.1",
+        "safe-buffer": "^5.1.2",
+        "through2": "^2.0.0",
+        "uglify-js": "^3.0.5",
+        "vinyl-sourcemaps-apply": "^0.2.0"
+      }
+    },
+    "node_modules/gulp-uglify/node_modules/extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+      "dev": true,
+      "dependencies": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/gulp-uglify/node_modules/is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/gulp-uglify/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/gulplog": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
+      "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==",
+      "dev": true,
+      "dependencies": {
+        "glogg": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/hard-rejection": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
+      "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dev": true,
+      "dependencies": {
+        "function-bind": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/has-bigints": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
+      "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-dynamic-import": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/has-dynamic-import/-/has-dynamic-import-2.0.1.tgz",
+      "integrity": "sha512-X3fbtsZmwb6W7fJGR9o7x65fZoodygCrZ3TVycvghP62yYQfS0t4RS0Qcz+j5tQYUKeSWS09tHkWW6WhFV3XhQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/has-gulplog": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
+      "integrity": "sha512-+F4GzLjwHNNDEAJW2DC1xXfEoPkRDmUdJ7CBYw4MpqtDwOnqdImJl7GWlpqx+Wko6//J8uKTnIe4wZSv7yCqmw==",
+      "dev": true,
+      "dependencies": {
+        "sparkles": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/has-property-descriptors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
+      "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.1.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-tostringtag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
+      "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
+      "dev": true,
+      "dependencies": {
+        "has-symbols": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+      "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==",
+      "dev": true,
+      "dependencies": {
+        "get-value": "^2.0.6",
+        "has-values": "^1.0.0",
+        "isobject": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-values": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+      "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==",
+      "dev": true,
+      "dependencies": {
+        "is-number": "^3.0.0",
+        "kind-of": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-values/node_modules/kind-of": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+      "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==",
+      "dev": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/hash-base": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+      "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.6.0",
+        "safe-buffer": "^5.2.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/hash-base/node_modules/readable-stream": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/hash.js": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+      "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "minimalistic-assert": "^1.0.1"
+      }
+    },
+    "node_modules/hasha": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz",
+      "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==",
+      "dev": true,
+      "dependencies": {
+        "is-stream": "^2.0.0",
+        "type-fest": "^0.8.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/hasha/node_modules/type-fest": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+      "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/hmac-drbg": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+      "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==",
+      "dev": true,
+      "dependencies": {
+        "hash.js": "^1.0.3",
+        "minimalistic-assert": "^1.0.0",
+        "minimalistic-crypto-utils": "^1.0.1"
+      }
+    },
+    "node_modules/homedir-polyfill": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+      "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+      "dev": true,
+      "dependencies": {
+        "parse-passwd": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/hosted-git-info": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+      "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/html-escaper": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+      "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+      "dev": true
+    },
+    "node_modules/htmlescape": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz",
+      "integrity": "sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/https-browserify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+      "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==",
+      "dev": true
+    },
+    "node_modules/ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/ignore": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
+      "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dev": true,
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.19"
+      }
+    },
+    "node_modules/indent-string": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+      "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "dev": true,
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true
+    },
+    "node_modules/ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+      "dev": true
+    },
+    "node_modules/inline-source-map": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz",
+      "integrity": "sha512-0mVWSSbNDvedDWIN4wxLsdPM4a7cIPcpyMxj3QZ406QRwQ6ePGB1YIHxVPjqpcUGbWQ5C+nHTwGNWAGvt7ggVA==",
+      "dev": true,
+      "dependencies": {
+        "source-map": "~0.5.3"
+      }
+    },
+    "node_modules/insert-module-globals": {
+      "version": "7.2.1",
+      "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.1.tgz",
+      "integrity": "sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==",
+      "dev": true,
+      "dependencies": {
+        "acorn-node": "^1.5.2",
+        "combine-source-map": "^0.8.0",
+        "concat-stream": "^1.6.1",
+        "is-buffer": "^1.1.0",
+        "JSONStream": "^1.0.3",
+        "path-is-absolute": "^1.0.1",
+        "process": "~0.11.0",
+        "through2": "^2.0.0",
+        "undeclared-identifiers": "^1.1.2",
+        "xtend": "^4.0.0"
+      },
+      "bin": {
+        "insert-module-globals": "bin/cmd.js"
+      }
+    },
+    "node_modules/internal-slot": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
+      "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.1.0",
+        "has": "^1.0.3",
+        "side-channel": "^1.0.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/interpret": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
+      "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/invert-kv": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+      "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-absolute": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+      "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
+      "dev": true,
+      "dependencies": {
+        "is-relative": "^1.0.0",
+        "is-windows": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-accessor-descriptor/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-arguments": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
+      "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+      "dev": true
+    },
+    "node_modules/is-bigint": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
+      "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
+      "dev": true,
+      "dependencies": {
+        "has-bigints": "^1.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-binary-path": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+      "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==",
+      "dev": true,
+      "dependencies": {
+        "binary-extensions": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-boolean-object": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
+      "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true
+    },
+    "node_modules/is-callable": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
+      "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-core-module": {
+      "version": "2.10.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz",
+      "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==",
+      "dev": true,
+      "dependencies": {
+        "has": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-data-descriptor/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-date-object": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
+      "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+      "dev": true,
+      "dependencies": {
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+      "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==",
+      "dev": true,
+      "dependencies": {
+        "number-is-nan": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-generator-function": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
+      "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
+      "dev": true,
+      "dependencies": {
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-map": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
+      "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-negated-glob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
+      "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-negative-zero": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
+      "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+      "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-number-object": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
+      "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
+      "dev": true,
+      "dependencies": {
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-number/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-plain-obj": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+      "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-plain-object": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+      "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-promise": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
+      "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==",
+      "dev": true
+    },
+    "node_modules/is-regex": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
+      "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-relative": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+      "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
+      "dev": true,
+      "dependencies": {
+        "is-unc-path": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-set": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
+      "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-shared-array-buffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
+      "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-string": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
+      "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
+      "dev": true,
+      "dependencies": {
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-symbol": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
+      "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+      "dev": true,
+      "dependencies": {
+        "has-symbols": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-typed-array": {
+      "version": "1.1.9",
+      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz",
+      "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==",
+      "dev": true,
+      "dependencies": {
+        "available-typed-arrays": "^1.0.5",
+        "call-bind": "^1.0.2",
+        "es-abstract": "^1.20.0",
+        "for-each": "^0.3.3",
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
+      "dev": true
+    },
+    "node_modules/is-unc-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+      "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
+      "dev": true,
+      "dependencies": {
+        "unc-path-regex": "^0.1.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-utf8": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+      "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==",
+      "dev": true
+    },
+    "node_modules/is-valid-glob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz",
+      "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-weakmap": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
+      "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakref": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
+      "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakset": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
+      "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-windows": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/isarray": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+      "dev": true
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true
+    },
+    "node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/istanbul-lib-coverage": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
+      "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-hook": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz",
+      "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==",
+      "dev": true,
+      "dependencies": {
+        "append-transform": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-instrument": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
+      "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/core": "^7.7.5",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-coverage": "^3.0.0",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-processinfo": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz",
+      "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==",
+      "dev": true,
+      "dependencies": {
+        "archy": "^1.0.0",
+        "cross-spawn": "^7.0.3",
+        "istanbul-lib-coverage": "^3.2.0",
+        "p-map": "^3.0.0",
+        "rimraf": "^3.0.0",
+        "uuid": "^8.3.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-report": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+      "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
+      "dev": true,
+      "dependencies": {
+        "istanbul-lib-coverage": "^3.0.0",
+        "make-dir": "^3.0.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-source-maps": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
+      "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^4.1.1",
+        "istanbul-lib-coverage": "^3.0.0",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-lib-source-maps/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/istanbul-reports": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
+      "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
+      "dev": true,
+      "dependencies": {
+        "html-escaper": "^2.0.0",
+        "istanbul-lib-report": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jaguarjs-jsdoc": {
+      "version": "0.0.1",
+      "resolved": "git+ssh://git@github.com/dcodeIO/jaguarjs-jsdoc.git#ade85ac841f5ca8be40c60d506102039a036a8fa",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true
+    },
+    "node_modules/js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/js2xmlparser": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz",
+      "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==",
+      "dev": true,
+      "dependencies": {
+        "xmlcreate": "^2.0.4"
+      }
+    },
+    "node_modules/jsdoc": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.0.tgz",
+      "integrity": "sha512-tzTgkklbWKrlaQL2+e3NNgLcZu3NaK2vsHRx7tyHQ+H5jcB9Gx0txSd2eJWlMC/xU1+7LQu4s58Ry0RkuaEQVg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/parser": "^7.9.4",
+        "@jsdoc/salty": "^0.2.1",
+        "@types/markdown-it": "^12.2.3",
+        "bluebird": "^3.7.2",
+        "catharsis": "^0.9.0",
+        "escape-string-regexp": "^2.0.0",
+        "js2xmlparser": "^4.0.2",
+        "klaw": "^3.0.0",
+        "markdown-it": "^12.3.2",
+        "markdown-it-anchor": "^8.4.1",
+        "marked": "^4.0.10",
+        "mkdirp": "^1.0.4",
+        "requizzle": "^0.2.3",
+        "strip-json-comments": "^3.1.0",
+        "underscore": "~1.13.2"
+      },
+      "bin": {
+        "jsdoc": "jsdoc.js"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/jsdoc/node_modules/escape-string-regexp": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+      "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jsesc": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+      "dev": true,
+      "bin": {
+        "jsesc": "bin/jsesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+      "dev": true
+    },
+    "node_modules/json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true
+    },
+    "node_modules/json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+      "dev": true
+    },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "dev": true,
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/jsonfile": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+      "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+      "dev": true,
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/jsonparse": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+      "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
+      "dev": true,
+      "engines": [
+        "node >= 0.2.0"
+      ]
+    },
+    "node_modules/JSONStream": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
+      "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
+      "dev": true,
+      "dependencies": {
+        "jsonparse": "^1.2.0",
+        "through": ">=2.2.7 <3"
+      },
+      "bin": {
+        "JSONStream": "bin.js"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/just-debounce": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz",
+      "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==",
+      "dev": true
+    },
+    "node_modules/kind-of": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+      "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/klaw": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz",
+      "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.9"
+      }
+    },
+    "node_modules/labeled-stream-splicer": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz",
+      "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.1",
+        "stream-splicer": "^2.0.0"
+      }
+    },
+    "node_modules/last-run": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz",
+      "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==",
+      "dev": true,
+      "dependencies": {
+        "default-resolution": "^2.0.0",
+        "es6-weak-map": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/lazystream": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
+      "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
+      "dev": true,
+      "dependencies": {
+        "readable-stream": "^2.0.5"
+      },
+      "engines": {
+        "node": ">= 0.6.3"
+      }
+    },
+    "node_modules/lcid": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+      "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==",
+      "dev": true,
+      "dependencies": {
+        "invert-kv": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/lead": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz",
+      "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==",
+      "dev": true,
+      "dependencies": {
+        "flush-write-stream": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/levn": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+      "dev": true,
+      "dependencies": {
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/liftoff": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz",
+      "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==",
+      "dev": true,
+      "dependencies": {
+        "extend": "^3.0.0",
+        "findup-sync": "^3.0.0",
+        "fined": "^1.0.1",
+        "flagged-respawn": "^1.0.0",
+        "is-plain-object": "^2.0.4",
+        "object.map": "^1.0.0",
+        "rechoir": "^0.6.2",
+        "resolve": "^1.1.7"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/liftoff/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+      "dev": true
+    },
+    "node_modules/linkify-it": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+      "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+      "dev": true,
+      "dependencies": {
+        "uc.micro": "^1.0.1"
+      }
+    },
+    "node_modules/load-json-file": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+      "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.2",
+        "parse-json": "^2.2.0",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0",
+        "strip-bom": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/load-json-file/node_modules/parse-json": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+      "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==",
+      "dev": true,
+      "dependencies": {
+        "error-ex": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/load-json-file/node_modules/strip-bom": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+      "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==",
+      "dev": true,
+      "dependencies": {
+        "is-utf8": "^0.2.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+      "dev": true
+    },
+    "node_modules/lodash._reinterpolate": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
+      "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==",
+      "dev": true
+    },
+    "node_modules/lodash.flattendeep": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
+      "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==",
+      "dev": true
+    },
+    "node_modules/lodash.memoize": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
+      "integrity": "sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==",
+      "dev": true
+    },
+    "node_modules/lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "dev": true
+    },
+    "node_modules/lodash.template": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
+      "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==",
+      "dev": true,
+      "dependencies": {
+        "lodash._reinterpolate": "^3.0.0",
+        "lodash.templatesettings": "^4.0.0"
+      }
+    },
+    "node_modules/lodash.templatesettings": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz",
+      "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==",
+      "dev": true,
+      "dependencies": {
+        "lodash._reinterpolate": "^3.0.0"
+      }
+    },
+    "node_modules/long": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/long/-/long-5.2.0.tgz",
+      "integrity": "sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w=="
+    },
+    "node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/lru-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
+      "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==",
+      "dev": true,
+      "dependencies": {
+        "es5-ext": "~0.10.2"
+      }
+    },
+    "node_modules/make-dir": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+      "dev": true,
+      "dependencies": {
+        "semver": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+      "dev": true
+    },
+    "node_modules/make-error-cause": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz",
+      "integrity": "sha512-4TO2Y3HkBnis4c0dxhAgD/jprySYLACf7nwN6V0HAHDx59g12WlRpUmFy1bRHamjGUEEBrEvCq6SUpsEE2lhUg==",
+      "dev": true,
+      "dependencies": {
+        "make-error": "^1.2.0"
+      }
+    },
+    "node_modules/make-iterator": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
+      "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/make-iterator/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/map-cache": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+      "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/map-obj": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
+      "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/map-stream": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz",
+      "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==",
+      "dev": true
+    },
+    "node_modules/map-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+      "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==",
+      "dev": true,
+      "dependencies": {
+        "object-visit": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/markdown-it": {
+      "version": "12.3.2",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+      "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^2.0.1",
+        "entities": "~2.1.0",
+        "linkify-it": "^3.0.1",
+        "mdurl": "^1.0.1",
+        "uc.micro": "^1.0.5"
+      },
+      "bin": {
+        "markdown-it": "bin/markdown-it.js"
+      }
+    },
+    "node_modules/markdown-it-anchor": {
+      "version": "8.6.4",
+      "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.4.tgz",
+      "integrity": "sha512-Ul4YVYZNxMJYALpKtu+ZRdrryYt/GlQ5CK+4l1bp/gWXOG2QWElt6AqF3Mih/wfUKdZbNAZVXGR73/n6U/8img==",
+      "dev": true,
+      "peerDependencies": {
+        "@types/markdown-it": "*",
+        "markdown-it": "*"
+      }
+    },
+    "node_modules/marked": {
+      "version": "4.0.19",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.19.tgz",
+      "integrity": "sha512-rgQF/OxOiLcvgUAj1Q1tAf4Bgxn5h5JZTp04Fx4XUkVhs7B+7YA9JEWJhJpoO8eJt8MkZMwqLCNeNqj1bCREZQ==",
+      "dev": true,
+      "bin": {
+        "marked": "bin/marked.js"
+      },
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/matchdep": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
+      "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==",
+      "dev": true,
+      "dependencies": {
+        "findup-sync": "^2.0.0",
+        "micromatch": "^3.0.4",
+        "resolve": "^1.4.0",
+        "stack-trace": "0.0.10"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
+    "node_modules/matchdep/node_modules/define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/matchdep/node_modules/extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+      "dev": true,
+      "dependencies": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/matchdep/node_modules/findup-sync": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
+      "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==",
+      "dev": true,
+      "dependencies": {
+        "detect-file": "^1.0.0",
+        "is-glob": "^3.1.0",
+        "micromatch": "^3.0.4",
+        "resolve-dir": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/matchdep/node_modules/is-accessor-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+      "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/matchdep/node_modules/is-data-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+      "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/matchdep/node_modules/is-descriptor": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+      "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+      "dev": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^1.0.0",
+        "is-data-descriptor": "^1.0.0",
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/matchdep/node_modules/is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/matchdep/node_modules/is-glob": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+      "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
+      "dev": true,
+      "dependencies": {
+        "is-extglob": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/matchdep/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/matchdep/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/matchdep/node_modules/micromatch": {
+      "version": "3.1.10",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+      "dev": true,
+      "dependencies": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "braces": "^2.3.1",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "extglob": "^2.0.4",
+        "fragment-cache": "^0.2.1",
+        "kind-of": "^6.0.2",
+        "nanomatch": "^1.2.9",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/md5.js": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+      "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+      "dev": true,
+      "dependencies": {
+        "hash-base": "^3.0.0",
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      }
+    },
+    "node_modules/mdurl": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+      "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
+      "dev": true
+    },
+    "node_modules/memoizee": {
+      "version": "0.4.15",
+      "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz",
+      "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==",
+      "dev": true,
+      "dependencies": {
+        "d": "^1.0.1",
+        "es5-ext": "^0.10.53",
+        "es6-weak-map": "^2.0.3",
+        "event-emitter": "^0.3.5",
+        "is-promise": "^2.2.2",
+        "lru-queue": "^0.1.0",
+        "next-tick": "^1.1.0",
+        "timers-ext": "^0.1.7"
+      }
+    },
+    "node_modules/meow": {
+      "version": "8.1.2",
+      "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz",
+      "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==",
+      "dev": true,
+      "dependencies": {
+        "@types/minimist": "^1.2.0",
+        "camelcase-keys": "^6.2.2",
+        "decamelize-keys": "^1.1.0",
+        "hard-rejection": "^2.1.0",
+        "minimist-options": "4.1.0",
+        "normalize-package-data": "^3.0.0",
+        "read-pkg-up": "^7.0.1",
+        "redent": "^3.0.0",
+        "trim-newlines": "^3.0.0",
+        "type-fest": "^0.18.0",
+        "yargs-parser": "^20.2.3"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/meow/node_modules/type-fest": {
+      "version": "0.18.1",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
+      "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/merge-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+      "dev": true
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+      "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+      "dev": true,
+      "dependencies": {
+        "braces": "^3.0.2",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/micromatch/node_modules/braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dev": true,
+      "dependencies": {
+        "fill-range": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/micromatch/node_modules/fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dev": true,
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/micromatch/node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/micromatch/node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/miller-rabin": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+      "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+      "dev": true,
+      "dependencies": {
+        "bn.js": "^4.0.0",
+        "brorand": "^1.0.1"
+      },
+      "bin": {
+        "miller-rabin": "bin/miller-rabin"
+      }
+    },
+    "node_modules/miller-rabin/node_modules/bn.js": {
+      "version": "4.12.0",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+      "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+      "dev": true
+    },
+    "node_modules/min-indent": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+      "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/minimalistic-assert": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+      "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+      "dev": true
+    },
+    "node_modules/minimalistic-crypto-utils": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+      "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==",
+      "dev": true
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+      "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
+      "dev": true
+    },
+    "node_modules/minimist-options": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
+      "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
+      "dev": true,
+      "dependencies": {
+        "arrify": "^1.0.1",
+        "is-plain-obj": "^1.1.0",
+        "kind-of": "^6.0.3"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/minimist-options/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/mixin-deep": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+      "dev": true,
+      "dependencies": {
+        "for-in": "^1.0.2",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/mixin-deep/node_modules/is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/mixin-deep/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "dev": true,
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/mkdirp-classic": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+      "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+      "dev": true
+    },
+    "node_modules/module-deps": {
+      "version": "6.2.3",
+      "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz",
+      "integrity": "sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==",
+      "dev": true,
+      "dependencies": {
+        "browser-resolve": "^2.0.0",
+        "cached-path-relative": "^1.0.2",
+        "concat-stream": "~1.6.0",
+        "defined": "^1.0.0",
+        "detective": "^5.2.0",
+        "duplexer2": "^0.1.2",
+        "inherits": "^2.0.1",
+        "JSONStream": "^1.0.3",
+        "parents": "^1.0.0",
+        "readable-stream": "^2.0.2",
+        "resolve": "^1.4.0",
+        "stream-combiner2": "^1.1.1",
+        "subarg": "^1.0.0",
+        "through2": "^2.0.0",
+        "xtend": "^4.0.0"
+      },
+      "bin": {
+        "module-deps": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
+    },
+    "node_modules/mute-stdout": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz",
+      "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/nan": {
+      "version": "2.16.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz",
+      "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
+      "dev": true,
+      "optional": true
+    },
+    "node_modules/nanomatch": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+      "dev": true,
+      "dependencies": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "fragment-cache": "^0.2.1",
+        "is-windows": "^1.0.2",
+        "kind-of": "^6.0.2",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nanomatch/node_modules/define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nanomatch/node_modules/extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+      "dev": true,
+      "dependencies": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nanomatch/node_modules/is-accessor-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+      "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nanomatch/node_modules/is-data-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+      "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nanomatch/node_modules/is-descriptor": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+      "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+      "dev": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^1.0.0",
+        "is-data-descriptor": "^1.0.0",
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nanomatch/node_modules/is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nanomatch/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nanomatch/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+      "dev": true
+    },
+    "node_modules/next-tick": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
+      "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==",
+      "dev": true
+    },
+    "node_modules/node-preload": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
+      "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==",
+      "dev": true,
+      "dependencies": {
+        "process-on-spawn": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
+      "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
+      "dev": true
+    },
+    "node_modules/normalize-package-data": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
+      "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
+      "dev": true,
+      "dependencies": {
+        "hosted-git-info": "^4.0.1",
+        "is-core-module": "^2.5.0",
+        "semver": "^7.3.4",
+        "validate-npm-package-license": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/normalize-package-data/node_modules/semver": {
+      "version": "7.3.7",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/now-and-later": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz",
+      "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==",
+      "dev": true,
+      "dependencies": {
+        "once": "^1.3.2"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nyc": {
+      "version": "15.1.0",
+      "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
+      "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==",
+      "dev": true,
+      "dependencies": {
+        "@istanbuljs/load-nyc-config": "^1.0.0",
+        "@istanbuljs/schema": "^0.1.2",
+        "caching-transform": "^4.0.0",
+        "convert-source-map": "^1.7.0",
+        "decamelize": "^1.2.0",
+        "find-cache-dir": "^3.2.0",
+        "find-up": "^4.1.0",
+        "foreground-child": "^2.0.0",
+        "get-package-type": "^0.1.0",
+        "glob": "^7.1.6",
+        "istanbul-lib-coverage": "^3.0.0",
+        "istanbul-lib-hook": "^3.0.0",
+        "istanbul-lib-instrument": "^4.0.0",
+        "istanbul-lib-processinfo": "^2.0.2",
+        "istanbul-lib-report": "^3.0.0",
+        "istanbul-lib-source-maps": "^4.0.0",
+        "istanbul-reports": "^3.0.2",
+        "make-dir": "^3.0.0",
+        "node-preload": "^0.2.1",
+        "p-map": "^3.0.0",
+        "process-on-spawn": "^1.0.0",
+        "resolve-from": "^5.0.0",
+        "rimraf": "^3.0.0",
+        "signal-exit": "^3.0.2",
+        "spawn-wrap": "^2.0.0",
+        "test-exclude": "^6.0.0",
+        "yargs": "^15.0.2"
+      },
+      "bin": {
+        "nyc": "bin/nyc.js"
+      },
+      "engines": {
+        "node": ">=8.9"
+      }
+    },
+    "node_modules/nyc/node_modules/cliui": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^6.2.0"
+      }
+    },
+    "node_modules/nyc/node_modules/convert-source-map": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
+      "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "~5.1.1"
+      }
+    },
+    "node_modules/nyc/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/nyc/node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true,
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/nyc/node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/nyc/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/nyc/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/nyc/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/nyc/node_modules/require-main-filename": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+      "dev": true
+    },
+    "node_modules/nyc/node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/nyc/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
+    },
+    "node_modules/nyc/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/nyc/node_modules/which-module": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+      "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
+      "dev": true
+    },
+    "node_modules/nyc/node_modules/wrap-ansi": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/nyc/node_modules/y18n": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+      "dev": true
+    },
+    "node_modules/nyc/node_modules/yargs": {
+      "version": "15.4.1",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+      "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+      "dev": true,
+      "dependencies": {
+        "cliui": "^6.0.0",
+        "decamelize": "^1.2.0",
+        "find-up": "^4.1.0",
+        "get-caller-file": "^2.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^2.0.0",
+        "set-blocking": "^2.0.0",
+        "string-width": "^4.2.0",
+        "which-module": "^2.0.0",
+        "y18n": "^4.0.0",
+        "yargs-parser": "^18.1.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/nyc/node_modules/yargs-parser": {
+      "version": "18.1.3",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+      "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+      "dev": true,
+      "dependencies": {
+        "camelcase": "^5.0.0",
+        "decamelize": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+      "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==",
+      "dev": true,
+      "dependencies": {
+        "copy-descriptor": "^0.1.0",
+        "define-property": "^0.2.5",
+        "kind-of": "^3.0.3"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.12.2",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
+      "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object-is": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
+      "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/object-visit": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+      "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object.assign": {
+      "version": "4.1.4",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
+      "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "has-symbols": "^1.0.3",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object.defaults": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
+      "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==",
+      "dev": true,
+      "dependencies": {
+        "array-each": "^1.0.1",
+        "array-slice": "^1.0.0",
+        "for-own": "^1.0.0",
+        "isobject": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object.map": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
+      "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==",
+      "dev": true,
+      "dependencies": {
+        "for-own": "^1.0.0",
+        "make-iterator": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object.pick": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+      "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object.reduce": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz",
+      "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==",
+      "dev": true,
+      "dependencies": {
+        "for-own": "^1.0.0",
+        "make-iterator": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dev": true,
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/optionator": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+      "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+      "dev": true,
+      "dependencies": {
+        "deep-is": "~0.1.3",
+        "fast-levenshtein": "~2.0.6",
+        "levn": "~0.3.0",
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2",
+        "word-wrap": "~1.2.3"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/optionator/node_modules/levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
+      "dev": true,
+      "dependencies": {
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/optionator/node_modules/prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/optionator/node_modules/type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
+      "dev": true,
+      "dependencies": {
+        "prelude-ls": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/ordered-read-streams": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz",
+      "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==",
+      "dev": true,
+      "dependencies": {
+        "readable-stream": "^2.0.1"
+      }
+    },
+    "node_modules/os-browserify": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+      "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==",
+      "dev": true
+    },
+    "node_modules/os-locale": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+      "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==",
+      "dev": true,
+      "dependencies": {
+        "lcid": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-map": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
+      "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
+      "dev": true,
+      "dependencies": {
+        "aggregate-error": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/package-hash": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz",
+      "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.15",
+        "hasha": "^5.0.0",
+        "lodash.flattendeep": "^4.4.0",
+        "release-zalgo": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pako": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+      "dev": true
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parents": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
+      "integrity": "sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==",
+      "dev": true,
+      "dependencies": {
+        "path-platform": "~0.11.15"
+      }
+    },
+    "node_modules/parse-asn1": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
+      "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
+      "dev": true,
+      "dependencies": {
+        "asn1.js": "^5.2.0",
+        "browserify-aes": "^1.0.0",
+        "evp_bytestokey": "^1.0.0",
+        "pbkdf2": "^3.0.3",
+        "safe-buffer": "^5.1.1"
+      }
+    },
+    "node_modules/parse-filepath": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
+      "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==",
+      "dev": true,
+      "dependencies": {
+        "is-absolute": "^1.0.0",
+        "map-cache": "^0.2.0",
+        "path-root": "^0.1.1"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/parse-node-version": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
+      "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/parse-passwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+      "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/pascalcase": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+      "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-browserify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
+      "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
+      "dev": true
+    },
+    "node_modules/path-dirname": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+      "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==",
+      "dev": true
+    },
+    "node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "dev": true
+    },
+    "node_modules/path-platform": {
+      "version": "0.11.15",
+      "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz",
+      "integrity": "sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/path-root": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
+      "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==",
+      "dev": true,
+      "dependencies": {
+        "path-root-regex": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-root-regex": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
+      "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pbkdf2": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
+      "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
+      "dev": true,
+      "dependencies": {
+        "create-hash": "^1.1.2",
+        "create-hmac": "^1.1.4",
+        "ripemd160": "^2.0.1",
+        "safe-buffer": "^5.0.1",
+        "sha.js": "^2.4.8"
+      },
+      "engines": {
+        "node": ">=0.12"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+      "dev": true
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pify": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/pinkie": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+      "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/pinkie-promise": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+      "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==",
+      "dev": true,
+      "dependencies": {
+        "pinkie": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/pkg-dir": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+      "dev": true,
+      "dependencies": {
+        "find-up": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/platform": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
+      "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==",
+      "dev": true
+    },
+    "node_modules/posix-character-classes": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+      "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "dev": true,
+      "dependencies": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/postcss/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/prelude-ls": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/pretty-hrtime": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
+      "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/process": {
+      "version": "0.11.10",
+      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+      "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "dev": true
+    },
+    "node_modules/process-on-spawn": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
+      "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==",
+      "dev": true,
+      "dependencies": {
+        "fromentries": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/public-encrypt": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
+      "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
+      "dev": true,
+      "dependencies": {
+        "bn.js": "^4.1.0",
+        "browserify-rsa": "^4.0.0",
+        "create-hash": "^1.1.0",
+        "parse-asn1": "^5.0.0",
+        "randombytes": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      }
+    },
+    "node_modules/public-encrypt/node_modules/bn.js": {
+      "version": "4.12.0",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+      "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+      "dev": true
+    },
+    "node_modules/pump": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+      "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+      "dev": true,
+      "dependencies": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "node_modules/pumpify": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+      "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+      "dev": true,
+      "dependencies": {
+        "duplexify": "^3.6.0",
+        "inherits": "^2.0.3",
+        "pump": "^2.0.0"
+      }
+    },
+    "node_modules/pumpify/node_modules/duplexify": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
+      "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
+      "dev": true,
+      "dependencies": {
+        "end-of-stream": "^1.0.0",
+        "inherits": "^2.0.1",
+        "readable-stream": "^2.0.0",
+        "stream-shift": "^1.0.0"
+      }
+    },
+    "node_modules/punycode": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+      "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
+      "dev": true
+    },
+    "node_modules/querystring": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+      "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==",
+      "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4.x"
+      }
+    },
+    "node_modules/querystring-es3": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+      "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4.x"
+      }
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/quick-lru": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
+      "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "node_modules/randomfill": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+      "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+      "dev": true,
+      "dependencies": {
+        "randombytes": "^2.0.5",
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "node_modules/read-only-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz",
+      "integrity": "sha512-3ALe0bjBVZtkdWKIcThYpQCLbBMd/+Tbh2CDSrAIDO3UsZ4Xs+tnyjv2MjCOMMgBG+AsUOeuP1cgtY1INISc8w==",
+      "dev": true,
+      "dependencies": {
+        "readable-stream": "^2.0.2"
+      }
+    },
+    "node_modules/read-pkg": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+      "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+      "dev": true,
+      "dependencies": {
+        "@types/normalize-package-data": "^2.4.0",
+        "normalize-package-data": "^2.5.0",
+        "parse-json": "^5.0.0",
+        "type-fest": "^0.6.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/read-pkg-up": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+      "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+      "dev": true,
+      "dependencies": {
+        "find-up": "^4.1.0",
+        "read-pkg": "^5.2.0",
+        "type-fest": "^0.8.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/read-pkg-up/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/read-pkg-up/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/read-pkg-up/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/read-pkg-up/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/read-pkg-up/node_modules/type-fest": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+      "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/read-pkg/node_modules/hosted-git-info": {
+      "version": "2.8.9",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+      "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+      "dev": true
+    },
+    "node_modules/read-pkg/node_modules/normalize-package-data": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+      "dev": true,
+      "dependencies": {
+        "hosted-git-info": "^2.1.4",
+        "resolve": "^1.10.0",
+        "semver": "2 || 3 || 4 || 5",
+        "validate-npm-package-license": "^3.0.1"
+      }
+    },
+    "node_modules/read-pkg/node_modules/semver": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver"
+      }
+    },
+    "node_modules/read-pkg/node_modules/type-fest": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+      "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/readable-stream": {
+      "version": "2.3.7",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+      "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+      "dev": true,
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "node_modules/readable-stream/node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+      "dev": true
+    },
+    "node_modules/readable-stream/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
+    },
+    "node_modules/readable-stream/node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+      "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.11",
+        "micromatch": "^3.1.10",
+        "readable-stream": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/readdirp/node_modules/define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/readdirp/node_modules/extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+      "dev": true,
+      "dependencies": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/readdirp/node_modules/is-accessor-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+      "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/readdirp/node_modules/is-data-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+      "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/readdirp/node_modules/is-descriptor": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+      "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+      "dev": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^1.0.0",
+        "is-data-descriptor": "^1.0.0",
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/readdirp/node_modules/is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/readdirp/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/readdirp/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/readdirp/node_modules/micromatch": {
+      "version": "3.1.10",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+      "dev": true,
+      "dependencies": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "braces": "^2.3.1",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "extglob": "^2.0.4",
+        "fragment-cache": "^0.2.1",
+        "kind-of": "^6.0.2",
+        "nanomatch": "^1.2.9",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rechoir": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+      "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
+      "dev": true,
+      "dependencies": {
+        "resolve": "^1.1.6"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/redent": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+      "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+      "dev": true,
+      "dependencies": {
+        "indent-string": "^4.0.0",
+        "strip-indent": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/reflect-metadata": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
+      "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
+      "dev": true
+    },
+    "node_modules/regex-not": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+      "dev": true,
+      "dependencies": {
+        "extend-shallow": "^3.0.2",
+        "safe-regex": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/regex-not/node_modules/extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+      "dev": true,
+      "dependencies": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/regex-not/node_modules/is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/regex-not/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/regexp.prototype.flags": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
+      "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3",
+        "functions-have-names": "^1.2.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/regexpp": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+      "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/mysticatea"
+      }
+    },
+    "node_modules/release-zalgo": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
+      "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==",
+      "dev": true,
+      "dependencies": {
+        "es6-error": "^4.0.1"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/remove-bom-buffer": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",
+      "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==",
+      "dev": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5",
+        "is-utf8": "^0.2.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/remove-bom-stream": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz",
+      "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==",
+      "dev": true,
+      "dependencies": {
+        "remove-bom-buffer": "^3.0.0",
+        "safe-buffer": "^5.1.0",
+        "through2": "^2.0.3"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==",
+      "dev": true
+    },
+    "node_modules/repeat-element": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
+      "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/replace-ext": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz",
+      "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/replace-homedir": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz",
+      "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==",
+      "dev": true,
+      "dependencies": {
+        "homedir-polyfill": "^1.0.1",
+        "is-absolute": "^1.0.0",
+        "remove-trailing-separator": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/require-main-filename": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+      "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==",
+      "dev": true
+    },
+    "node_modules/requizzle": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz",
+      "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.14"
+      }
+    },
+    "node_modules/resolve": {
+      "version": "1.22.1",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "dev": true,
+      "dependencies": {
+        "is-core-module": "^2.9.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/resolve-dir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+      "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==",
+      "dev": true,
+      "dependencies": {
+        "expand-tilde": "^2.0.0",
+        "global-modules": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/resolve-options": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz",
+      "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==",
+      "dev": true,
+      "dependencies": {
+        "value-or-function": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/resolve-url": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+      "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==",
+      "deprecated": "https://github.com/lydell/resolve-url#deprecated",
+      "dev": true
+    },
+    "node_modules/resumer": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz",
+      "integrity": "sha512-Fn9X8rX8yYF4m81rZCK/5VmrmsSbqS/i3rDLl6ZZHAXgC2nTAx3dhwG8q8odP/RmdLa2YrybDJaAMg+X1ajY3w==",
+      "dev": true,
+      "dependencies": {
+        "through": "~2.3.4"
+      }
+    },
+    "node_modules/ret": {
+      "version": "0.1.15",
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "dev": true,
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "dev": true,
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/ripemd160": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+      "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+      "dev": true,
+      "dependencies": {
+        "hash-base": "^3.0.0",
+        "inherits": "^2.0.1"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/safe-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+      "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==",
+      "dev": true,
+      "dependencies": {
+        "ret": "~0.1.10"
+      }
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
+    },
+    "node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/semver-greatest-satisfied-range": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz",
+      "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==",
+      "dev": true,
+      "dependencies": {
+        "sver-compat": "^1.5.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+      "dev": true
+    },
+    "node_modules/set-value": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+      "dev": true,
+      "dependencies": {
+        "extend-shallow": "^2.0.1",
+        "is-extendable": "^0.1.1",
+        "is-plain-object": "^2.0.3",
+        "split-string": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/set-value/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sha.js": {
+      "version": "2.4.11",
+      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+      "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.0.1"
+      },
+      "bin": {
+        "sha.js": "bin.js"
+      }
+    },
+    "node_modules/shasum-object": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz",
+      "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==",
+      "dev": true,
+      "dependencies": {
+        "fast-safe-stringify": "^2.0.7"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shell-quote": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz",
+      "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==",
+      "dev": true
+    },
+    "node_modules/side-channel": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.0",
+        "get-intrinsic": "^1.0.2",
+        "object-inspect": "^1.9.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/signal-exit": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+      "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+      "dev": true
+    },
+    "node_modules/simple-concat": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+      "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/snapdragon": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+      "dev": true,
+      "dependencies": {
+        "base": "^0.11.1",
+        "debug": "^2.2.0",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "map-cache": "^0.2.2",
+        "source-map": "^0.5.6",
+        "source-map-resolve": "^0.5.0",
+        "use": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-node": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+      "dev": true,
+      "dependencies": {
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.0",
+        "snapdragon-util": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-node/node_modules/define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+      "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+      "dev": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+      "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-node/node_modules/is-data-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+      "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-node/node_modules/is-descriptor": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+      "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+      "dev": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^1.0.0",
+        "is-data-descriptor": "^1.0.0",
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-node/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-util": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^3.2.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-util/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/snapdragon/node_modules/source-map-resolve": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+      "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+      "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated",
+      "dev": true,
+      "dependencies": {
+        "atob": "^2.1.2",
+        "decode-uri-component": "^0.2.0",
+        "resolve-url": "^0.2.1",
+        "source-map-url": "^0.4.0",
+        "urix": "^0.1.0"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+      "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-resolve": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz",
+      "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==",
+      "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated",
+      "dev": true,
+      "dependencies": {
+        "atob": "^2.1.2",
+        "decode-uri-component": "^0.2.0"
+      }
+    },
+    "node_modules/source-map-url": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
+      "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
+      "deprecated": "See https://github.com/lydell/source-map-url#deprecated",
+      "dev": true
+    },
+    "node_modules/sparkles": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz",
+      "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/spawn-wrap": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz",
+      "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==",
+      "dev": true,
+      "dependencies": {
+        "foreground-child": "^2.0.0",
+        "is-windows": "^1.0.2",
+        "make-dir": "^3.0.0",
+        "rimraf": "^3.0.0",
+        "signal-exit": "^3.0.2",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/spdx-correct": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
+      "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
+      "dev": true,
+      "dependencies": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "node_modules/spdx-exceptions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+      "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
+      "dev": true
+    },
+    "node_modules/spdx-expression-parse": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+      "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+      "dev": true,
+      "dependencies": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "node_modules/spdx-license-ids": {
+      "version": "3.0.12",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz",
+      "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==",
+      "dev": true
+    },
+    "node_modules/split-string": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+      "dev": true,
+      "dependencies": {
+        "extend-shallow": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/split-string/node_modules/extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+      "dev": true,
+      "dependencies": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/split-string/node_modules/is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/split-string/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/split2": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
+      "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==",
+      "dev": true,
+      "dependencies": {
+        "readable-stream": "^3.0.0"
+      }
+    },
+    "node_modules/split2/node_modules/readable-stream": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+      "dev": true
+    },
+    "node_modules/stack-trace": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+      "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/static-extend": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+      "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==",
+      "dev": true,
+      "dependencies": {
+        "define-property": "^0.2.5",
+        "object-copy": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/stream-browserify": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
+      "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "~2.0.4",
+        "readable-stream": "^3.5.0"
+      }
+    },
+    "node_modules/stream-browserify/node_modules/readable-stream": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/stream-combiner2": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz",
+      "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==",
+      "dev": true,
+      "dependencies": {
+        "duplexer2": "~0.1.0",
+        "readable-stream": "^2.0.2"
+      }
+    },
+    "node_modules/stream-exhaust": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz",
+      "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==",
+      "dev": true
+    },
+    "node_modules/stream-http": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz",
+      "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==",
+      "dev": true,
+      "dependencies": {
+        "builtin-status-codes": "^3.0.0",
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.6.0",
+        "xtend": "^4.0.2"
+      }
+    },
+    "node_modules/stream-http/node_modules/readable-stream": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/stream-shift": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
+      "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
+      "dev": true
+    },
+    "node_modules/stream-splicer": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz",
+      "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.1",
+        "readable-stream": "^2.0.2"
+      }
+    },
+    "node_modules/string_decoder": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+      "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==",
+      "dev": true,
+      "dependencies": {
+        "code-point-at": "^1.0.0",
+        "is-fullwidth-code-point": "^1.0.0",
+        "strip-ansi": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/string-width/node_modules/ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/string-width/node_modules/strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/string.prototype.trim": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.6.tgz",
+      "integrity": "sha512-8lMR2m+U0VJTPp6JjvJTtGyc4FIGq9CdRt7O9p6T0e6K4vjU+OP+SQJpbe/SBmRcCUIvNUnjsbmY6lnMp8MhsQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.19.5"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string.prototype.trimend": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
+      "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.19.5"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string.prototype.trimstart": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz",
+      "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.19.5"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-bom": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+      "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-bom-string": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
+      "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/strip-indent": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+      "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+      "dev": true,
+      "dependencies": {
+        "min-indent": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/strip-outer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
+      "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
+      "dev": true,
+      "dependencies": {
+        "escape-string-regexp": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/strip-outer/node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/subarg": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
+      "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==",
+      "dev": true,
+      "dependencies": {
+        "minimist": "^1.1.0"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/sver-compat": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz",
+      "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==",
+      "dev": true,
+      "dependencies": {
+        "es6-iterator": "^2.0.1",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "node_modules/syntax-error": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz",
+      "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==",
+      "dev": true,
+      "dependencies": {
+        "acorn-node": "^1.2.0"
+      }
+    },
+    "node_modules/tape": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/tape/-/tape-5.6.0.tgz",
+      "integrity": "sha512-LyM4uqbiTAqDgsHTY0r1LH66yE24P3SZaz5TL3mPUds0XCTFl/0AMUBrjgBjUclvbPTFB4IalXg0wFfbTuuu/Q==",
+      "dev": true,
+      "dependencies": {
+        "array.prototype.every": "^1.1.3",
+        "call-bind": "^1.0.2",
+        "deep-equal": "^2.0.5",
+        "defined": "^1.0.0",
+        "dotignore": "^0.1.2",
+        "for-each": "^0.3.3",
+        "get-package-type": "^0.1.0",
+        "glob": "^7.2.3",
+        "has": "^1.0.3",
+        "has-dynamic-import": "^2.0.1",
+        "inherits": "^2.0.4",
+        "is-regex": "^1.1.4",
+        "minimist": "^1.2.6",
+        "object-inspect": "^1.12.2",
+        "object-is": "^1.1.5",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.3",
+        "resolve": "^2.0.0-next.3",
+        "resumer": "^0.0.0",
+        "string.prototype.trim": "^1.2.6",
+        "through": "^2.3.8"
+      },
+      "bin": {
+        "tape": "bin/tape"
+      }
+    },
+    "node_modules/tape/node_modules/resolve": {
+      "version": "2.0.0-next.4",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
+      "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==",
+      "dev": true,
+      "dependencies": {
+        "is-core-module": "^2.9.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/ternary-stream": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-3.0.0.tgz",
+      "integrity": "sha512-oIzdi+UL/JdktkT+7KU5tSIQjj8pbShj3OASuvDEhm0NT5lppsm7aXWAmAq4/QMaBIyfuEcNLbAQA+HpaISobQ==",
+      "dev": true,
+      "dependencies": {
+        "duplexify": "^4.1.1",
+        "fork-stream": "^0.0.4",
+        "merge-stream": "^2.0.0",
+        "through2": "^3.0.1"
+      }
+    },
+    "node_modules/ternary-stream/node_modules/through2": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
+      "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.4",
+        "readable-stream": "2 || 3"
+      }
+    },
+    "node_modules/test-exclude": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+      "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+      "dev": true,
+      "dependencies": {
+        "@istanbuljs/schema": "^0.1.2",
+        "glob": "^7.1.4",
+        "minimatch": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+      "dev": true
+    },
+    "node_modules/through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+      "dev": true
+    },
+    "node_modules/through2": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+      "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+      "dev": true,
+      "dependencies": {
+        "readable-stream": "~2.3.6",
+        "xtend": "~4.0.1"
+      }
+    },
+    "node_modules/through2-filter": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz",
+      "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==",
+      "dev": true,
+      "dependencies": {
+        "through2": "~2.0.0",
+        "xtend": "~4.0.0"
+      }
+    },
+    "node_modules/time-stamp": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
+      "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/timers-browserify": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz",
+      "integrity": "sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q==",
+      "dev": true,
+      "dependencies": {
+        "process": "~0.11.0"
+      },
+      "engines": {
+        "node": ">=0.6.0"
+      }
+    },
+    "node_modules/timers-ext": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz",
+      "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==",
+      "dev": true,
+      "dependencies": {
+        "es5-ext": "~0.10.46",
+        "next-tick": "1"
+      }
+    },
+    "node_modules/to-absolute-glob": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
+      "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==",
+      "dev": true,
+      "dependencies": {
+        "is-absolute": "^1.0.0",
+        "is-negated-glob": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-fast-properties": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+      "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/to-object-path": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+      "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-object-path/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+      "dev": true,
+      "dependencies": {
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "regex-not": "^1.0.2",
+        "safe-regex": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+      "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
+      "dev": true,
+      "dependencies": {
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex/node_modules/define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex/node_modules/extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+      "dev": true,
+      "dependencies": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex/node_modules/is-accessor-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+      "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex/node_modules/is-data-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+      "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex/node_modules/is-descriptor": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+      "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+      "dev": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^1.0.0",
+        "is-data-descriptor": "^1.0.0",
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex/node_modules/is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex/node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-through": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz",
+      "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==",
+      "dev": true,
+      "dependencies": {
+        "through2": "^2.0.3"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/trim-newlines": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
+      "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/trim-repeated": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
+      "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==",
+      "dev": true,
+      "dependencies": {
+        "escape-string-regexp": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/trim-repeated/node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true
+    },
+    "node_modules/tslint": {
+      "version": "6.1.3",
+      "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
+      "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
+      "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.0.0",
+        "builtin-modules": "^1.1.1",
+        "chalk": "^2.3.0",
+        "commander": "^2.12.1",
+        "diff": "^4.0.1",
+        "glob": "^7.1.1",
+        "js-yaml": "^3.13.1",
+        "minimatch": "^3.0.4",
+        "mkdirp": "^0.5.3",
+        "resolve": "^1.3.2",
+        "semver": "^5.3.0",
+        "tslib": "^1.13.0",
+        "tsutils": "^2.29.0"
+      },
+      "bin": {
+        "tslint": "bin/tslint"
+      },
+      "engines": {
+        "node": ">=4.8.0"
+      },
+      "peerDependencies": {
+        "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev"
+      }
+    },
+    "node_modules/tslint/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/tslint/node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "node_modules/tslint/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/tslint/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/tslint/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+      "dev": true
+    },
+    "node_modules/tslint/node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/tslint/node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/tslint/node_modules/js-yaml": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/tslint/node_modules/mkdirp": {
+      "version": "0.5.6",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+      "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+      "dev": true,
+      "dependencies": {
+        "minimist": "^1.2.6"
+      },
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      }
+    },
+    "node_modules/tslint/node_modules/semver": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver"
+      }
+    },
+    "node_modules/tslint/node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/tsutils": {
+      "version": "2.29.0",
+      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
+      "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
+      "dev": true,
+      "dependencies": {
+        "tslib": "^1.8.1"
+      },
+      "peerDependencies": {
+        "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev"
+      }
+    },
+    "node_modules/tty-browserify": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz",
+      "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==",
+      "dev": true
+    },
+    "node_modules/type": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+      "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
+      "dev": true
+    },
+    "node_modules/type-check": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+      "dev": true,
+      "dependencies": {
+        "prelude-ls": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/type-fest": {
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+      "dev": true
+    },
+    "node_modules/typedarray-to-buffer": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+      "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+      "dev": true,
+      "dependencies": {
+        "is-typedarray": "^1.0.0"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "3.9.10",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz",
+      "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==",
+      "dev": true,
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=4.2.0"
+      }
+    },
+    "node_modules/uc.micro": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+      "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
+      "dev": true
+    },
+    "node_modules/uglify-js": {
+      "version": "3.17.0",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz",
+      "integrity": "sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg==",
+      "dev": true,
+      "bin": {
+        "uglifyjs": "bin/uglifyjs"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/umd": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz",
+      "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==",
+      "dev": true,
+      "bin": {
+        "umd": "bin/cli.js"
+      }
+    },
+    "node_modules/unbox-primitive": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
+      "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "has-bigints": "^1.0.2",
+        "has-symbols": "^1.0.3",
+        "which-boxed-primitive": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/unc-path-regex": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
+      "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/undeclared-identifiers": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz",
+      "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==",
+      "dev": true,
+      "dependencies": {
+        "acorn-node": "^1.3.0",
+        "dash-ast": "^1.0.0",
+        "get-assigned-identifiers": "^1.2.0",
+        "simple-concat": "^1.0.0",
+        "xtend": "^4.0.1"
+      },
+      "bin": {
+        "undeclared-identifiers": "bin.js"
+      }
+    },
+    "node_modules/underscore": {
+      "version": "1.13.4",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz",
+      "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==",
+      "dev": true
+    },
+    "node_modules/undertaker": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz",
+      "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==",
+      "dev": true,
+      "dependencies": {
+        "arr-flatten": "^1.0.1",
+        "arr-map": "^2.0.0",
+        "bach": "^1.0.0",
+        "collection-map": "^1.0.0",
+        "es6-weak-map": "^2.0.1",
+        "fast-levenshtein": "^1.0.0",
+        "last-run": "^1.1.0",
+        "object.defaults": "^1.0.0",
+        "object.reduce": "^1.0.0",
+        "undertaker-registry": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/undertaker-registry": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz",
+      "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/undertaker/node_modules/fast-levenshtein": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz",
+      "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==",
+      "dev": true
+    },
+    "node_modules/union-value": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+      "dev": true,
+      "dependencies": {
+        "arr-union": "^3.1.0",
+        "get-value": "^2.0.6",
+        "is-extendable": "^0.1.1",
+        "set-value": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unique-stream": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
+      "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==",
+      "dev": true,
+      "dependencies": {
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "through2-filter": "^3.0.0"
+      }
+    },
+    "node_modules/universalify": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
+    "node_modules/unset-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+      "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==",
+      "dev": true,
+      "dependencies": {
+        "has-value": "^0.3.1",
+        "isobject": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unset-value/node_modules/has-value": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+      "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==",
+      "dev": true,
+      "dependencies": {
+        "get-value": "^2.0.3",
+        "has-values": "^0.1.4",
+        "isobject": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unset-value/node_modules/has-value/node_modules/isobject": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+      "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==",
+      "dev": true,
+      "dependencies": {
+        "isarray": "1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unset-value/node_modules/has-values": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+      "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unset-value/node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+      "dev": true
+    },
+    "node_modules/upath": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+      "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+      "dev": true,
+      "engines": {
+        "node": ">=4",
+        "yarn": "*"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz",
+      "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        }
+      ],
+      "dependencies": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      },
+      "bin": {
+        "browserslist-lint": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/update-browserslist-db/node_modules/picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+      "dev": true
+    },
+    "node_modules/uri-js": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+      "dev": true,
+      "dependencies": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "node_modules/uri-js/node_modules/punycode": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/urix": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+      "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==",
+      "deprecated": "Please see https://github.com/lydell/urix#deprecated",
+      "dev": true
+    },
+    "node_modules/url": {
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+      "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==",
+      "dev": true,
+      "dependencies": {
+        "punycode": "1.3.2",
+        "querystring": "0.2.0"
+      }
+    },
+    "node_modules/url/node_modules/punycode": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+      "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==",
+      "dev": true
+    },
+    "node_modules/use": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/util": {
+      "version": "0.12.4",
+      "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz",
+      "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "is-arguments": "^1.0.4",
+        "is-generator-function": "^1.0.7",
+        "is-typed-array": "^1.1.3",
+        "safe-buffer": "^5.1.2",
+        "which-typed-array": "^1.1.2"
+      }
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+      "dev": true
+    },
+    "node_modules/uuid": {
+      "version": "8.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+      "dev": true,
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/v8-compile-cache": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
+      "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
+      "dev": true
+    },
+    "node_modules/v8flags": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz",
+      "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==",
+      "dev": true,
+      "dependencies": {
+        "homedir-polyfill": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "dev": true,
+      "dependencies": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
+    "node_modules/value-or-function": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
+      "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/vinyl": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz",
+      "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==",
+      "dev": true,
+      "dependencies": {
+        "clone": "^2.1.1",
+        "clone-buffer": "^1.0.0",
+        "clone-stats": "^1.0.0",
+        "cloneable-readable": "^1.0.0",
+        "remove-trailing-separator": "^1.0.1",
+        "replace-ext": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/vinyl-buffer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/vinyl-buffer/-/vinyl-buffer-1.0.1.tgz",
+      "integrity": "sha512-LRBE2/g3C1hSHL2k/FynSZcVTRhEw8sb08oKGt/0hukZXwrh2m8nfy+r5yLhGEk7eFFuclhyIuPct/Bxlxk6rg==",
+      "dev": true,
+      "dependencies": {
+        "bl": "^1.2.1",
+        "through2": "^2.0.3"
+      }
+    },
+    "node_modules/vinyl-fs": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz",
+      "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==",
+      "dev": true,
+      "dependencies": {
+        "fs-mkdirp-stream": "^1.0.0",
+        "glob-stream": "^6.1.0",
+        "graceful-fs": "^4.0.0",
+        "is-valid-glob": "^1.0.0",
+        "lazystream": "^1.0.0",
+        "lead": "^1.0.0",
+        "object.assign": "^4.0.4",
+        "pumpify": "^1.3.5",
+        "readable-stream": "^2.3.3",
+        "remove-bom-buffer": "^3.0.0",
+        "remove-bom-stream": "^1.2.0",
+        "resolve-options": "^1.1.0",
+        "through2": "^2.0.0",
+        "to-through": "^2.0.0",
+        "value-or-function": "^3.0.0",
+        "vinyl": "^2.0.0",
+        "vinyl-sourcemap": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/vinyl-source-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-2.0.0.tgz",
+      "integrity": "sha512-Y5f1wRGajOfYukhv8biIGA7iZiY8UOIc3zJ6zcUNIbRG1BVuXzBsfSfe7MUJTttVkuy64k/pGQtJdd/aIt+hbw==",
+      "dev": true,
+      "dependencies": {
+        "through2": "^2.0.3",
+        "vinyl": "^2.1.0"
+      }
+    },
+    "node_modules/vinyl-sourcemap": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz",
+      "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==",
+      "dev": true,
+      "dependencies": {
+        "append-buffer": "^1.0.2",
+        "convert-source-map": "^1.5.0",
+        "graceful-fs": "^4.1.6",
+        "normalize-path": "^2.1.1",
+        "now-and-later": "^2.0.0",
+        "remove-bom-buffer": "^3.0.0",
+        "vinyl": "^2.0.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/vinyl-sourcemap/node_modules/convert-source-map": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
+      "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "~5.1.1"
+      }
+    },
+    "node_modules/vinyl-sourcemap/node_modules/normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
+      "dev": true,
+      "dependencies": {
+        "remove-trailing-separator": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/vinyl-sourcemap/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
+    },
+    "node_modules/vinyl-sourcemaps-apply": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz",
+      "integrity": "sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==",
+      "dev": true,
+      "dependencies": {
+        "source-map": "^0.5.1"
+      }
+    },
+    "node_modules/vm-browserify": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
+      "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
+      "dev": true
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/which-boxed-primitive": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
+      "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
+      "dev": true,
+      "dependencies": {
+        "is-bigint": "^1.0.1",
+        "is-boolean-object": "^1.1.0",
+        "is-number-object": "^1.0.4",
+        "is-string": "^1.0.5",
+        "is-symbol": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-collection": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
+      "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==",
+      "dev": true,
+      "dependencies": {
+        "is-map": "^2.0.1",
+        "is-set": "^2.0.1",
+        "is-weakmap": "^2.0.1",
+        "is-weakset": "^2.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-module": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
+      "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==",
+      "dev": true
+    },
+    "node_modules/which-typed-array": {
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz",
+      "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==",
+      "dev": true,
+      "dependencies": {
+        "available-typed-arrays": "^1.0.5",
+        "call-bind": "^1.0.2",
+        "es-abstract": "^1.20.0",
+        "for-each": "^0.3.3",
+        "has-tostringtag": "^1.0.0",
+        "is-typed-array": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/word-wrap": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/wrap-ansi": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+      "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+      "dev": true
+    },
+    "node_modules/write-file-atomic": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+      "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+      "dev": true,
+      "dependencies": {
+        "imurmurhash": "^0.1.4",
+        "is-typedarray": "^1.0.0",
+        "signal-exit": "^3.0.2",
+        "typedarray-to-buffer": "^3.1.5"
+      }
+    },
+    "node_modules/xmlcreate": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz",
+      "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==",
+      "dev": true
+    },
+    "node_modules/xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4"
+      }
+    },
+    "node_modules/y18n": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz",
+      "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==",
+      "dev": true
+    },
+    "node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
+    "node_modules/yargs": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz",
+      "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==",
+      "dev": true,
+      "dependencies": {
+        "camelcase": "^3.0.0",
+        "cliui": "^3.2.0",
+        "decamelize": "^1.1.1",
+        "get-caller-file": "^1.0.1",
+        "os-locale": "^1.4.0",
+        "read-pkg-up": "^1.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^1.0.1",
+        "set-blocking": "^2.0.0",
+        "string-width": "^1.0.2",
+        "which-module": "^1.0.0",
+        "y18n": "^3.2.1",
+        "yargs-parser": "^5.0.1"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "20.2.9",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+      "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs/node_modules/camelcase": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+      "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/yargs/node_modules/find-up": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+      "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==",
+      "dev": true,
+      "dependencies": {
+        "path-exists": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/yargs/node_modules/hosted-git-info": {
+      "version": "2.8.9",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+      "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+      "dev": true
+    },
+    "node_modules/yargs/node_modules/normalize-package-data": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+      "dev": true,
+      "dependencies": {
+        "hosted-git-info": "^2.1.4",
+        "resolve": "^1.10.0",
+        "semver": "2 || 3 || 4 || 5",
+        "validate-npm-package-license": "^3.0.1"
+      }
+    },
+    "node_modules/yargs/node_modules/path-exists": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+      "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==",
+      "dev": true,
+      "dependencies": {
+        "pinkie-promise": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/yargs/node_modules/path-type": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+      "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.2",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/yargs/node_modules/read-pkg": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+      "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==",
+      "dev": true,
+      "dependencies": {
+        "load-json-file": "^1.0.0",
+        "normalize-package-data": "^2.3.2",
+        "path-type": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/yargs/node_modules/read-pkg-up": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+      "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==",
+      "dev": true,
+      "dependencies": {
+        "find-up": "^1.0.0",
+        "read-pkg": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/yargs/node_modules/semver": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver"
+      }
+    },
+    "node_modules/yargs/node_modules/yargs-parser": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz",
+      "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==",
+      "dev": true,
+      "dependencies": {
+        "camelcase": "^3.0.0",
+        "object.assign": "^4.1.0"
+      }
+    },
+    "node_modules/yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    }
+  },
+  "dependencies": {
+    "@ampproject/remapping": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
+      "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/gen-mapping": "^0.1.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      }
+    },
+    "@babel/code-frame": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+      "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+      "dev": true,
+      "requires": {
+        "@babel/highlight": "^7.18.6"
+      }
+    },
+    "@babel/compat-data": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.13.tgz",
+      "integrity": "sha512-5yUzC5LqyTFp2HLmDoxGQelcdYgSpP9xsnMWBphAscOdFrHSAVbLNzWiy32sVNDqJRDiJK6klfDnAgu6PAGSHw==",
+      "dev": true
+    },
+    "@babel/core": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.13.tgz",
+      "integrity": "sha512-ZisbOvRRusFktksHSG6pjj1CSvkPkcZq/KHD45LAkVP/oiHJkNBZWfpvlLmX8OtHDG8IuzsFlVRWo08w7Qxn0A==",
+      "dev": true,
+      "requires": {
+        "@ampproject/remapping": "^2.1.0",
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.18.13",
+        "@babel/helper-compilation-targets": "^7.18.9",
+        "@babel/helper-module-transforms": "^7.18.9",
+        "@babel/helpers": "^7.18.9",
+        "@babel/parser": "^7.18.13",
+        "@babel/template": "^7.18.10",
+        "@babel/traverse": "^7.18.13",
+        "@babel/types": "^7.18.13",
+        "convert-source-map": "^1.7.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.1",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "convert-source-map": {
+          "version": "1.8.0",
+          "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
+          "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.1"
+          }
+        },
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+          "dev": true
+        }
+      }
+    },
+    "@babel/generator": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.13.tgz",
+      "integrity": "sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.18.13",
+        "@jridgewell/gen-mapping": "^0.3.2",
+        "jsesc": "^2.5.1"
+      },
+      "dependencies": {
+        "@jridgewell/gen-mapping": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+          "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+          "dev": true,
+          "requires": {
+            "@jridgewell/set-array": "^1.0.1",
+            "@jridgewell/sourcemap-codec": "^1.4.10",
+            "@jridgewell/trace-mapping": "^0.3.9"
+          }
+        }
+      }
+    },
+    "@babel/helper-compilation-targets": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz",
+      "integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==",
+      "dev": true,
+      "requires": {
+        "@babel/compat-data": "^7.18.8",
+        "@babel/helper-validator-option": "^7.18.6",
+        "browserslist": "^4.20.2",
+        "semver": "^6.3.0"
+      }
+    },
+    "@babel/helper-environment-visitor": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
+      "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
+      "dev": true
+    },
+    "@babel/helper-function-name": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz",
+      "integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==",
+      "dev": true,
+      "requires": {
+        "@babel/template": "^7.18.6",
+        "@babel/types": "^7.18.9"
+      }
+    },
+    "@babel/helper-hoist-variables": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
+      "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.18.6"
+      }
+    },
+    "@babel/helper-module-imports": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
+      "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.18.6"
+      }
+    },
+    "@babel/helper-module-transforms": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz",
+      "integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-simple-access": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/helper-validator-identifier": "^7.18.6",
+        "@babel/template": "^7.18.6",
+        "@babel/traverse": "^7.18.9",
+        "@babel/types": "^7.18.9"
+      }
+    },
+    "@babel/helper-simple-access": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz",
+      "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.18.6"
+      }
+    },
+    "@babel/helper-split-export-declaration": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
+      "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.18.6"
+      }
+    },
+    "@babel/helper-string-parser": {
+      "version": "7.18.10",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz",
+      "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==",
+      "dev": true
+    },
+    "@babel/helper-validator-identifier": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz",
+      "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==",
+      "dev": true
+    },
+    "@babel/helper-validator-option": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
+      "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
+      "dev": true
+    },
+    "@babel/helpers": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz",
+      "integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==",
+      "dev": true,
+      "requires": {
+        "@babel/template": "^7.18.6",
+        "@babel/traverse": "^7.18.9",
+        "@babel/types": "^7.18.9"
+      }
+    },
+    "@babel/highlight": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+      "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-validator-identifier": "^7.18.6",
+        "chalk": "^2.0.0",
+        "js-tokens": "^4.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "color-convert": {
+          "version": "1.9.3",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+          "dev": true,
+          "requires": {
+            "color-name": "1.1.3"
+          }
+        },
+        "color-name": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+          "dev": true
+        },
+        "escape-string-regexp": {
+          "version": "1.0.5",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+          "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "@babel/parser": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.13.tgz",
+      "integrity": "sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==",
+      "dev": true
+    },
+    "@babel/template": {
+      "version": "7.18.10",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz",
+      "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.18.6",
+        "@babel/parser": "^7.18.10",
+        "@babel/types": "^7.18.10"
+      }
+    },
+    "@babel/traverse": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.13.tgz",
+      "integrity": "sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.18.13",
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-function-name": "^7.18.9",
+        "@babel/helper-hoist-variables": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/parser": "^7.18.13",
+        "@babel/types": "^7.18.13",
+        "debug": "^4.1.0",
+        "globals": "^11.1.0"
+      },
+      "dependencies": {
+        "globals": {
+          "version": "11.12.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+          "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+          "dev": true
+        }
+      }
+    },
+    "@babel/types": {
+      "version": "7.18.13",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.13.tgz",
+      "integrity": "sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-string-parser": "^7.18.10",
+        "@babel/helper-validator-identifier": "^7.18.6",
+        "to-fast-properties": "^2.0.0"
+      }
+    },
+    "@eslint/eslintrc": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
+      "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==",
+      "dev": true,
+      "requires": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^9.3.2",
+        "globals": "^13.15.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      }
+    },
+    "@gulp-sourcemaps/identity-map": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-2.0.1.tgz",
+      "integrity": "sha512-Tb+nSISZku+eQ4X1lAkevcQa+jknn/OVUgZ3XCxEKIsLsqYuPoJwJOPQeaOk75X3WPftb29GWY1eqE7GLsXb1Q==",
+      "dev": true,
+      "requires": {
+        "acorn": "^6.4.1",
+        "normalize-path": "^3.0.0",
+        "postcss": "^7.0.16",
+        "source-map": "^0.6.0",
+        "through2": "^3.0.1"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "6.4.2",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
+          "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
+          "dev": true
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        },
+        "through2": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
+          "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.4",
+            "readable-stream": "2 || 3"
+          }
+        }
+      }
+    },
+    "@gulp-sourcemaps/map-sources": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz",
+      "integrity": "sha512-o/EatdaGt8+x2qpb0vFLC/2Gug/xYPRXb6a+ET1wGYKozKN3krDWC/zZFZAtrzxJHuDL12mwdfEFKcKMNvc55A==",
+      "dev": true,
+      "requires": {
+        "normalize-path": "^2.0.1",
+        "through2": "^2.0.3"
+      },
+      "dependencies": {
+        "normalize-path": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+          "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
+          "dev": true,
+          "requires": {
+            "remove-trailing-separator": "^1.0.1"
+          }
+        }
+      }
+    },
+    "@humanwhocodes/config-array": {
+      "version": "0.10.4",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz",
+      "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==",
+      "dev": true,
+      "requires": {
+        "@humanwhocodes/object-schema": "^1.2.1",
+        "debug": "^4.1.1",
+        "minimatch": "^3.0.4"
+      }
+    },
+    "@humanwhocodes/gitignore-to-minimatch": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz",
+      "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==",
+      "dev": true
+    },
+    "@humanwhocodes/object-schema": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+      "dev": true
+    },
+    "@istanbuljs/load-nyc-config": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+      "dev": true,
+      "requires": {
+        "camelcase": "^5.3.1",
+        "find-up": "^4.1.0",
+        "get-package-type": "^0.1.0",
+        "js-yaml": "^3.13.1",
+        "resolve-from": "^5.0.0"
+      },
+      "dependencies": {
+        "argparse": {
+          "version": "1.0.10",
+          "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+          "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+          "dev": true,
+          "requires": {
+            "sprintf-js": "~1.0.2"
+          }
+        },
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "js-yaml": {
+          "version": "3.14.1",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+          "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+          "dev": true,
+          "requires": {
+            "argparse": "^1.0.7",
+            "esprima": "^4.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        },
+        "resolve-from": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+          "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+          "dev": true
+        }
+      }
+    },
+    "@istanbuljs/schema": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+      "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+      "dev": true
+    },
+    "@jridgewell/gen-mapping": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
+      "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/set-array": "^1.0.0",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      }
+    },
+    "@jridgewell/resolve-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "dev": true
+    },
+    "@jridgewell/set-array": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+      "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+      "dev": true
+    },
+    "@jridgewell/sourcemap-codec": {
+      "version": "1.4.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+      "dev": true
+    },
+    "@jridgewell/trace-mapping": {
+      "version": "0.3.15",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz",
+      "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/resolve-uri": "^3.0.3",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      }
+    },
+    "@jsdoc/salty": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.1.tgz",
+      "integrity": "sha512-JXwylDNSHa549N9uceDYu8D4GMXwSo3H8CCPYEQqxhhHpxD28+lRl2b3bS/caaPj5w1YD3SWtrficJNTnUjGpg==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.21"
+      }
+    },
+    "@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "requires": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      }
+    },
+    "@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true
+    },
+    "@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "requires": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      }
+    },
+    "@protobufjs/aspromise": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
+    },
+    "@protobufjs/base64": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
+    },
+    "@protobufjs/codegen": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
+    },
+    "@protobufjs/eventemitter": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
+    },
+    "@protobufjs/fetch": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+      "requires": {
+        "@protobufjs/aspromise": "^1.1.1",
+        "@protobufjs/inquire": "^1.1.0"
+      }
+    },
+    "@protobufjs/float": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
+    },
+    "@protobufjs/inquire": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
+    },
+    "@protobufjs/path": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
+    },
+    "@protobufjs/pool": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
+    },
+    "@protobufjs/utf8": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
+    },
+    "@types/linkify-it": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz",
+      "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==",
+      "dev": true
+    },
+    "@types/markdown-it": {
+      "version": "12.2.3",
+      "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz",
+      "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==",
+      "dev": true,
+      "requires": {
+        "@types/linkify-it": "*",
+        "@types/mdurl": "*"
+      }
+    },
+    "@types/mdurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz",
+      "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==",
+      "dev": true
+    },
+    "@types/minimist": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz",
+      "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==",
+      "dev": true
+    },
+    "@types/node": {
+      "version": "18.7.13",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.13.tgz",
+      "integrity": "sha512-46yIhxSe5xEaJZXWdIBP7GU4HDTG8/eo0qd9atdiL+lFpA03y8KS+lkTN834TWJj5767GbWv4n/P6efyTFt1Dw=="
+    },
+    "@types/normalize-package-data": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz",
+      "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==",
+      "dev": true
+    },
+    "acorn": {
+      "version": "7.4.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+      "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+      "dev": true
+    },
+    "acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "requires": {}
+    },
+    "acorn-node": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
+      "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
+      "dev": true,
+      "requires": {
+        "acorn": "^7.0.0",
+        "acorn-walk": "^7.0.0",
+        "xtend": "^4.0.2"
+      }
+    },
+    "acorn-walk": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
+      "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
+      "dev": true
+    },
+    "aggregate-error": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+      "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+      "dev": true,
+      "requires": {
+        "clean-stack": "^2.0.0",
+        "indent-string": "^4.0.0"
+      }
+    },
+    "ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
+      "requires": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      }
+    },
+    "ansi-colors": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
+      "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
+      "dev": true,
+      "requires": {
+        "ansi-wrap": "^0.1.0"
+      }
+    },
+    "ansi-gray": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz",
+      "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==",
+      "dev": true,
+      "requires": {
+        "ansi-wrap": "0.1.0"
+      }
+    },
+    "ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true
+    },
+    "ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "requires": {
+        "color-convert": "^2.0.1"
+      }
+    },
+    "ansi-wrap": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
+      "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==",
+      "dev": true
+    },
+    "anymatch": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+      "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+      "dev": true,
+      "requires": {
+        "micromatch": "^3.1.4",
+        "normalize-path": "^2.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+          "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.2",
+            "isobject": "^3.0.1"
+          }
+        },
+        "extend-shallow": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+          "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+          "dev": true,
+          "requires": {
+            "assign-symbols": "^1.0.0",
+            "is-extendable": "^1.0.1"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        },
+        "micromatch": {
+          "version": "3.1.10",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+          "dev": true,
+          "requires": {
+            "arr-diff": "^4.0.0",
+            "array-unique": "^0.3.2",
+            "braces": "^2.3.1",
+            "define-property": "^2.0.2",
+            "extend-shallow": "^3.0.2",
+            "extglob": "^2.0.4",
+            "fragment-cache": "^0.2.1",
+            "kind-of": "^6.0.2",
+            "nanomatch": "^1.2.9",
+            "object.pick": "^1.3.0",
+            "regex-not": "^1.0.0",
+            "snapdragon": "^0.8.1",
+            "to-regex": "^3.0.2"
+          }
+        },
+        "normalize-path": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+          "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
+          "dev": true,
+          "requires": {
+            "remove-trailing-separator": "^1.0.1"
+          }
+        }
+      }
+    },
+    "append-buffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz",
+      "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==",
+      "dev": true,
+      "requires": {
+        "buffer-equal": "^1.0.0"
+      }
+    },
+    "append-transform": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz",
+      "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==",
+      "dev": true,
+      "requires": {
+        "default-require-extensions": "^3.0.0"
+      }
+    },
+    "archy": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
+      "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==",
+      "dev": true
+    },
+    "argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
+    "arr-diff": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+      "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==",
+      "dev": true
+    },
+    "arr-filter": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz",
+      "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==",
+      "dev": true,
+      "requires": {
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+      "dev": true
+    },
+    "arr-map": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz",
+      "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==",
+      "dev": true,
+      "requires": {
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "arr-union": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+      "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
+      "dev": true
+    },
+    "array-each": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
+      "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==",
+      "dev": true
+    },
+    "array-initial": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz",
+      "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==",
+      "dev": true,
+      "requires": {
+        "array-slice": "^1.0.0",
+        "is-number": "^4.0.0"
+      },
+      "dependencies": {
+        "is-number": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+          "dev": true
+        }
+      }
+    },
+    "array-last": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz",
+      "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==",
+      "dev": true,
+      "requires": {
+        "is-number": "^4.0.0"
+      },
+      "dependencies": {
+        "is-number": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+          "dev": true
+        }
+      }
+    },
+    "array-slice": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
+      "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==",
+      "dev": true
+    },
+    "array-sort": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz",
+      "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==",
+      "dev": true,
+      "requires": {
+        "default-compare": "^1.0.0",
+        "get-value": "^2.0.6",
+        "kind-of": "^5.0.2"
+      }
+    },
+    "array-union": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "dev": true
+    },
+    "array-uniq": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+      "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==",
+      "dev": true
+    },
+    "array-unique": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+      "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==",
+      "dev": true
+    },
+    "array.prototype.every": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/array.prototype.every/-/array.prototype.every-1.1.3.tgz",
+      "integrity": "sha512-vWnriJI//SOMOWtXbU/VXhJ/InfnNHPF6BLKn5WfY8xXy+NWql0fUy20GO3sdqBhCAO+qw8S/E5nJiZX+QFdCA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.19.0",
+        "is-string": "^1.0.7"
+      }
+    },
+    "arrify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+      "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
+      "dev": true
+    },
+    "asn1.js": {
+      "version": "5.4.1",
+      "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
+      "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^4.0.0",
+        "inherits": "^2.0.1",
+        "minimalistic-assert": "^1.0.0",
+        "safer-buffer": "^2.1.0"
+      },
+      "dependencies": {
+        "bn.js": {
+          "version": "4.12.0",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+          "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+          "dev": true
+        }
+      }
+    },
+    "assert": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
+      "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
+      "dev": true,
+      "requires": {
+        "object-assign": "^4.1.1",
+        "util": "0.10.3"
+      },
+      "dependencies": {
+        "inherits": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+          "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==",
+          "dev": true
+        },
+        "util": {
+          "version": "0.10.3",
+          "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+          "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==",
+          "dev": true,
+          "requires": {
+            "inherits": "2.0.1"
+          }
+        }
+      }
+    },
+    "assign-symbols": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+      "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==",
+      "dev": true
+    },
+    "async": {
+      "version": "2.6.4",
+      "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
+      "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.14"
+      }
+    },
+    "async-done": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz",
+      "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.2",
+        "process-nextick-args": "^2.0.0",
+        "stream-exhaust": "^1.0.1"
+      }
+    },
+    "async-each": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+      "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
+      "dev": true
+    },
+    "async-settle": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz",
+      "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==",
+      "dev": true,
+      "requires": {
+        "async-done": "^1.2.2"
+      }
+    },
+    "atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "dev": true
+    },
+    "available-typed-arrays": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
+      "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
+      "dev": true
+    },
+    "bach": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz",
+      "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==",
+      "dev": true,
+      "requires": {
+        "arr-filter": "^1.1.1",
+        "arr-flatten": "^1.0.1",
+        "arr-map": "^2.0.0",
+        "array-each": "^1.0.0",
+        "array-initial": "^1.0.0",
+        "array-last": "^1.1.1",
+        "async-done": "^1.2.2",
+        "async-settle": "^1.0.0",
+        "now-and-later": "^2.0.0"
+      }
+    },
+    "balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true
+    },
+    "base": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+      "dev": true,
+      "requires": {
+        "cache-base": "^1.0.1",
+        "class-utils": "^0.3.5",
+        "component-emitter": "^1.2.1",
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.1",
+        "mixin-deep": "^1.2.0",
+        "pascalcase": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+      "dev": true
+    },
+    "benchmark": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz",
+      "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.4",
+        "platform": "^1.3.3"
+      }
+    },
+    "binary-extensions": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+      "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+      "dev": true
+    },
+    "bindings": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "file-uri-to-path": "1.0.0"
+      }
+    },
+    "bl": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz",
+      "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.3.5",
+        "safe-buffer": "^5.1.1"
+      }
+    },
+    "bluebird": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+      "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+      "dev": true
+    },
+    "bn.js": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+      "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
+      "dev": true
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "braces": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+      "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+      "dev": true,
+      "requires": {
+        "arr-flatten": "^1.1.0",
+        "array-unique": "^0.3.2",
+        "extend-shallow": "^2.0.1",
+        "fill-range": "^4.0.0",
+        "isobject": "^3.0.1",
+        "repeat-element": "^1.1.2",
+        "snapdragon": "^0.8.1",
+        "snapdragon-node": "^2.0.1",
+        "split-string": "^3.0.2",
+        "to-regex": "^3.0.1"
+      }
+    },
+    "brorand": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+      "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==",
+      "dev": true
+    },
+    "browser-pack": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz",
+      "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==",
+      "dev": true,
+      "requires": {
+        "combine-source-map": "~0.8.0",
+        "defined": "^1.0.0",
+        "JSONStream": "^1.0.3",
+        "safe-buffer": "^5.1.1",
+        "through2": "^2.0.0",
+        "umd": "^3.0.0"
+      }
+    },
+    "browser-resolve": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz",
+      "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==",
+      "dev": true,
+      "requires": {
+        "resolve": "^1.17.0"
+      }
+    },
+    "browser-unpack": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/browser-unpack/-/browser-unpack-1.4.2.tgz",
+      "integrity": "sha512-uHkiY4bmXjjBBWoKH1aRnEGTQxUUCCcVtoJfH9w1lmGGjETY4u93Zk+GRYkCE/SRMrdoMTINQ/1/manr/3aMVA==",
+      "dev": true,
+      "requires": {
+        "acorn-node": "^1.5.2",
+        "concat-stream": "^1.5.0",
+        "minimist": "^1.1.1"
+      }
+    },
+    "browserify": {
+      "version": "17.0.0",
+      "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.0.tgz",
+      "integrity": "sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w==",
+      "dev": true,
+      "requires": {
+        "assert": "^1.4.0",
+        "browser-pack": "^6.0.1",
+        "browser-resolve": "^2.0.0",
+        "browserify-zlib": "~0.2.0",
+        "buffer": "~5.2.1",
+        "cached-path-relative": "^1.0.0",
+        "concat-stream": "^1.6.0",
+        "console-browserify": "^1.1.0",
+        "constants-browserify": "~1.0.0",
+        "crypto-browserify": "^3.0.0",
+        "defined": "^1.0.0",
+        "deps-sort": "^2.0.1",
+        "domain-browser": "^1.2.0",
+        "duplexer2": "~0.1.2",
+        "events": "^3.0.0",
+        "glob": "^7.1.0",
+        "has": "^1.0.0",
+        "htmlescape": "^1.1.0",
+        "https-browserify": "^1.0.0",
+        "inherits": "~2.0.1",
+        "insert-module-globals": "^7.2.1",
+        "JSONStream": "^1.0.3",
+        "labeled-stream-splicer": "^2.0.0",
+        "mkdirp-classic": "^0.5.2",
+        "module-deps": "^6.2.3",
+        "os-browserify": "~0.3.0",
+        "parents": "^1.0.1",
+        "path-browserify": "^1.0.0",
+        "process": "~0.11.0",
+        "punycode": "^1.3.2",
+        "querystring-es3": "~0.2.0",
+        "read-only-stream": "^2.0.0",
+        "readable-stream": "^2.0.2",
+        "resolve": "^1.1.4",
+        "shasum-object": "^1.0.0",
+        "shell-quote": "^1.6.1",
+        "stream-browserify": "^3.0.0",
+        "stream-http": "^3.0.0",
+        "string_decoder": "^1.1.1",
+        "subarg": "^1.0.0",
+        "syntax-error": "^1.1.1",
+        "through2": "^2.0.0",
+        "timers-browserify": "^1.0.1",
+        "tty-browserify": "0.0.1",
+        "url": "~0.11.0",
+        "util": "~0.12.0",
+        "vm-browserify": "^1.0.0",
+        "xtend": "^4.0.0"
+      }
+    },
+    "browserify-aes": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+      "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+      "dev": true,
+      "requires": {
+        "buffer-xor": "^1.0.3",
+        "cipher-base": "^1.0.0",
+        "create-hash": "^1.1.0",
+        "evp_bytestokey": "^1.0.3",
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "browserify-cipher": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
+      "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
+      "dev": true,
+      "requires": {
+        "browserify-aes": "^1.0.4",
+        "browserify-des": "^1.0.0",
+        "evp_bytestokey": "^1.0.0"
+      }
+    },
+    "browserify-des": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
+      "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
+      "dev": true,
+      "requires": {
+        "cipher-base": "^1.0.1",
+        "des.js": "^1.0.0",
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      }
+    },
+    "browserify-rsa": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
+      "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^5.0.0",
+        "randombytes": "^2.0.1"
+      }
+    },
+    "browserify-sign": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
+      "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^5.1.1",
+        "browserify-rsa": "^4.0.1",
+        "create-hash": "^1.2.0",
+        "create-hmac": "^1.1.7",
+        "elliptic": "^6.5.3",
+        "inherits": "^2.0.4",
+        "parse-asn1": "^5.1.5",
+        "readable-stream": "^3.6.0",
+        "safe-buffer": "^5.2.0"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
+    "browserify-wrap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/browserify-wrap/-/browserify-wrap-1.0.2.tgz",
+      "integrity": "sha512-WzNdGOw6UzwTwupeBa8Og8RLt4izpal6ss9GqcqPue95qS+r4IHkn9qVnIYW5QNcQnyk3b1+36xFdFAbiKJ98g==",
+      "dev": true
+    },
+    "browserify-zlib": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+      "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+      "dev": true,
+      "requires": {
+        "pako": "~1.0.5"
+      }
+    },
+    "browserslist": {
+      "version": "4.21.3",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz",
+      "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==",
+      "dev": true,
+      "requires": {
+        "caniuse-lite": "^1.0.30001370",
+        "electron-to-chromium": "^1.4.202",
+        "node-releases": "^2.0.6",
+        "update-browserslist-db": "^1.0.5"
+      }
+    },
+    "buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz",
+      "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==",
+      "dev": true,
+      "requires": {
+        "base64-js": "^1.0.2",
+        "ieee754": "^1.1.4"
+      }
+    },
+    "buffer-equal": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz",
+      "integrity": "sha512-tcBWO2Dl4e7Asr9hTGcpVrCe+F7DubpmqWCTbj4FHLmjqO2hIaC383acQubWtRJhdceqs5uBHs6Es+Sk//RKiQ==",
+      "dev": true
+    },
+    "buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true
+    },
+    "buffer-xor": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+      "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==",
+      "dev": true
+    },
+    "builtin-modules": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+      "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==",
+      "dev": true
+    },
+    "builtin-status-codes": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+      "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==",
+      "dev": true
+    },
+    "bundle-collapser": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/bundle-collapser/-/bundle-collapser-1.4.0.tgz",
+      "integrity": "sha512-Gd3K3+3KI1Utuk+gwAvuOVOjT/2XLGL8tU6FwDKk04LlOZkYfT0pwQllsG1Dv8RRhgcjNxZSDmmSXb0AOkwSwg==",
+      "dev": true,
+      "requires": {
+        "browser-pack": "^6.0.2",
+        "browser-unpack": "^1.1.0",
+        "concat-stream": "^1.5.0",
+        "falafel": "^2.1.0",
+        "minimist": "^1.1.1",
+        "through2": "^2.0.0"
+      }
+    },
+    "cache-base": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+      "dev": true,
+      "requires": {
+        "collection-visit": "^1.0.0",
+        "component-emitter": "^1.2.1",
+        "get-value": "^2.0.6",
+        "has-value": "^1.0.0",
+        "isobject": "^3.0.1",
+        "set-value": "^2.0.0",
+        "to-object-path": "^0.3.0",
+        "union-value": "^1.0.0",
+        "unset-value": "^1.0.0"
+      }
+    },
+    "cached-path-relative": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.1.0.tgz",
+      "integrity": "sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA==",
+      "dev": true
+    },
+    "caching-transform": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
+      "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==",
+      "dev": true,
+      "requires": {
+        "hasha": "^5.0.0",
+        "make-dir": "^3.0.0",
+        "package-hash": "^4.0.0",
+        "write-file-atomic": "^3.0.0"
+      }
+    },
+    "call-bind": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1",
+        "get-intrinsic": "^1.0.2"
+      }
+    },
+    "callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true
+    },
+    "camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "dev": true
+    },
+    "camelcase-keys": {
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
+      "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
+      "dev": true,
+      "requires": {
+        "camelcase": "^5.3.1",
+        "map-obj": "^4.0.0",
+        "quick-lru": "^4.0.1"
+      }
+    },
+    "caniuse-lite": {
+      "version": "1.0.30001383",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001383.tgz",
+      "integrity": "sha512-swMpEoTp5vDoGBZsYZX7L7nXHe6dsHxi9o6/LKf/f0LukVtnrxly5GVb/fWdCDTqi/yw6Km6tiJ0pmBacm0gbg==",
+      "dev": true
+    },
+    "catharsis": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
+      "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.15"
+      }
+    },
+    "chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      }
+    },
+    "chokidar": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+      "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
+      "dev": true,
+      "requires": {
+        "anymatch": "^2.0.0",
+        "async-each": "^1.0.1",
+        "braces": "^2.3.2",
+        "fsevents": "^1.2.7",
+        "glob-parent": "^3.1.0",
+        "inherits": "^2.0.3",
+        "is-binary-path": "^1.0.0",
+        "is-glob": "^4.0.0",
+        "normalize-path": "^3.0.0",
+        "path-is-absolute": "^1.0.0",
+        "readdirp": "^2.2.1",
+        "upath": "^1.1.1"
+      },
+      "dependencies": {
+        "glob-parent": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+          "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
+          "dev": true,
+          "requires": {
+            "is-glob": "^3.1.0",
+            "path-dirname": "^1.0.0"
+          },
+          "dependencies": {
+            "is-glob": {
+              "version": "3.1.0",
+              "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+              "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
+              "dev": true,
+              "requires": {
+                "is-extglob": "^2.1.0"
+              }
+            }
+          }
+        }
+      }
+    },
+    "cipher-base": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+      "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "class-utils": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+      "dev": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "define-property": "^0.2.5",
+        "isobject": "^3.0.0",
+        "static-extend": "^0.1.1"
+      }
+    },
+    "clean-stack": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+      "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+      "dev": true
+    },
+    "cliui": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+      "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==",
+      "dev": true,
+      "requires": {
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1",
+        "wrap-ansi": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+          "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+          "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^2.0.0"
+          }
+        }
+      }
+    },
+    "clone": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+      "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
+      "dev": true
+    },
+    "clone-buffer": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
+      "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==",
+      "dev": true
+    },
+    "clone-stats": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
+      "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==",
+      "dev": true
+    },
+    "cloneable-readable": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz",
+      "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.1",
+        "process-nextick-args": "^2.0.0",
+        "readable-stream": "^2.3.5"
+      }
+    },
+    "code-point-at": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+      "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==",
+      "dev": true
+    },
+    "collection-map": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz",
+      "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==",
+      "dev": true,
+      "requires": {
+        "arr-map": "^2.0.2",
+        "for-own": "^1.0.0",
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "collection-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+      "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==",
+      "dev": true,
+      "requires": {
+        "map-visit": "^1.0.0",
+        "object-visit": "^1.0.0"
+      }
+    },
+    "color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "requires": {
+        "color-name": "~1.1.4"
+      }
+    },
+    "color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "color-support": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+      "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+      "dev": true
+    },
+    "combine-source-map": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz",
+      "integrity": "sha512-UlxQ9Vw0b/Bt/KYwCFqdEwsQ1eL8d1gibiFb7lxQJFdvTgc2hIZi6ugsg+kyhzhPV+QEpUiEIwInIAIrgoEkrg==",
+      "dev": true,
+      "requires": {
+        "convert-source-map": "~1.1.0",
+        "inline-source-map": "~0.6.0",
+        "lodash.memoize": "~3.0.3",
+        "source-map": "~0.5.3"
+      }
+    },
+    "commander": {
+      "version": "2.20.3",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+      "dev": true
+    },
+    "commondir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+      "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
+      "dev": true
+    },
+    "component-emitter": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+      "dev": true
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true
+    },
+    "concat-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.2.2",
+        "typedarray": "^0.0.6"
+      }
+    },
+    "concat-with-sourcemaps": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz",
+      "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==",
+      "dev": true,
+      "requires": {
+        "source-map": "^0.6.1"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "console-browserify": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
+      "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==",
+      "dev": true
+    },
+    "constants-browserify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+      "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==",
+      "dev": true
+    },
+    "convert-source-map": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
+      "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==",
+      "dev": true
+    },
+    "copy-descriptor": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+      "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==",
+      "dev": true
+    },
+    "copy-props": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz",
+      "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==",
+      "dev": true,
+      "requires": {
+        "each-props": "^1.3.2",
+        "is-plain-object": "^5.0.0"
+      }
+    },
+    "core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+      "dev": true
+    },
+    "create-ecdh": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
+      "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^4.1.0",
+        "elliptic": "^6.5.3"
+      },
+      "dependencies": {
+        "bn.js": {
+          "version": "4.12.0",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+          "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+          "dev": true
+        }
+      }
+    },
+    "create-hash": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+      "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+      "dev": true,
+      "requires": {
+        "cipher-base": "^1.0.1",
+        "inherits": "^2.0.1",
+        "md5.js": "^1.3.4",
+        "ripemd160": "^2.0.1",
+        "sha.js": "^2.4.0"
+      }
+    },
+    "create-hmac": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+      "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+      "dev": true,
+      "requires": {
+        "cipher-base": "^1.0.3",
+        "create-hash": "^1.1.0",
+        "inherits": "^2.0.1",
+        "ripemd160": "^2.0.0",
+        "safe-buffer": "^5.0.1",
+        "sha.js": "^2.4.8"
+      }
+    },
+    "cross-spawn": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+      "dev": true,
+      "requires": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      }
+    },
+    "crypto-browserify": {
+      "version": "3.12.0",
+      "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+      "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+      "dev": true,
+      "requires": {
+        "browserify-cipher": "^1.0.0",
+        "browserify-sign": "^4.0.0",
+        "create-ecdh": "^4.0.0",
+        "create-hash": "^1.1.0",
+        "create-hmac": "^1.1.0",
+        "diffie-hellman": "^5.0.0",
+        "inherits": "^2.0.1",
+        "pbkdf2": "^3.0.3",
+        "public-encrypt": "^4.0.0",
+        "randombytes": "^2.0.0",
+        "randomfill": "^1.0.3"
+      }
+    },
+    "css": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz",
+      "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.4",
+        "source-map": "^0.6.1",
+        "source-map-resolve": "^0.6.0"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "d": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+      "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+      "dev": true,
+      "requires": {
+        "es5-ext": "^0.10.50",
+        "type": "^1.0.1"
+      }
+    },
+    "dargs": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz",
+      "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==",
+      "dev": true
+    },
+    "dash-ast": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz",
+      "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==",
+      "dev": true
+    },
+    "debug": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+      "dev": true,
+      "requires": {
+        "ms": "2.1.2"
+      }
+    },
+    "debug-fabulous": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz",
+      "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==",
+      "dev": true,
+      "requires": {
+        "debug": "3.X",
+        "memoizee": "0.4.X",
+        "object-assign": "4.X"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        }
+      }
+    },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+      "dev": true
+    },
+    "decamelize-keys": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
+      "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==",
+      "dev": true,
+      "requires": {
+        "decamelize": "^1.1.0",
+        "map-obj": "^1.0.0"
+      },
+      "dependencies": {
+        "map-obj": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+          "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==",
+          "dev": true
+        }
+      }
+    },
+    "decode-uri-component": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
+      "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
+      "dev": true
+    },
+    "deep-equal": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz",
+      "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.0",
+        "es-get-iterator": "^1.1.1",
+        "get-intrinsic": "^1.0.1",
+        "is-arguments": "^1.0.4",
+        "is-date-object": "^1.0.2",
+        "is-regex": "^1.1.1",
+        "isarray": "^2.0.5",
+        "object-is": "^1.1.4",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.2",
+        "regexp.prototype.flags": "^1.3.0",
+        "side-channel": "^1.0.3",
+        "which-boxed-primitive": "^1.0.1",
+        "which-collection": "^1.0.1",
+        "which-typed-array": "^1.1.2"
+      }
+    },
+    "deep-is": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+      "dev": true
+    },
+    "default-compare": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz",
+      "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^5.0.2"
+      }
+    },
+    "default-require-extensions": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz",
+      "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==",
+      "dev": true,
+      "requires": {
+        "strip-bom": "^4.0.0"
+      }
+    },
+    "default-resolution": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz",
+      "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==",
+      "dev": true
+    },
+    "define-properties": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
+      "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
+      "dev": true,
+      "requires": {
+        "has-property-descriptors": "^1.0.0",
+        "object-keys": "^1.1.1"
+      }
+    },
+    "define-property": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+      "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+      "dev": true,
+      "requires": {
+        "is-descriptor": "^0.1.0"
+      }
+    },
+    "defined": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+      "integrity": "sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==",
+      "dev": true
+    },
+    "deps-sort": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz",
+      "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==",
+      "dev": true,
+      "requires": {
+        "JSONStream": "^1.0.3",
+        "shasum-object": "^1.0.0",
+        "subarg": "^1.0.0",
+        "through2": "^2.0.0"
+      }
+    },
+    "des.js": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
+      "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.1",
+        "minimalistic-assert": "^1.0.0"
+      }
+    },
+    "detect-file": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+      "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==",
+      "dev": true
+    },
+    "detect-newline": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
+      "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==",
+      "dev": true
+    },
+    "detective": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz",
+      "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==",
+      "dev": true,
+      "requires": {
+        "acorn-node": "^1.8.2",
+        "defined": "^1.0.0",
+        "minimist": "^1.2.6"
+      }
+    },
+    "diff": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+      "dev": true
+    },
+    "diffie-hellman": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+      "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^4.1.0",
+        "miller-rabin": "^4.0.0",
+        "randombytes": "^2.0.0"
+      },
+      "dependencies": {
+        "bn.js": {
+          "version": "4.12.0",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+          "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+          "dev": true
+        }
+      }
+    },
+    "dir-glob": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+      "dev": true,
+      "requires": {
+        "path-type": "^4.0.0"
+      }
+    },
+    "doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+      "dev": true,
+      "requires": {
+        "esutils": "^2.0.2"
+      }
+    },
+    "domain-browser": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
+      "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
+      "dev": true
+    },
+    "dotignore": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz",
+      "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==",
+      "dev": true,
+      "requires": {
+        "minimatch": "^3.0.4"
+      }
+    },
+    "duplexer2": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+      "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.0.2"
+      }
+    },
+    "duplexify": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz",
+      "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.4.1",
+        "inherits": "^2.0.3",
+        "readable-stream": "^3.1.1",
+        "stream-shift": "^1.0.0"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
+    "each-props": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz",
+      "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==",
+      "dev": true,
+      "requires": {
+        "is-plain-object": "^2.0.1",
+        "object.defaults": "^1.1.0"
+      },
+      "dependencies": {
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        }
+      }
+    },
+    "electron-to-chromium": {
+      "version": "1.4.232",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.232.tgz",
+      "integrity": "sha512-nd+FW8xHjM+PxNWG44nKnwHaBDdVpJUZuI2sS2JJPt/QpdombnmoCRWEEQNnzaktdIQhsNWdD+dlqxwO8Bn99g==",
+      "dev": true
+    },
+    "elliptic": {
+      "version": "6.5.4",
+      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
+      "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^4.11.9",
+        "brorand": "^1.1.0",
+        "hash.js": "^1.0.0",
+        "hmac-drbg": "^1.0.1",
+        "inherits": "^2.0.4",
+        "minimalistic-assert": "^1.0.1",
+        "minimalistic-crypto-utils": "^1.0.1"
+      },
+      "dependencies": {
+        "bn.js": {
+          "version": "4.12.0",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+          "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+          "dev": true
+        }
+      }
+    },
+    "email-addresses": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
+      "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==",
+      "dev": true
+    },
+    "emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+      "dev": true,
+      "requires": {
+        "once": "^1.4.0"
+      }
+    },
+    "entities": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+      "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+      "dev": true
+    },
+    "error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dev": true,
+      "requires": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "es-abstract": {
+      "version": "1.20.1",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz",
+      "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "es-to-primitive": "^1.2.1",
+        "function-bind": "^1.1.1",
+        "function.prototype.name": "^1.1.5",
+        "get-intrinsic": "^1.1.1",
+        "get-symbol-description": "^1.0.0",
+        "has": "^1.0.3",
+        "has-property-descriptors": "^1.0.0",
+        "has-symbols": "^1.0.3",
+        "internal-slot": "^1.0.3",
+        "is-callable": "^1.2.4",
+        "is-negative-zero": "^2.0.2",
+        "is-regex": "^1.1.4",
+        "is-shared-array-buffer": "^1.0.2",
+        "is-string": "^1.0.7",
+        "is-weakref": "^1.0.2",
+        "object-inspect": "^1.12.0",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.2",
+        "regexp.prototype.flags": "^1.4.3",
+        "string.prototype.trimend": "^1.0.5",
+        "string.prototype.trimstart": "^1.0.5",
+        "unbox-primitive": "^1.0.2"
+      }
+    },
+    "es-get-iterator": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz",
+      "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.0",
+        "has-symbols": "^1.0.1",
+        "is-arguments": "^1.1.0",
+        "is-map": "^2.0.2",
+        "is-set": "^2.0.2",
+        "is-string": "^1.0.5",
+        "isarray": "^2.0.5"
+      }
+    },
+    "es-to-primitive": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+      "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+      "dev": true,
+      "requires": {
+        "is-callable": "^1.1.4",
+        "is-date-object": "^1.0.1",
+        "is-symbol": "^1.0.2"
+      }
+    },
+    "es5-ext": {
+      "version": "0.10.62",
+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
+      "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+      "dev": true,
+      "requires": {
+        "es6-iterator": "^2.0.3",
+        "es6-symbol": "^3.1.3",
+        "next-tick": "^1.1.0"
+      }
+    },
+    "es6-error": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
+      "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
+      "dev": true
+    },
+    "es6-iterator": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+      "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+      "dev": true,
+      "requires": {
+        "d": "1",
+        "es5-ext": "^0.10.35",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "es6-symbol": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+      "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+      "dev": true,
+      "requires": {
+        "d": "^1.0.1",
+        "ext": "^1.1.2"
+      }
+    },
+    "es6-weak-map": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
+      "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
+      "dev": true,
+      "requires": {
+        "d": "1",
+        "es5-ext": "^0.10.46",
+        "es6-iterator": "^2.0.3",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "dev": true
+    },
+    "escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true
+    },
+    "escodegen": {
+      "version": "1.14.3",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
+      "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
+      "dev": true,
+      "requires": {
+        "esprima": "^4.0.1",
+        "estraverse": "^4.2.0",
+        "esutils": "^2.0.2",
+        "optionator": "^0.8.1",
+        "source-map": "~0.6.1"
+      },
+      "dependencies": {
+        "estraverse": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+          "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+          "dev": true
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "eslint": {
+      "version": "8.22.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz",
+      "integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==",
+      "dev": true,
+      "requires": {
+        "@eslint/eslintrc": "^1.3.0",
+        "@humanwhocodes/config-array": "^0.10.4",
+        "@humanwhocodes/gitignore-to-minimatch": "^1.0.2",
+        "ajv": "^6.10.0",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.2",
+        "debug": "^4.3.2",
+        "doctrine": "^3.0.0",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^7.1.1",
+        "eslint-utils": "^3.0.0",
+        "eslint-visitor-keys": "^3.3.0",
+        "espree": "^9.3.3",
+        "esquery": "^1.4.0",
+        "esutils": "^2.0.2",
+        "fast-deep-equal": "^3.1.3",
+        "file-entry-cache": "^6.0.1",
+        "find-up": "^5.0.0",
+        "functional-red-black-tree": "^1.0.1",
+        "glob-parent": "^6.0.1",
+        "globals": "^13.15.0",
+        "globby": "^11.1.0",
+        "grapheme-splitter": "^1.0.4",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.0.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "js-yaml": "^4.1.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.4.1",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.1",
+        "regexpp": "^3.2.0",
+        "strip-ansi": "^6.0.1",
+        "strip-json-comments": "^3.1.0",
+        "text-table": "^0.2.0",
+        "v8-compile-cache": "^2.0.3"
+      },
+      "dependencies": {
+        "optionator": {
+          "version": "0.9.1",
+          "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+          "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+          "dev": true,
+          "requires": {
+            "deep-is": "^0.1.3",
+            "fast-levenshtein": "^2.0.6",
+            "levn": "^0.4.1",
+            "prelude-ls": "^1.2.1",
+            "type-check": "^0.4.0",
+            "word-wrap": "^1.2.3"
+          }
+        }
+      }
+    },
+    "eslint-scope": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+      "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+      "dev": true,
+      "requires": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^5.2.0"
+      }
+    },
+    "eslint-utils": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+      "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+      "dev": true,
+      "requires": {
+        "eslint-visitor-keys": "^2.0.0"
+      },
+      "dependencies": {
+        "eslint-visitor-keys": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+          "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+          "dev": true
+        }
+      }
+    },
+    "eslint-visitor-keys": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+      "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+      "dev": true
+    },
+    "espree": {
+      "version": "9.4.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz",
+      "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==",
+      "dev": true,
+      "requires": {
+        "acorn": "^8.8.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.3.0"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "8.8.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
+          "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
+          "dev": true
+        }
+      }
+    },
+    "esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true
+    },
+    "esquery": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+      "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^5.1.0"
+      }
+    },
+    "esrecurse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^5.2.0"
+      }
+    },
+    "estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true
+    },
+    "esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true
+    },
+    "event-emitter": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+      "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
+      "dev": true,
+      "requires": {
+        "d": "1",
+        "es5-ext": "~0.10.14"
+      }
+    },
+    "events": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+      "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+      "dev": true
+    },
+    "evp_bytestokey": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+      "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+      "dev": true,
+      "requires": {
+        "md5.js": "^1.3.4",
+        "safe-buffer": "^5.1.1"
+      }
+    },
+    "expand-brackets": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+      "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==",
+      "dev": true,
+      "requires": {
+        "debug": "^2.3.3",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "posix-character-classes": "^0.1.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true
+        }
+      }
+    },
+    "expand-tilde": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+      "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1"
+      }
+    },
+    "ext": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz",
+      "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==",
+      "dev": true,
+      "requires": {
+        "type": "^2.5.0"
+      },
+      "dependencies": {
+        "type": {
+          "version": "2.7.2",
+          "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
+          "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==",
+          "dev": true
+        }
+      }
+    },
+    "extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true
+    },
+    "extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+      "dev": true,
+      "requires": {
+        "is-extendable": "^0.1.0"
+      }
+    },
+    "extglob": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+      "dev": true,
+      "requires": {
+        "array-unique": "^0.3.2",
+        "define-property": "^1.0.0",
+        "expand-brackets": "^2.1.4",
+        "extend-shallow": "^2.0.1",
+        "fragment-cache": "^0.2.1",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "falafel": {
+      "version": "2.2.5",
+      "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.2.5.tgz",
+      "integrity": "sha512-HuC1qF9iTnHDnML9YZAdCDQwT0yKl/U55K4XSUXqGAA2GLoafFgWRqdAbhWJxXaYD4pyoVxAJ8wH670jMpI9DQ==",
+      "dev": true,
+      "requires": {
+        "acorn": "^7.1.1",
+        "isarray": "^2.0.1"
+      }
+    },
+    "fancy-log": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz",
+      "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==",
+      "dev": true,
+      "requires": {
+        "ansi-gray": "^0.1.1",
+        "color-support": "^1.1.3",
+        "parse-node-version": "^1.0.0",
+        "time-stamp": "^1.0.0"
+      }
+    },
+    "fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true
+    },
+    "fast-glob": {
+      "version": "3.2.11",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
+      "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
+      "dev": true,
+      "requires": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      },
+      "dependencies": {
+        "glob-parent": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+          "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+          "dev": true,
+          "requires": {
+            "is-glob": "^4.0.1"
+          }
+        }
+      }
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true
+    },
+    "fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+      "dev": true
+    },
+    "fast-safe-stringify": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
+      "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
+      "dev": true
+    },
+    "fastq": {
+      "version": "1.13.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
+      "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
+      "dev": true,
+      "requires": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "file-entry-cache": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+      "dev": true,
+      "requires": {
+        "flat-cache": "^3.0.4"
+      }
+    },
+    "file-uri-to-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+      "dev": true,
+      "optional": true
+    },
+    "filename-reserved-regex": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
+      "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==",
+      "dev": true
+    },
+    "filenamify": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz",
+      "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==",
+      "dev": true,
+      "requires": {
+        "filename-reserved-regex": "^2.0.0",
+        "strip-outer": "^1.0.1",
+        "trim-repeated": "^1.0.0"
+      }
+    },
+    "fill-range": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+      "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^2.0.1",
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1",
+        "to-regex-range": "^2.1.0"
+      }
+    },
+    "find-cache-dir": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
+      "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
+      "dev": true,
+      "requires": {
+        "commondir": "^1.0.1",
+        "make-dir": "^3.0.2",
+        "pkg-dir": "^4.1.0"
+      }
+    },
+    "find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "requires": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      }
+    },
+    "findup-sync": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
+      "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==",
+      "dev": true,
+      "requires": {
+        "detect-file": "^1.0.0",
+        "is-glob": "^4.0.0",
+        "micromatch": "^3.0.4",
+        "resolve-dir": "^1.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+          "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.2",
+            "isobject": "^3.0.1"
+          }
+        },
+        "extend-shallow": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+          "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+          "dev": true,
+          "requires": {
+            "assign-symbols": "^1.0.0",
+            "is-extendable": "^1.0.1"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        },
+        "micromatch": {
+          "version": "3.1.10",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+          "dev": true,
+          "requires": {
+            "arr-diff": "^4.0.0",
+            "array-unique": "^0.3.2",
+            "braces": "^2.3.1",
+            "define-property": "^2.0.2",
+            "extend-shallow": "^3.0.2",
+            "extglob": "^2.0.4",
+            "fragment-cache": "^0.2.1",
+            "kind-of": "^6.0.2",
+            "nanomatch": "^1.2.9",
+            "object.pick": "^1.3.0",
+            "regex-not": "^1.0.0",
+            "snapdragon": "^0.8.1",
+            "to-regex": "^3.0.2"
+          }
+        }
+      }
+    },
+    "fined": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz",
+      "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.2",
+        "is-plain-object": "^2.0.3",
+        "object.defaults": "^1.1.0",
+        "object.pick": "^1.2.0",
+        "parse-filepath": "^1.0.1"
+      },
+      "dependencies": {
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        }
+      }
+    },
+    "flagged-respawn": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz",
+      "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==",
+      "dev": true
+    },
+    "flat-cache": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+      "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+      "dev": true,
+      "requires": {
+        "flatted": "^3.1.0",
+        "rimraf": "^3.0.2"
+      }
+    },
+    "flatted": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+      "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+      "dev": true
+    },
+    "flush-write-stream": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
+      "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.3.6"
+      }
+    },
+    "for-each": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+      "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+      "dev": true,
+      "requires": {
+        "is-callable": "^1.1.3"
+      }
+    },
+    "for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==",
+      "dev": true
+    },
+    "for-own": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+      "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==",
+      "dev": true,
+      "requires": {
+        "for-in": "^1.0.1"
+      }
+    },
+    "foreground-child": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
+      "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
+      "dev": true,
+      "requires": {
+        "cross-spawn": "^7.0.0",
+        "signal-exit": "^3.0.2"
+      }
+    },
+    "fork-stream": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz",
+      "integrity": "sha512-Pqq5NnT78ehvUnAk/We/Jr22vSvanRlFTpAmQ88xBY/M1TlHe+P0ILuEyXS595ysdGfaj22634LBkGMA2GTcpA==",
+      "dev": true
+    },
+    "fragment-cache": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+      "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==",
+      "dev": true,
+      "requires": {
+        "map-cache": "^0.2.2"
+      }
+    },
+    "fromentries": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz",
+      "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==",
+      "dev": true
+    },
+    "fs-extra": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+      "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
+      }
+    },
+    "fs-mkdirp-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz",
+      "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.11",
+        "through2": "^2.0.3"
+      }
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+      "dev": true
+    },
+    "fsevents": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+      "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "bindings": "^1.5.0",
+        "nan": "^2.12.1"
+      }
+    },
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
+    },
+    "function.prototype.name": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
+      "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.19.0",
+        "functions-have-names": "^1.2.2"
+      }
+    },
+    "functional-red-black-tree": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+      "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
+      "dev": true
+    },
+    "functions-have-names": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+      "dev": true
+    },
+    "gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "dev": true
+    },
+    "get-assigned-identifiers": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz",
+      "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==",
+      "dev": true
+    },
+    "get-caller-file": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+      "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
+      "dev": true
+    },
+    "get-intrinsic": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz",
+      "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1",
+        "has": "^1.0.3",
+        "has-symbols": "^1.0.3"
+      }
+    },
+    "get-package-type": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+      "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+      "dev": true
+    },
+    "get-symbol-description": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
+      "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.1"
+      }
+    },
+    "get-value": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+      "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==",
+      "dev": true
+    },
+    "gh-pages": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-4.0.0.tgz",
+      "integrity": "sha512-p8S0T3aGJc68MtwOcZusul5qPSNZCalap3NWbhRUZYu1YOdp+EjZ+4kPmRM8h3NNRdqw00yuevRjlkuSzCn7iQ==",
+      "dev": true,
+      "requires": {
+        "async": "^2.6.1",
+        "commander": "^2.18.0",
+        "email-addresses": "^3.0.1",
+        "filenamify": "^4.3.0",
+        "find-cache-dir": "^3.3.1",
+        "fs-extra": "^8.1.0",
+        "globby": "^6.1.0"
+      },
+      "dependencies": {
+        "array-union": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+          "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
+          "dev": true,
+          "requires": {
+            "array-uniq": "^1.0.1"
+          }
+        },
+        "globby": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+          "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==",
+          "dev": true,
+          "requires": {
+            "array-union": "^1.0.1",
+            "glob": "^7.0.3",
+            "object-assign": "^4.0.1",
+            "pify": "^2.0.0",
+            "pinkie-promise": "^2.0.0"
+          }
+        }
+      }
+    },
+    "git-raw-commits": {
+      "version": "2.0.11",
+      "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz",
+      "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==",
+      "dev": true,
+      "requires": {
+        "dargs": "^7.0.0",
+        "lodash": "^4.17.15",
+        "meow": "^8.0.0",
+        "split2": "^3.0.0",
+        "through2": "^4.0.0"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        },
+        "through2": {
+          "version": "4.0.2",
+          "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz",
+          "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==",
+          "dev": true,
+          "requires": {
+            "readable-stream": "3"
+          }
+        }
+      }
+    },
+    "git-semver-tags": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz",
+      "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==",
+      "dev": true,
+      "requires": {
+        "meow": "^8.0.0",
+        "semver": "^6.0.0"
+      }
+    },
+    "glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dev": true,
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dev": true,
+      "requires": {
+        "is-glob": "^4.0.3"
+      }
+    },
+    "glob-stream": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz",
+      "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==",
+      "dev": true,
+      "requires": {
+        "extend": "^3.0.0",
+        "glob": "^7.1.1",
+        "glob-parent": "^3.1.0",
+        "is-negated-glob": "^1.0.0",
+        "ordered-read-streams": "^1.0.0",
+        "pumpify": "^1.3.5",
+        "readable-stream": "^2.1.5",
+        "remove-trailing-separator": "^1.0.1",
+        "to-absolute-glob": "^2.0.0",
+        "unique-stream": "^2.0.2"
+      },
+      "dependencies": {
+        "glob-parent": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+          "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
+          "dev": true,
+          "requires": {
+            "is-glob": "^3.1.0",
+            "path-dirname": "^1.0.0"
+          }
+        },
+        "is-glob": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+          "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^2.1.0"
+          }
+        }
+      }
+    },
+    "glob-watcher": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz",
+      "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==",
+      "dev": true,
+      "requires": {
+        "anymatch": "^2.0.0",
+        "async-done": "^1.2.0",
+        "chokidar": "^2.0.0",
+        "is-negated-glob": "^1.0.0",
+        "just-debounce": "^1.0.0",
+        "normalize-path": "^3.0.0",
+        "object.defaults": "^1.1.0"
+      }
+    },
+    "global-modules": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+      "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+      "dev": true,
+      "requires": {
+        "global-prefix": "^1.0.1",
+        "is-windows": "^1.0.1",
+        "resolve-dir": "^1.0.0"
+      }
+    },
+    "global-prefix": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+      "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.2",
+        "homedir-polyfill": "^1.0.1",
+        "ini": "^1.3.4",
+        "is-windows": "^1.0.1",
+        "which": "^1.2.14"
+      },
+      "dependencies": {
+        "which": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+          "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+          "dev": true,
+          "requires": {
+            "isexe": "^2.0.0"
+          }
+        }
+      }
+    },
+    "globals": {
+      "version": "13.17.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
+      "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
+      "dev": true,
+      "requires": {
+        "type-fest": "^0.20.2"
+      }
+    },
+    "globby": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+      "dev": true,
+      "requires": {
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^3.0.0"
+      }
+    },
+    "glogg": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz",
+      "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==",
+      "dev": true,
+      "requires": {
+        "sparkles": "^1.0.0"
+      }
+    },
+    "google-protobuf": {
+      "version": "3.21.0",
+      "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.0.tgz",
+      "integrity": "sha512-byR7MBTK4tZ5PZEb+u5ZTzpt4SfrTxv5682MjPlHN16XeqgZE2/8HOIWeiXe8JKnT9OVbtBGhbq8mtvkK8cd5g==",
+      "dev": true
+    },
+    "graceful-fs": {
+      "version": "4.2.10",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+      "dev": true
+    },
+    "grapheme-splitter": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+      "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+      "dev": true
+    },
+    "gulp": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz",
+      "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==",
+      "dev": true,
+      "requires": {
+        "glob-watcher": "^5.0.3",
+        "gulp-cli": "^2.2.0",
+        "undertaker": "^1.2.1",
+        "vinyl-fs": "^3.0.0"
+      }
+    },
+    "gulp-cli": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz",
+      "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==",
+      "dev": true,
+      "requires": {
+        "ansi-colors": "^1.0.1",
+        "archy": "^1.0.0",
+        "array-sort": "^1.0.0",
+        "color-support": "^1.1.3",
+        "concat-stream": "^1.6.0",
+        "copy-props": "^2.0.1",
+        "fancy-log": "^1.3.2",
+        "gulplog": "^1.0.0",
+        "interpret": "^1.4.0",
+        "isobject": "^3.0.1",
+        "liftoff": "^3.1.0",
+        "matchdep": "^2.0.0",
+        "mute-stdout": "^1.0.0",
+        "pretty-hrtime": "^1.0.0",
+        "replace-homedir": "^1.0.0",
+        "semver-greatest-satisfied-range": "^1.1.0",
+        "v8flags": "^3.2.0",
+        "yargs": "^7.1.0"
+      }
+    },
+    "gulp-header": {
+      "version": "2.0.9",
+      "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-2.0.9.tgz",
+      "integrity": "sha512-LMGiBx+qH8giwrOuuZXSGvswcIUh0OiioNkUpLhNyvaC6/Ga8X6cfAeme2L5PqsbXMhL8o8b/OmVqIQdxprhcQ==",
+      "dev": true,
+      "requires": {
+        "concat-with-sourcemaps": "^1.1.0",
+        "lodash.template": "^4.5.0",
+        "map-stream": "0.0.7",
+        "through2": "^2.0.0"
+      }
+    },
+    "gulp-if": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/gulp-if/-/gulp-if-3.0.0.tgz",
+      "integrity": "sha512-fCUEngzNiEZEK2YuPm+sdMpO6ukb8+/qzbGfJBXyNOXz85bCG7yBI+pPSl+N90d7gnLvMsarthsAImx0qy7BAw==",
+      "dev": true,
+      "requires": {
+        "gulp-match": "^1.1.0",
+        "ternary-stream": "^3.0.0",
+        "through2": "^3.0.1"
+      },
+      "dependencies": {
+        "through2": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
+          "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.4",
+            "readable-stream": "2 || 3"
+          }
+        }
+      }
+    },
+    "gulp-match": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/gulp-match/-/gulp-match-1.1.0.tgz",
+      "integrity": "sha512-DlyVxa1Gj24DitY2OjEsS+X6tDpretuxD6wTfhXE/Rw2hweqc1f6D/XtsJmoiCwLWfXgR87W9ozEityPCVzGtQ==",
+      "dev": true,
+      "requires": {
+        "minimatch": "^3.0.3"
+      }
+    },
+    "gulp-sourcemaps": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-3.0.0.tgz",
+      "integrity": "sha512-RqvUckJkuYqy4VaIH60RMal4ZtG0IbQ6PXMNkNsshEGJ9cldUPRb/YCgboYae+CLAs1HQNb4ADTKCx65HInquQ==",
+      "dev": true,
+      "requires": {
+        "@gulp-sourcemaps/identity-map": "^2.0.1",
+        "@gulp-sourcemaps/map-sources": "^1.0.0",
+        "acorn": "^6.4.1",
+        "convert-source-map": "^1.0.0",
+        "css": "^3.0.0",
+        "debug-fabulous": "^1.0.0",
+        "detect-newline": "^2.0.0",
+        "graceful-fs": "^4.0.0",
+        "source-map": "^0.6.0",
+        "strip-bom-string": "^1.0.0",
+        "through2": "^2.0.0"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "6.4.2",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
+          "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
+          "dev": true
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "gulp-uglify": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.2.tgz",
+      "integrity": "sha512-gk1dhB74AkV2kzqPMQBLA3jPoIAPd/nlNzP2XMDSG8XZrqnlCiDGAqC+rZOumzFvB5zOphlFh6yr3lgcAb/OOg==",
+      "dev": true,
+      "requires": {
+        "array-each": "^1.0.1",
+        "extend-shallow": "^3.0.2",
+        "gulplog": "^1.0.0",
+        "has-gulplog": "^0.1.0",
+        "isobject": "^3.0.1",
+        "make-error-cause": "^1.1.1",
+        "safe-buffer": "^5.1.2",
+        "through2": "^2.0.0",
+        "uglify-js": "^3.0.5",
+        "vinyl-sourcemaps-apply": "^0.2.0"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+          "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+          "dev": true,
+          "requires": {
+            "assign-symbols": "^1.0.0",
+            "is-extendable": "^1.0.1"
+          }
+        },
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        }
+      }
+    },
+    "gulplog": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
+      "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==",
+      "dev": true,
+      "requires": {
+        "glogg": "^1.0.0"
+      }
+    },
+    "hard-rejection": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
+      "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
+      "dev": true
+    },
+    "has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1"
+      }
+    },
+    "has-bigints": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
+      "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
+      "dev": true
+    },
+    "has-dynamic-import": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/has-dynamic-import/-/has-dynamic-import-2.0.1.tgz",
+      "integrity": "sha512-X3fbtsZmwb6W7fJGR9o7x65fZoodygCrZ3TVycvghP62yYQfS0t4RS0Qcz+j5tQYUKeSWS09tHkWW6WhFV3XhQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.1"
+      }
+    },
+    "has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true
+    },
+    "has-gulplog": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
+      "integrity": "sha512-+F4GzLjwHNNDEAJW2DC1xXfEoPkRDmUdJ7CBYw4MpqtDwOnqdImJl7GWlpqx+Wko6//J8uKTnIe4wZSv7yCqmw==",
+      "dev": true,
+      "requires": {
+        "sparkles": "^1.0.0"
+      }
+    },
+    "has-property-descriptors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
+      "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
+      "dev": true,
+      "requires": {
+        "get-intrinsic": "^1.1.1"
+      }
+    },
+    "has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "dev": true
+    },
+    "has-tostringtag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
+      "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
+      "dev": true,
+      "requires": {
+        "has-symbols": "^1.0.2"
+      }
+    },
+    "has-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+      "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==",
+      "dev": true,
+      "requires": {
+        "get-value": "^2.0.6",
+        "has-values": "^1.0.0",
+        "isobject": "^3.0.0"
+      }
+    },
+    "has-values": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+      "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==",
+      "dev": true,
+      "requires": {
+        "is-number": "^3.0.0",
+        "kind-of": "^4.0.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+          "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "hash-base": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+      "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.6.0",
+        "safe-buffer": "^5.2.0"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
+    "hash.js": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+      "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.3",
+        "minimalistic-assert": "^1.0.1"
+      }
+    },
+    "hasha": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz",
+      "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==",
+      "dev": true,
+      "requires": {
+        "is-stream": "^2.0.0",
+        "type-fest": "^0.8.0"
+      },
+      "dependencies": {
+        "type-fest": {
+          "version": "0.8.1",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+          "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+          "dev": true
+        }
+      }
+    },
+    "hmac-drbg": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+      "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==",
+      "dev": true,
+      "requires": {
+        "hash.js": "^1.0.3",
+        "minimalistic-assert": "^1.0.0",
+        "minimalistic-crypto-utils": "^1.0.1"
+      }
+    },
+    "homedir-polyfill": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+      "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+      "dev": true,
+      "requires": {
+        "parse-passwd": "^1.0.0"
+      }
+    },
+    "hosted-git-info": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+      "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+      "dev": true,
+      "requires": {
+        "lru-cache": "^6.0.0"
+      }
+    },
+    "html-escaper": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+      "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+      "dev": true
+    },
+    "htmlescape": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz",
+      "integrity": "sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==",
+      "dev": true
+    },
+    "https-browserify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+      "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==",
+      "dev": true
+    },
+    "ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "dev": true
+    },
+    "ignore": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
+      "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
+      "dev": true
+    },
+    "import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dev": true,
+      "requires": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      }
+    },
+    "imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+      "dev": true
+    },
+    "indent-string": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+      "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+      "dev": true
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "dev": true,
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true
+    },
+    "ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+      "dev": true
+    },
+    "inline-source-map": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz",
+      "integrity": "sha512-0mVWSSbNDvedDWIN4wxLsdPM4a7cIPcpyMxj3QZ406QRwQ6ePGB1YIHxVPjqpcUGbWQ5C+nHTwGNWAGvt7ggVA==",
+      "dev": true,
+      "requires": {
+        "source-map": "~0.5.3"
+      }
+    },
+    "insert-module-globals": {
+      "version": "7.2.1",
+      "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.1.tgz",
+      "integrity": "sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==",
+      "dev": true,
+      "requires": {
+        "acorn-node": "^1.5.2",
+        "combine-source-map": "^0.8.0",
+        "concat-stream": "^1.6.1",
+        "is-buffer": "^1.1.0",
+        "JSONStream": "^1.0.3",
+        "path-is-absolute": "^1.0.1",
+        "process": "~0.11.0",
+        "through2": "^2.0.0",
+        "undeclared-identifiers": "^1.1.2",
+        "xtend": "^4.0.0"
+      }
+    },
+    "internal-slot": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
+      "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
+      "dev": true,
+      "requires": {
+        "get-intrinsic": "^1.1.0",
+        "has": "^1.0.3",
+        "side-channel": "^1.0.4"
+      }
+    },
+    "interpret": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
+      "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
+      "dev": true
+    },
+    "invert-kv": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+      "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==",
+      "dev": true
+    },
+    "is-absolute": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+      "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
+      "dev": true,
+      "requires": {
+        "is-relative": "^1.0.0",
+        "is-windows": "^1.0.1"
+      }
+    },
+    "is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-arguments": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
+      "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+      "dev": true
+    },
+    "is-bigint": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
+      "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
+      "dev": true,
+      "requires": {
+        "has-bigints": "^1.0.1"
+      }
+    },
+    "is-binary-path": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+      "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==",
+      "dev": true,
+      "requires": {
+        "binary-extensions": "^1.0.0"
+      }
+    },
+    "is-boolean-object": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
+      "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true
+    },
+    "is-callable": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
+      "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
+      "dev": true
+    },
+    "is-core-module": {
+      "version": "2.10.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz",
+      "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==",
+      "dev": true,
+      "requires": {
+        "has": "^1.0.3"
+      }
+    },
+    "is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-date-object": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
+      "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+      "dev": true,
+      "requires": {
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "requires": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      }
+    },
+    "is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+      "dev": true
+    },
+    "is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true
+    },
+    "is-fullwidth-code-point": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+      "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==",
+      "dev": true,
+      "requires": {
+        "number-is-nan": "^1.0.0"
+      }
+    },
+    "is-generator-function": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
+      "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
+      "dev": true,
+      "requires": {
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "requires": {
+        "is-extglob": "^2.1.1"
+      }
+    },
+    "is-map": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
+      "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
+      "dev": true
+    },
+    "is-negated-glob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
+      "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==",
+      "dev": true
+    },
+    "is-negative-zero": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
+      "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
+      "dev": true
+    },
+    "is-number": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+      "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-number-object": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
+      "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
+      "dev": true,
+      "requires": {
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-plain-obj": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+      "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
+      "dev": true
+    },
+    "is-plain-object": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+      "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+      "dev": true
+    },
+    "is-promise": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
+      "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==",
+      "dev": true
+    },
+    "is-regex": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
+      "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-relative": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+      "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
+      "dev": true,
+      "requires": {
+        "is-unc-path": "^1.0.0"
+      }
+    },
+    "is-set": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
+      "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
+      "dev": true
+    },
+    "is-shared-array-buffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
+      "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2"
+      }
+    },
+    "is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "dev": true
+    },
+    "is-string": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
+      "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
+      "dev": true,
+      "requires": {
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-symbol": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
+      "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+      "dev": true,
+      "requires": {
+        "has-symbols": "^1.0.2"
+      }
+    },
+    "is-typed-array": {
+      "version": "1.1.9",
+      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz",
+      "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==",
+      "dev": true,
+      "requires": {
+        "available-typed-arrays": "^1.0.5",
+        "call-bind": "^1.0.2",
+        "es-abstract": "^1.20.0",
+        "for-each": "^0.3.3",
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
+      "dev": true
+    },
+    "is-unc-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+      "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
+      "dev": true,
+      "requires": {
+        "unc-path-regex": "^0.1.2"
+      }
+    },
+    "is-utf8": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+      "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==",
+      "dev": true
+    },
+    "is-valid-glob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz",
+      "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==",
+      "dev": true
+    },
+    "is-weakmap": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
+      "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
+      "dev": true
+    },
+    "is-weakref": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
+      "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2"
+      }
+    },
+    "is-weakset": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
+      "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.1"
+      }
+    },
+    "is-windows": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+      "dev": true
+    },
+    "isarray": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+      "dev": true
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true
+    },
+    "isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
+      "dev": true
+    },
+    "istanbul-lib-coverage": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
+      "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
+      "dev": true
+    },
+    "istanbul-lib-hook": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz",
+      "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==",
+      "dev": true,
+      "requires": {
+        "append-transform": "^2.0.0"
+      }
+    },
+    "istanbul-lib-instrument": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
+      "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
+      "dev": true,
+      "requires": {
+        "@babel/core": "^7.7.5",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-coverage": "^3.0.0",
+        "semver": "^6.3.0"
+      }
+    },
+    "istanbul-lib-processinfo": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz",
+      "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==",
+      "dev": true,
+      "requires": {
+        "archy": "^1.0.0",
+        "cross-spawn": "^7.0.3",
+        "istanbul-lib-coverage": "^3.2.0",
+        "p-map": "^3.0.0",
+        "rimraf": "^3.0.0",
+        "uuid": "^8.3.2"
+      }
+    },
+    "istanbul-lib-report": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+      "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
+      "dev": true,
+      "requires": {
+        "istanbul-lib-coverage": "^3.0.0",
+        "make-dir": "^3.0.0",
+        "supports-color": "^7.1.0"
+      }
+    },
+    "istanbul-lib-source-maps": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
+      "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+      "dev": true,
+      "requires": {
+        "debug": "^4.1.1",
+        "istanbul-lib-coverage": "^3.0.0",
+        "source-map": "^0.6.1"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "istanbul-reports": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
+      "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
+      "dev": true,
+      "requires": {
+        "html-escaper": "^2.0.0",
+        "istanbul-lib-report": "^3.0.0"
+      }
+    },
+    "jaguarjs-jsdoc": {
+      "version": "git+ssh://git@github.com/dcodeIO/jaguarjs-jsdoc.git#ade85ac841f5ca8be40c60d506102039a036a8fa",
+      "dev": true,
+      "from": "jaguarjs-jsdoc@github:dcodeIO/jaguarjs-jsdoc"
+    },
+    "js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true
+    },
+    "js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "dev": true,
+      "requires": {
+        "argparse": "^2.0.1"
+      }
+    },
+    "js2xmlparser": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz",
+      "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==",
+      "dev": true,
+      "requires": {
+        "xmlcreate": "^2.0.4"
+      }
+    },
+    "jsdoc": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.0.tgz",
+      "integrity": "sha512-tzTgkklbWKrlaQL2+e3NNgLcZu3NaK2vsHRx7tyHQ+H5jcB9Gx0txSd2eJWlMC/xU1+7LQu4s58Ry0RkuaEQVg==",
+      "dev": true,
+      "requires": {
+        "@babel/parser": "^7.9.4",
+        "@jsdoc/salty": "^0.2.1",
+        "@types/markdown-it": "^12.2.3",
+        "bluebird": "^3.7.2",
+        "catharsis": "^0.9.0",
+        "escape-string-regexp": "^2.0.0",
+        "js2xmlparser": "^4.0.2",
+        "klaw": "^3.0.0",
+        "markdown-it": "^12.3.2",
+        "markdown-it-anchor": "^8.4.1",
+        "marked": "^4.0.10",
+        "mkdirp": "^1.0.4",
+        "requizzle": "^0.2.3",
+        "strip-json-comments": "^3.1.0",
+        "underscore": "~1.13.2"
+      },
+      "dependencies": {
+        "escape-string-regexp": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+          "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+          "dev": true
+        }
+      }
+    },
+    "jsesc": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+      "dev": true
+    },
+    "json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+      "dev": true
+    },
+    "json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true
+    },
+    "json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+      "dev": true
+    },
+    "json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "dev": true
+    },
+    "jsonfile": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+      "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "jsonparse": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+      "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
+      "dev": true
+    },
+    "JSONStream": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
+      "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
+      "dev": true,
+      "requires": {
+        "jsonparse": "^1.2.0",
+        "through": ">=2.2.7 <3"
+      }
+    },
+    "just-debounce": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz",
+      "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==",
+      "dev": true
+    },
+    "kind-of": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+      "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+      "dev": true
+    },
+    "klaw": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz",
+      "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.9"
+      }
+    },
+    "labeled-stream-splicer": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz",
+      "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.1",
+        "stream-splicer": "^2.0.0"
+      }
+    },
+    "last-run": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz",
+      "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==",
+      "dev": true,
+      "requires": {
+        "default-resolution": "^2.0.0",
+        "es6-weak-map": "^2.0.1"
+      }
+    },
+    "lazystream": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
+      "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.0.5"
+      }
+    },
+    "lcid": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+      "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==",
+      "dev": true,
+      "requires": {
+        "invert-kv": "^1.0.0"
+      }
+    },
+    "lead": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz",
+      "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==",
+      "dev": true,
+      "requires": {
+        "flush-write-stream": "^1.0.2"
+      }
+    },
+    "levn": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
+      }
+    },
+    "liftoff": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz",
+      "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==",
+      "dev": true,
+      "requires": {
+        "extend": "^3.0.0",
+        "findup-sync": "^3.0.0",
+        "fined": "^1.0.1",
+        "flagged-respawn": "^1.0.0",
+        "is-plain-object": "^2.0.4",
+        "object.map": "^1.0.0",
+        "rechoir": "^0.6.2",
+        "resolve": "^1.1.7"
+      },
+      "dependencies": {
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        }
+      }
+    },
+    "lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+      "dev": true
+    },
+    "linkify-it": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+      "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+      "dev": true,
+      "requires": {
+        "uc.micro": "^1.0.1"
+      }
+    },
+    "load-json-file": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+      "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "parse-json": "^2.2.0",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0",
+        "strip-bom": "^2.0.0"
+      },
+      "dependencies": {
+        "parse-json": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+          "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==",
+          "dev": true,
+          "requires": {
+            "error-ex": "^1.2.0"
+          }
+        },
+        "strip-bom": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+          "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==",
+          "dev": true,
+          "requires": {
+            "is-utf8": "^0.2.0"
+          }
+        }
+      }
+    },
+    "locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "requires": {
+        "p-locate": "^5.0.0"
+      }
+    },
+    "lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+      "dev": true
+    },
+    "lodash._reinterpolate": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
+      "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==",
+      "dev": true
+    },
+    "lodash.flattendeep": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
+      "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==",
+      "dev": true
+    },
+    "lodash.memoize": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
+      "integrity": "sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==",
+      "dev": true
+    },
+    "lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "dev": true
+    },
+    "lodash.template": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
+      "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==",
+      "dev": true,
+      "requires": {
+        "lodash._reinterpolate": "^3.0.0",
+        "lodash.templatesettings": "^4.0.0"
+      }
+    },
+    "lodash.templatesettings": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz",
+      "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==",
+      "dev": true,
+      "requires": {
+        "lodash._reinterpolate": "^3.0.0"
+      }
+    },
+    "long": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/long/-/long-5.2.0.tgz",
+      "integrity": "sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w=="
+    },
+    "lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "requires": {
+        "yallist": "^4.0.0"
+      }
+    },
+    "lru-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
+      "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==",
+      "dev": true,
+      "requires": {
+        "es5-ext": "~0.10.2"
+      }
+    },
+    "make-dir": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+      "dev": true,
+      "requires": {
+        "semver": "^6.0.0"
+      }
+    },
+    "make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+      "dev": true
+    },
+    "make-error-cause": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz",
+      "integrity": "sha512-4TO2Y3HkBnis4c0dxhAgD/jprySYLACf7nwN6V0HAHDx59g12WlRpUmFy1bRHamjGUEEBrEvCq6SUpsEE2lhUg==",
+      "dev": true,
+      "requires": {
+        "make-error": "^1.2.0"
+      }
+    },
+    "make-iterator": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
+      "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^6.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "map-cache": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+      "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==",
+      "dev": true
+    },
+    "map-obj": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
+      "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
+      "dev": true
+    },
+    "map-stream": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz",
+      "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==",
+      "dev": true
+    },
+    "map-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+      "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==",
+      "dev": true,
+      "requires": {
+        "object-visit": "^1.0.0"
+      }
+    },
+    "markdown-it": {
+      "version": "12.3.2",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+      "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
+      "dev": true,
+      "requires": {
+        "argparse": "^2.0.1",
+        "entities": "~2.1.0",
+        "linkify-it": "^3.0.1",
+        "mdurl": "^1.0.1",
+        "uc.micro": "^1.0.5"
+      }
+    },
+    "markdown-it-anchor": {
+      "version": "8.6.4",
+      "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.4.tgz",
+      "integrity": "sha512-Ul4YVYZNxMJYALpKtu+ZRdrryYt/GlQ5CK+4l1bp/gWXOG2QWElt6AqF3Mih/wfUKdZbNAZVXGR73/n6U/8img==",
+      "dev": true,
+      "requires": {}
+    },
+    "marked": {
+      "version": "4.0.19",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.19.tgz",
+      "integrity": "sha512-rgQF/OxOiLcvgUAj1Q1tAf4Bgxn5h5JZTp04Fx4XUkVhs7B+7YA9JEWJhJpoO8eJt8MkZMwqLCNeNqj1bCREZQ==",
+      "dev": true
+    },
+    "matchdep": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
+      "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==",
+      "dev": true,
+      "requires": {
+        "findup-sync": "^2.0.0",
+        "micromatch": "^3.0.4",
+        "resolve": "^1.4.0",
+        "stack-trace": "0.0.10"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+          "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.2",
+            "isobject": "^3.0.1"
+          }
+        },
+        "extend-shallow": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+          "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+          "dev": true,
+          "requires": {
+            "assign-symbols": "^1.0.0",
+            "is-extendable": "^1.0.1"
+          }
+        },
+        "findup-sync": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
+          "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==",
+          "dev": true,
+          "requires": {
+            "detect-file": "^1.0.0",
+            "is-glob": "^3.1.0",
+            "micromatch": "^3.0.4",
+            "resolve-dir": "^1.0.1"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        },
+        "is-glob": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+          "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^2.1.0"
+          }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        },
+        "micromatch": {
+          "version": "3.1.10",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+          "dev": true,
+          "requires": {
+            "arr-diff": "^4.0.0",
+            "array-unique": "^0.3.2",
+            "braces": "^2.3.1",
+            "define-property": "^2.0.2",
+            "extend-shallow": "^3.0.2",
+            "extglob": "^2.0.4",
+            "fragment-cache": "^0.2.1",
+            "kind-of": "^6.0.2",
+            "nanomatch": "^1.2.9",
+            "object.pick": "^1.3.0",
+            "regex-not": "^1.0.0",
+            "snapdragon": "^0.8.1",
+            "to-regex": "^3.0.2"
+          }
+        }
+      }
+    },
+    "md5.js": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+      "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+      "dev": true,
+      "requires": {
+        "hash-base": "^3.0.0",
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      }
+    },
+    "mdurl": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+      "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
+      "dev": true
+    },
+    "memoizee": {
+      "version": "0.4.15",
+      "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz",
+      "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==",
+      "dev": true,
+      "requires": {
+        "d": "^1.0.1",
+        "es5-ext": "^0.10.53",
+        "es6-weak-map": "^2.0.3",
+        "event-emitter": "^0.3.5",
+        "is-promise": "^2.2.2",
+        "lru-queue": "^0.1.0",
+        "next-tick": "^1.1.0",
+        "timers-ext": "^0.1.7"
+      }
+    },
+    "meow": {
+      "version": "8.1.2",
+      "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz",
+      "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==",
+      "dev": true,
+      "requires": {
+        "@types/minimist": "^1.2.0",
+        "camelcase-keys": "^6.2.2",
+        "decamelize-keys": "^1.1.0",
+        "hard-rejection": "^2.1.0",
+        "minimist-options": "4.1.0",
+        "normalize-package-data": "^3.0.0",
+        "read-pkg-up": "^7.0.1",
+        "redent": "^3.0.0",
+        "trim-newlines": "^3.0.0",
+        "type-fest": "^0.18.0",
+        "yargs-parser": "^20.2.3"
+      },
+      "dependencies": {
+        "type-fest": {
+          "version": "0.18.1",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
+          "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
+          "dev": true
+        }
+      }
+    },
+    "merge-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+      "dev": true
+    },
+    "merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true
+    },
+    "micromatch": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+      "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+      "dev": true,
+      "requires": {
+        "braces": "^3.0.2",
+        "picomatch": "^2.3.1"
+      },
+      "dependencies": {
+        "braces": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+          "dev": true,
+          "requires": {
+            "fill-range": "^7.0.1"
+          }
+        },
+        "fill-range": {
+          "version": "7.0.1",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+          "dev": true,
+          "requires": {
+            "to-regex-range": "^5.0.1"
+          }
+        },
+        "is-number": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+          "dev": true
+        },
+        "to-regex-range": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+          "dev": true,
+          "requires": {
+            "is-number": "^7.0.0"
+          }
+        }
+      }
+    },
+    "miller-rabin": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+      "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^4.0.0",
+        "brorand": "^1.0.1"
+      },
+      "dependencies": {
+        "bn.js": {
+          "version": "4.12.0",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+          "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+          "dev": true
+        }
+      }
+    },
+    "min-indent": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+      "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+      "dev": true
+    },
+    "minimalistic-assert": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+      "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+      "dev": true
+    },
+    "minimalistic-crypto-utils": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+      "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==",
+      "dev": true
+    },
+    "minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "minimist": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+      "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
+      "dev": true
+    },
+    "minimist-options": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
+      "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
+      "dev": true,
+      "requires": {
+        "arrify": "^1.0.1",
+        "is-plain-obj": "^1.1.0",
+        "kind-of": "^6.0.3"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "mixin-deep": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+      "dev": true,
+      "requires": {
+        "for-in": "^1.0.2",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        }
+      }
+    },
+    "mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "dev": true
+    },
+    "mkdirp-classic": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+      "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+      "dev": true
+    },
+    "module-deps": {
+      "version": "6.2.3",
+      "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz",
+      "integrity": "sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==",
+      "dev": true,
+      "requires": {
+        "browser-resolve": "^2.0.0",
+        "cached-path-relative": "^1.0.2",
+        "concat-stream": "~1.6.0",
+        "defined": "^1.0.0",
+        "detective": "^5.2.0",
+        "duplexer2": "^0.1.2",
+        "inherits": "^2.0.1",
+        "JSONStream": "^1.0.3",
+        "parents": "^1.0.0",
+        "readable-stream": "^2.0.2",
+        "resolve": "^1.4.0",
+        "stream-combiner2": "^1.1.1",
+        "subarg": "^1.0.0",
+        "through2": "^2.0.0",
+        "xtend": "^4.0.0"
+      }
+    },
+    "ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
+    },
+    "mute-stdout": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz",
+      "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==",
+      "dev": true
+    },
+    "nan": {
+      "version": "2.16.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz",
+      "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
+      "dev": true,
+      "optional": true
+    },
+    "nanomatch": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+      "dev": true,
+      "requires": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "fragment-cache": "^0.2.1",
+        "is-windows": "^1.0.2",
+        "kind-of": "^6.0.2",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+          "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.2",
+            "isobject": "^3.0.1"
+          }
+        },
+        "extend-shallow": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+          "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+          "dev": true,
+          "requires": {
+            "assign-symbols": "^1.0.0",
+            "is-extendable": "^1.0.1"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+      "dev": true
+    },
+    "next-tick": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
+      "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==",
+      "dev": true
+    },
+    "node-preload": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
+      "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==",
+      "dev": true,
+      "requires": {
+        "process-on-spawn": "^1.0.0"
+      }
+    },
+    "node-releases": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
+      "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
+      "dev": true
+    },
+    "normalize-package-data": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
+      "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
+      "dev": true,
+      "requires": {
+        "hosted-git-info": "^4.0.1",
+        "is-core-module": "^2.5.0",
+        "semver": "^7.3.4",
+        "validate-npm-package-license": "^3.0.1"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "7.3.7",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+          "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        }
+      }
+    },
+    "normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true
+    },
+    "now-and-later": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz",
+      "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==",
+      "dev": true,
+      "requires": {
+        "once": "^1.3.2"
+      }
+    },
+    "number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==",
+      "dev": true
+    },
+    "nyc": {
+      "version": "15.1.0",
+      "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
+      "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==",
+      "dev": true,
+      "requires": {
+        "@istanbuljs/load-nyc-config": "^1.0.0",
+        "@istanbuljs/schema": "^0.1.2",
+        "caching-transform": "^4.0.0",
+        "convert-source-map": "^1.7.0",
+        "decamelize": "^1.2.0",
+        "find-cache-dir": "^3.2.0",
+        "find-up": "^4.1.0",
+        "foreground-child": "^2.0.0",
+        "get-package-type": "^0.1.0",
+        "glob": "^7.1.6",
+        "istanbul-lib-coverage": "^3.0.0",
+        "istanbul-lib-hook": "^3.0.0",
+        "istanbul-lib-instrument": "^4.0.0",
+        "istanbul-lib-processinfo": "^2.0.2",
+        "istanbul-lib-report": "^3.0.0",
+        "istanbul-lib-source-maps": "^4.0.0",
+        "istanbul-reports": "^3.0.2",
+        "make-dir": "^3.0.0",
+        "node-preload": "^0.2.1",
+        "p-map": "^3.0.0",
+        "process-on-spawn": "^1.0.0",
+        "resolve-from": "^5.0.0",
+        "rimraf": "^3.0.0",
+        "signal-exit": "^3.0.2",
+        "spawn-wrap": "^2.0.0",
+        "test-exclude": "^6.0.0",
+        "yargs": "^15.0.2"
+      },
+      "dependencies": {
+        "cliui": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+          "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+          "dev": true,
+          "requires": {
+            "string-width": "^4.2.0",
+            "strip-ansi": "^6.0.0",
+            "wrap-ansi": "^6.2.0"
+          }
+        },
+        "convert-source-map": {
+          "version": "1.8.0",
+          "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
+          "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.1"
+          }
+        },
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "get-caller-file": {
+          "version": "2.0.5",
+          "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+          "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+          "dev": true
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        },
+        "require-main-filename": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+          "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+          "dev": true
+        },
+        "resolve-from": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+          "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+          "dev": true
+        },
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "4.2.3",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.1"
+          }
+        },
+        "which-module": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+          "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
+          "dev": true
+        },
+        "wrap-ansi": {
+          "version": "6.2.0",
+          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+          "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "string-width": "^4.1.0",
+            "strip-ansi": "^6.0.0"
+          }
+        },
+        "y18n": {
+          "version": "4.0.3",
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+          "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+          "dev": true
+        },
+        "yargs": {
+          "version": "15.4.1",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+          "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+          "dev": true,
+          "requires": {
+            "cliui": "^6.0.0",
+            "decamelize": "^1.2.0",
+            "find-up": "^4.1.0",
+            "get-caller-file": "^2.0.1",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^2.0.0",
+            "set-blocking": "^2.0.0",
+            "string-width": "^4.2.0",
+            "which-module": "^2.0.0",
+            "y18n": "^4.0.0",
+            "yargs-parser": "^18.1.2"
+          }
+        },
+        "yargs-parser": {
+          "version": "18.1.3",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+          "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+          "dev": true,
+          "requires": {
+            "camelcase": "^5.0.0",
+            "decamelize": "^1.2.0"
+          }
+        }
+      }
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "dev": true
+    },
+    "object-copy": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+      "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==",
+      "dev": true,
+      "requires": {
+        "copy-descriptor": "^0.1.0",
+        "define-property": "^0.2.5",
+        "kind-of": "^3.0.3"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "object-inspect": {
+      "version": "1.12.2",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
+      "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
+      "dev": true
+    },
+    "object-is": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
+      "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3"
+      }
+    },
+    "object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "dev": true
+    },
+    "object-visit": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+      "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.0"
+      }
+    },
+    "object.assign": {
+      "version": "4.1.4",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
+      "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "has-symbols": "^1.0.3",
+        "object-keys": "^1.1.1"
+      }
+    },
+    "object.defaults": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
+      "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==",
+      "dev": true,
+      "requires": {
+        "array-each": "^1.0.1",
+        "array-slice": "^1.0.0",
+        "for-own": "^1.0.0",
+        "isobject": "^3.0.0"
+      }
+    },
+    "object.map": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
+      "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==",
+      "dev": true,
+      "requires": {
+        "for-own": "^1.0.0",
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "object.pick": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+      "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
+    "object.reduce": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz",
+      "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==",
+      "dev": true,
+      "requires": {
+        "for-own": "^1.0.0",
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dev": true,
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "optionator": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+      "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+      "dev": true,
+      "requires": {
+        "deep-is": "~0.1.3",
+        "fast-levenshtein": "~2.0.6",
+        "levn": "~0.3.0",
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2",
+        "word-wrap": "~1.2.3"
+      },
+      "dependencies": {
+        "levn": {
+          "version": "0.3.0",
+          "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+          "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
+          "dev": true,
+          "requires": {
+            "prelude-ls": "~1.1.2",
+            "type-check": "~0.3.2"
+          }
+        },
+        "prelude-ls": {
+          "version": "1.1.2",
+          "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+          "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
+          "dev": true
+        },
+        "type-check": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+          "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
+          "dev": true,
+          "requires": {
+            "prelude-ls": "~1.1.2"
+          }
+        }
+      }
+    },
+    "ordered-read-streams": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz",
+      "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.0.1"
+      }
+    },
+    "os-browserify": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+      "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==",
+      "dev": true
+    },
+    "os-locale": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+      "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==",
+      "dev": true,
+      "requires": {
+        "lcid": "^1.0.0"
+      }
+    },
+    "p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "requires": {
+        "yocto-queue": "^0.1.0"
+      }
+    },
+    "p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "requires": {
+        "p-limit": "^3.0.2"
+      }
+    },
+    "p-map": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
+      "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
+      "dev": true,
+      "requires": {
+        "aggregate-error": "^3.0.0"
+      }
+    },
+    "p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true
+    },
+    "package-hash": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz",
+      "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.15",
+        "hasha": "^5.0.0",
+        "lodash.flattendeep": "^4.4.0",
+        "release-zalgo": "^1.0.0"
+      }
+    },
+    "pako": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+      "dev": true
+    },
+    "parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "requires": {
+        "callsites": "^3.0.0"
+      }
+    },
+    "parents": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
+      "integrity": "sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==",
+      "dev": true,
+      "requires": {
+        "path-platform": "~0.11.15"
+      }
+    },
+    "parse-asn1": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
+      "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
+      "dev": true,
+      "requires": {
+        "asn1.js": "^5.2.0",
+        "browserify-aes": "^1.0.0",
+        "evp_bytestokey": "^1.0.0",
+        "pbkdf2": "^3.0.3",
+        "safe-buffer": "^5.1.1"
+      }
+    },
+    "parse-filepath": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
+      "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==",
+      "dev": true,
+      "requires": {
+        "is-absolute": "^1.0.0",
+        "map-cache": "^0.2.0",
+        "path-root": "^0.1.1"
+      }
+    },
+    "parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      }
+    },
+    "parse-node-version": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
+      "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
+      "dev": true
+    },
+    "parse-passwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+      "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==",
+      "dev": true
+    },
+    "pascalcase": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+      "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==",
+      "dev": true
+    },
+    "path-browserify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
+      "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
+      "dev": true
+    },
+    "path-dirname": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+      "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==",
+      "dev": true
+    },
+    "path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "dev": true
+    },
+    "path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true
+    },
+    "path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "dev": true
+    },
+    "path-platform": {
+      "version": "0.11.15",
+      "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz",
+      "integrity": "sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==",
+      "dev": true
+    },
+    "path-root": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
+      "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==",
+      "dev": true,
+      "requires": {
+        "path-root-regex": "^0.1.0"
+      }
+    },
+    "path-root-regex": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
+      "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==",
+      "dev": true
+    },
+    "path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true
+    },
+    "pbkdf2": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
+      "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
+      "dev": true,
+      "requires": {
+        "create-hash": "^1.1.2",
+        "create-hmac": "^1.1.4",
+        "ripemd160": "^2.0.1",
+        "safe-buffer": "^5.0.1",
+        "sha.js": "^2.4.8"
+      }
+    },
+    "picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+      "dev": true
+    },
+    "picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true
+    },
+    "pify": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+      "dev": true
+    },
+    "pinkie": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+      "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==",
+      "dev": true
+    },
+    "pinkie-promise": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+      "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==",
+      "dev": true,
+      "requires": {
+        "pinkie": "^2.0.0"
+      }
+    },
+    "pkg-dir": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+      "dev": true,
+      "requires": {
+        "find-up": "^4.0.0"
+      },
+      "dependencies": {
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        }
+      }
+    },
+    "platform": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
+      "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==",
+      "dev": true
+    },
+    "posix-character-classes": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+      "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==",
+      "dev": true
+    },
+    "postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "dev": true,
+      "requires": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "prelude-ls": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+      "dev": true
+    },
+    "pretty-hrtime": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
+      "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==",
+      "dev": true
+    },
+    "process": {
+      "version": "0.11.10",
+      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+      "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+      "dev": true
+    },
+    "process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "dev": true
+    },
+    "process-on-spawn": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
+      "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==",
+      "dev": true,
+      "requires": {
+        "fromentries": "^1.2.0"
+      }
+    },
+    "public-encrypt": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
+      "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^4.1.0",
+        "browserify-rsa": "^4.0.0",
+        "create-hash": "^1.1.0",
+        "parse-asn1": "^5.0.0",
+        "randombytes": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      },
+      "dependencies": {
+        "bn.js": {
+          "version": "4.12.0",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+          "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+          "dev": true
+        }
+      }
+    },
+    "pump": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+      "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "pumpify": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+      "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+      "dev": true,
+      "requires": {
+        "duplexify": "^3.6.0",
+        "inherits": "^2.0.3",
+        "pump": "^2.0.0"
+      },
+      "dependencies": {
+        "duplexify": {
+          "version": "3.7.1",
+          "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
+          "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
+          "dev": true,
+          "requires": {
+            "end-of-stream": "^1.0.0",
+            "inherits": "^2.0.1",
+            "readable-stream": "^2.0.0",
+            "stream-shift": "^1.0.0"
+          }
+        }
+      }
+    },
+    "punycode": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+      "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
+      "dev": true
+    },
+    "querystring": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+      "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==",
+      "dev": true
+    },
+    "querystring-es3": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+      "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==",
+      "dev": true
+    },
+    "queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true
+    },
+    "quick-lru": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
+      "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
+      "dev": true
+    },
+    "randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "randomfill": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+      "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+      "dev": true,
+      "requires": {
+        "randombytes": "^2.0.5",
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "read-only-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz",
+      "integrity": "sha512-3ALe0bjBVZtkdWKIcThYpQCLbBMd/+Tbh2CDSrAIDO3UsZ4Xs+tnyjv2MjCOMMgBG+AsUOeuP1cgtY1INISc8w==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.0.2"
+      }
+    },
+    "read-pkg": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+      "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+      "dev": true,
+      "requires": {
+        "@types/normalize-package-data": "^2.4.0",
+        "normalize-package-data": "^2.5.0",
+        "parse-json": "^5.0.0",
+        "type-fest": "^0.6.0"
+      },
+      "dependencies": {
+        "hosted-git-info": {
+          "version": "2.8.9",
+          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+          "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+          "dev": true
+        },
+        "normalize-package-data": {
+          "version": "2.5.0",
+          "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+          "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+          "dev": true,
+          "requires": {
+            "hosted-git-info": "^2.1.4",
+            "resolve": "^1.10.0",
+            "semver": "2 || 3 || 4 || 5",
+            "validate-npm-package-license": "^3.0.1"
+          }
+        },
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        },
+        "type-fest": {
+          "version": "0.6.0",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+          "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+          "dev": true
+        }
+      }
+    },
+    "read-pkg-up": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+      "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+      "dev": true,
+      "requires": {
+        "find-up": "^4.1.0",
+        "read-pkg": "^5.2.0",
+        "type-fest": "^0.8.1"
+      },
+      "dependencies": {
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        },
+        "type-fest": {
+          "version": "0.8.1",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+          "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+          "dev": true
+        }
+      }
+    },
+    "readable-stream": {
+      "version": "2.3.7",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+      "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+      "dev": true,
+      "requires": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+          "dev": true
+        },
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+          "dev": true
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "readdirp": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+      "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.11",
+        "micromatch": "^3.1.10",
+        "readable-stream": "^2.0.2"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+          "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.2",
+            "isobject": "^3.0.1"
+          }
+        },
+        "extend-shallow": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+          "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+          "dev": true,
+          "requires": {
+            "assign-symbols": "^1.0.0",
+            "is-extendable": "^1.0.1"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        },
+        "micromatch": {
+          "version": "3.1.10",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+          "dev": true,
+          "requires": {
+            "arr-diff": "^4.0.0",
+            "array-unique": "^0.3.2",
+            "braces": "^2.3.1",
+            "define-property": "^2.0.2",
+            "extend-shallow": "^3.0.2",
+            "extglob": "^2.0.4",
+            "fragment-cache": "^0.2.1",
+            "kind-of": "^6.0.2",
+            "nanomatch": "^1.2.9",
+            "object.pick": "^1.3.0",
+            "regex-not": "^1.0.0",
+            "snapdragon": "^0.8.1",
+            "to-regex": "^3.0.2"
+          }
+        }
+      }
+    },
+    "rechoir": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+      "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
+      "dev": true,
+      "requires": {
+        "resolve": "^1.1.6"
+      }
+    },
+    "redent": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+      "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+      "dev": true,
+      "requires": {
+        "indent-string": "^4.0.0",
+        "strip-indent": "^3.0.0"
+      }
+    },
+    "reflect-metadata": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
+      "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
+      "dev": true
+    },
+    "regex-not": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^3.0.2",
+        "safe-regex": "^1.1.0"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+          "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+          "dev": true,
+          "requires": {
+            "assign-symbols": "^1.0.0",
+            "is-extendable": "^1.0.1"
+          }
+        },
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        }
+      }
+    },
+    "regexp.prototype.flags": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
+      "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3",
+        "functions-have-names": "^1.2.2"
+      }
+    },
+    "regexpp": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+      "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+      "dev": true
+    },
+    "release-zalgo": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
+      "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==",
+      "dev": true,
+      "requires": {
+        "es6-error": "^4.0.1"
+      }
+    },
+    "remove-bom-buffer": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",
+      "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==",
+      "dev": true,
+      "requires": {
+        "is-buffer": "^1.1.5",
+        "is-utf8": "^0.2.1"
+      }
+    },
+    "remove-bom-stream": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz",
+      "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==",
+      "dev": true,
+      "requires": {
+        "remove-bom-buffer": "^3.0.0",
+        "safe-buffer": "^5.1.0",
+        "through2": "^2.0.3"
+      }
+    },
+    "remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==",
+      "dev": true
+    },
+    "repeat-element": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
+      "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==",
+      "dev": true
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
+      "dev": true
+    },
+    "replace-ext": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz",
+      "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==",
+      "dev": true
+    },
+    "replace-homedir": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz",
+      "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1",
+        "is-absolute": "^1.0.0",
+        "remove-trailing-separator": "^1.1.0"
+      }
+    },
+    "require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "dev": true
+    },
+    "require-main-filename": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+      "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==",
+      "dev": true
+    },
+    "requizzle": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz",
+      "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.14"
+      }
+    },
+    "resolve": {
+      "version": "1.22.1",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "dev": true,
+      "requires": {
+        "is-core-module": "^2.9.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      }
+    },
+    "resolve-dir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+      "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.0",
+        "global-modules": "^1.0.0"
+      }
+    },
+    "resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true
+    },
+    "resolve-options": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz",
+      "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==",
+      "dev": true,
+      "requires": {
+        "value-or-function": "^3.0.0"
+      }
+    },
+    "resolve-url": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+      "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==",
+      "dev": true
+    },
+    "resumer": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz",
+      "integrity": "sha512-Fn9X8rX8yYF4m81rZCK/5VmrmsSbqS/i3rDLl6ZZHAXgC2nTAx3dhwG8q8odP/RmdLa2YrybDJaAMg+X1ajY3w==",
+      "dev": true,
+      "requires": {
+        "through": "~2.3.4"
+      }
+    },
+    "ret": {
+      "version": "0.1.15",
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+      "dev": true
+    },
+    "reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "dev": true
+    },
+    "rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "dev": true,
+      "requires": {
+        "glob": "^7.1.3"
+      }
+    },
+    "ripemd160": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+      "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+      "dev": true,
+      "requires": {
+        "hash-base": "^3.0.0",
+        "inherits": "^2.0.1"
+      }
+    },
+    "run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "requires": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true
+    },
+    "safe-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+      "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==",
+      "dev": true,
+      "requires": {
+        "ret": "~0.1.10"
+      }
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
+    },
+    "semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true
+    },
+    "semver-greatest-satisfied-range": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz",
+      "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==",
+      "dev": true,
+      "requires": {
+        "sver-compat": "^1.5.0"
+      }
+    },
+    "set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+      "dev": true
+    },
+    "set-value": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^2.0.1",
+        "is-extendable": "^0.1.1",
+        "is-plain-object": "^2.0.3",
+        "split-string": "^3.0.1"
+      },
+      "dependencies": {
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        }
+      }
+    },
+    "sha.js": {
+      "version": "2.4.11",
+      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+      "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "shasum-object": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz",
+      "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==",
+      "dev": true,
+      "requires": {
+        "fast-safe-stringify": "^2.0.7"
+      }
+    },
+    "shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "requires": {
+        "shebang-regex": "^3.0.0"
+      }
+    },
+    "shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true
+    },
+    "shell-quote": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz",
+      "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==",
+      "dev": true
+    },
+    "side-channel": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.0",
+        "get-intrinsic": "^1.0.2",
+        "object-inspect": "^1.9.0"
+      }
+    },
+    "signal-exit": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+      "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+      "dev": true
+    },
+    "simple-concat": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+      "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+      "dev": true
+    },
+    "slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true
+    },
+    "snapdragon": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+      "dev": true,
+      "requires": {
+        "base": "^0.11.1",
+        "debug": "^2.2.0",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "map-cache": "^0.2.2",
+        "source-map": "^0.5.6",
+        "source-map-resolve": "^0.5.0",
+        "use": "^3.1.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true
+        },
+        "source-map-resolve": {
+          "version": "0.5.3",
+          "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+          "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+          "dev": true,
+          "requires": {
+            "atob": "^2.1.2",
+            "decode-uri-component": "^0.2.0",
+            "resolve-url": "^0.2.1",
+            "source-map-url": "^0.4.0",
+            "urix": "^0.1.0"
+          }
+        }
+      }
+    },
+    "snapdragon-node": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+      "dev": true,
+      "requires": {
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.0",
+        "snapdragon-util": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "snapdragon-util": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.2.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "source-map": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+      "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+      "dev": true
+    },
+    "source-map-resolve": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz",
+      "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==",
+      "dev": true,
+      "requires": {
+        "atob": "^2.1.2",
+        "decode-uri-component": "^0.2.0"
+      }
+    },
+    "source-map-url": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
+      "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
+      "dev": true
+    },
+    "sparkles": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz",
+      "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==",
+      "dev": true
+    },
+    "spawn-wrap": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz",
+      "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==",
+      "dev": true,
+      "requires": {
+        "foreground-child": "^2.0.0",
+        "is-windows": "^1.0.2",
+        "make-dir": "^3.0.0",
+        "rimraf": "^3.0.0",
+        "signal-exit": "^3.0.2",
+        "which": "^2.0.1"
+      }
+    },
+    "spdx-correct": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
+      "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
+      "dev": true,
+      "requires": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-exceptions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+      "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
+      "dev": true
+    },
+    "spdx-expression-parse": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+      "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+      "dev": true,
+      "requires": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-license-ids": {
+      "version": "3.0.12",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz",
+      "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==",
+      "dev": true
+    },
+    "split-string": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^3.0.0"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+          "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+          "dev": true,
+          "requires": {
+            "assign-symbols": "^1.0.0",
+            "is-extendable": "^1.0.1"
+          }
+        },
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        }
+      }
+    },
+    "split2": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
+      "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^3.0.0"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+      "dev": true
+    },
+    "stack-trace": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+      "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
+      "dev": true
+    },
+    "static-extend": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+      "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==",
+      "dev": true,
+      "requires": {
+        "define-property": "^0.2.5",
+        "object-copy": "^0.1.0"
+      }
+    },
+    "stream-browserify": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
+      "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==",
+      "dev": true,
+      "requires": {
+        "inherits": "~2.0.4",
+        "readable-stream": "^3.5.0"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
+    "stream-combiner2": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz",
+      "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==",
+      "dev": true,
+      "requires": {
+        "duplexer2": "~0.1.0",
+        "readable-stream": "^2.0.2"
+      }
+    },
+    "stream-exhaust": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz",
+      "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==",
+      "dev": true
+    },
+    "stream-http": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz",
+      "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==",
+      "dev": true,
+      "requires": {
+        "builtin-status-codes": "^3.0.0",
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.6.0",
+        "xtend": "^4.0.2"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
+    "stream-shift": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
+      "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
+      "dev": true
+    },
+    "stream-splicer": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz",
+      "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.1",
+        "readable-stream": "^2.0.2"
+      }
+    },
+    "string_decoder": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
+    "string-width": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+      "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==",
+      "dev": true,
+      "requires": {
+        "code-point-at": "^1.0.0",
+        "is-fullwidth-code-point": "^1.0.0",
+        "strip-ansi": "^3.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+          "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+          "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^2.0.0"
+          }
+        }
+      }
+    },
+    "string.prototype.trim": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.6.tgz",
+      "integrity": "sha512-8lMR2m+U0VJTPp6JjvJTtGyc4FIGq9CdRt7O9p6T0e6K4vjU+OP+SQJpbe/SBmRcCUIvNUnjsbmY6lnMp8MhsQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.19.5"
+      }
+    },
+    "string.prototype.trimend": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
+      "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.19.5"
+      }
+    },
+    "string.prototype.trimstart": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz",
+      "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.19.5"
+      }
+    },
+    "strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "^5.0.1"
+      }
+    },
+    "strip-bom": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+      "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+      "dev": true
+    },
+    "strip-bom-string": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
+      "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
+      "dev": true
+    },
+    "strip-indent": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+      "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+      "dev": true,
+      "requires": {
+        "min-indent": "^1.0.0"
+      }
+    },
+    "strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true
+    },
+    "strip-outer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
+      "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
+      "dev": true,
+      "requires": {
+        "escape-string-regexp": "^1.0.2"
+      },
+      "dependencies": {
+        "escape-string-regexp": {
+          "version": "1.0.5",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+          "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+          "dev": true
+        }
+      }
+    },
+    "subarg": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
+      "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==",
+      "dev": true,
+      "requires": {
+        "minimist": "^1.1.0"
+      }
+    },
+    "supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "requires": {
+        "has-flag": "^4.0.0"
+      }
+    },
+    "supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "dev": true
+    },
+    "sver-compat": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz",
+      "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==",
+      "dev": true,
+      "requires": {
+        "es6-iterator": "^2.0.1",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "syntax-error": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz",
+      "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==",
+      "dev": true,
+      "requires": {
+        "acorn-node": "^1.2.0"
+      }
+    },
+    "tape": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/tape/-/tape-5.6.0.tgz",
+      "integrity": "sha512-LyM4uqbiTAqDgsHTY0r1LH66yE24P3SZaz5TL3mPUds0XCTFl/0AMUBrjgBjUclvbPTFB4IalXg0wFfbTuuu/Q==",
+      "dev": true,
+      "requires": {
+        "array.prototype.every": "^1.1.3",
+        "call-bind": "^1.0.2",
+        "deep-equal": "^2.0.5",
+        "defined": "^1.0.0",
+        "dotignore": "^0.1.2",
+        "for-each": "^0.3.3",
+        "get-package-type": "^0.1.0",
+        "glob": "^7.2.3",
+        "has": "^1.0.3",
+        "has-dynamic-import": "^2.0.1",
+        "inherits": "^2.0.4",
+        "is-regex": "^1.1.4",
+        "minimist": "^1.2.6",
+        "object-inspect": "^1.12.2",
+        "object-is": "^1.1.5",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.3",
+        "resolve": "^2.0.0-next.3",
+        "resumer": "^0.0.0",
+        "string.prototype.trim": "^1.2.6",
+        "through": "^2.3.8"
+      },
+      "dependencies": {
+        "resolve": {
+          "version": "2.0.0-next.4",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
+          "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==",
+          "dev": true,
+          "requires": {
+            "is-core-module": "^2.9.0",
+            "path-parse": "^1.0.7",
+            "supports-preserve-symlinks-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "ternary-stream": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-3.0.0.tgz",
+      "integrity": "sha512-oIzdi+UL/JdktkT+7KU5tSIQjj8pbShj3OASuvDEhm0NT5lppsm7aXWAmAq4/QMaBIyfuEcNLbAQA+HpaISobQ==",
+      "dev": true,
+      "requires": {
+        "duplexify": "^4.1.1",
+        "fork-stream": "^0.0.4",
+        "merge-stream": "^2.0.0",
+        "through2": "^3.0.1"
+      },
+      "dependencies": {
+        "through2": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
+          "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.4",
+            "readable-stream": "2 || 3"
+          }
+        }
+      }
+    },
+    "test-exclude": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+      "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+      "dev": true,
+      "requires": {
+        "@istanbuljs/schema": "^0.1.2",
+        "glob": "^7.1.4",
+        "minimatch": "^3.0.4"
+      }
+    },
+    "text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+      "dev": true
+    },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+      "dev": true
+    },
+    "through2": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+      "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "~2.3.6",
+        "xtend": "~4.0.1"
+      }
+    },
+    "through2-filter": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz",
+      "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==",
+      "dev": true,
+      "requires": {
+        "through2": "~2.0.0",
+        "xtend": "~4.0.0"
+      }
+    },
+    "time-stamp": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
+      "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==",
+      "dev": true
+    },
+    "timers-browserify": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz",
+      "integrity": "sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q==",
+      "dev": true,
+      "requires": {
+        "process": "~0.11.0"
+      }
+    },
+    "timers-ext": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz",
+      "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==",
+      "dev": true,
+      "requires": {
+        "es5-ext": "~0.10.46",
+        "next-tick": "1"
+      }
+    },
+    "to-absolute-glob": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
+      "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==",
+      "dev": true,
+      "requires": {
+        "is-absolute": "^1.0.0",
+        "is-negated-glob": "^1.0.0"
+      }
+    },
+    "to-fast-properties": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+      "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+      "dev": true
+    },
+    "to-object-path": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+      "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "to-regex": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+      "dev": true,
+      "requires": {
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "regex-not": "^1.0.2",
+        "safe-regex": "^1.1.0"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+          "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.2",
+            "isobject": "^3.0.1"
+          }
+        },
+        "extend-shallow": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+          "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+          "dev": true,
+          "requires": {
+            "assign-symbols": "^1.0.0",
+            "is-extendable": "^1.0.1"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "to-regex-range": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+      "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
+      "dev": true,
+      "requires": {
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1"
+      }
+    },
+    "to-through": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz",
+      "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==",
+      "dev": true,
+      "requires": {
+        "through2": "^2.0.3"
+      }
+    },
+    "trim-newlines": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
+      "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
+      "dev": true
+    },
+    "trim-repeated": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
+      "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==",
+      "dev": true,
+      "requires": {
+        "escape-string-regexp": "^1.0.2"
+      },
+      "dependencies": {
+        "escape-string-regexp": {
+          "version": "1.0.5",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+          "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+          "dev": true
+        }
+      }
+    },
+    "tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true
+    },
+    "tslint": {
+      "version": "6.1.3",
+      "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
+      "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.0.0",
+        "builtin-modules": "^1.1.1",
+        "chalk": "^2.3.0",
+        "commander": "^2.12.1",
+        "diff": "^4.0.1",
+        "glob": "^7.1.1",
+        "js-yaml": "^3.13.1",
+        "minimatch": "^3.0.4",
+        "mkdirp": "^0.5.3",
+        "resolve": "^1.3.2",
+        "semver": "^5.3.0",
+        "tslib": "^1.13.0",
+        "tsutils": "^2.29.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "argparse": {
+          "version": "1.0.10",
+          "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+          "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+          "dev": true,
+          "requires": {
+            "sprintf-js": "~1.0.2"
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "color-convert": {
+          "version": "1.9.3",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+          "dev": true,
+          "requires": {
+            "color-name": "1.1.3"
+          }
+        },
+        "color-name": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+          "dev": true
+        },
+        "escape-string-regexp": {
+          "version": "1.0.5",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+          "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+          "dev": true
+        },
+        "js-yaml": {
+          "version": "3.14.1",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+          "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+          "dev": true,
+          "requires": {
+            "argparse": "^1.0.7",
+            "esprima": "^4.0.0"
+          }
+        },
+        "mkdirp": {
+          "version": "0.5.6",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+          "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+          "dev": true,
+          "requires": {
+            "minimist": "^1.2.6"
+          }
+        },
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "tsutils": {
+      "version": "2.29.0",
+      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
+      "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
+      "dev": true,
+      "requires": {
+        "tslib": "^1.8.1"
+      }
+    },
+    "tty-browserify": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz",
+      "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==",
+      "dev": true
+    },
+    "type": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+      "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
+      "dev": true
+    },
+    "type-check": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "^1.2.1"
+      }
+    },
+    "type-fest": {
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+      "dev": true
+    },
+    "typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+      "dev": true
+    },
+    "typedarray-to-buffer": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+      "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+      "dev": true,
+      "requires": {
+        "is-typedarray": "^1.0.0"
+      }
+    },
+    "typescript": {
+      "version": "3.9.10",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz",
+      "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==",
+      "dev": true
+    },
+    "uc.micro": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+      "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
+      "dev": true
+    },
+    "uglify-js": {
+      "version": "3.17.0",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz",
+      "integrity": "sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg==",
+      "dev": true
+    },
+    "umd": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz",
+      "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==",
+      "dev": true
+    },
+    "unbox-primitive": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
+      "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "has-bigints": "^1.0.2",
+        "has-symbols": "^1.0.3",
+        "which-boxed-primitive": "^1.0.2"
+      }
+    },
+    "unc-path-regex": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
+      "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==",
+      "dev": true
+    },
+    "undeclared-identifiers": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz",
+      "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==",
+      "dev": true,
+      "requires": {
+        "acorn-node": "^1.3.0",
+        "dash-ast": "^1.0.0",
+        "get-assigned-identifiers": "^1.2.0",
+        "simple-concat": "^1.0.0",
+        "xtend": "^4.0.1"
+      }
+    },
+    "underscore": {
+      "version": "1.13.4",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz",
+      "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==",
+      "dev": true
+    },
+    "undertaker": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz",
+      "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==",
+      "dev": true,
+      "requires": {
+        "arr-flatten": "^1.0.1",
+        "arr-map": "^2.0.0",
+        "bach": "^1.0.0",
+        "collection-map": "^1.0.0",
+        "es6-weak-map": "^2.0.1",
+        "fast-levenshtein": "^1.0.0",
+        "last-run": "^1.1.0",
+        "object.defaults": "^1.0.0",
+        "object.reduce": "^1.0.0",
+        "undertaker-registry": "^1.0.0"
+      },
+      "dependencies": {
+        "fast-levenshtein": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz",
+          "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==",
+          "dev": true
+        }
+      }
+    },
+    "undertaker-registry": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz",
+      "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==",
+      "dev": true
+    },
+    "union-value": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+      "dev": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "get-value": "^2.0.6",
+        "is-extendable": "^0.1.1",
+        "set-value": "^2.0.1"
+      }
+    },
+    "unique-stream": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
+      "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==",
+      "dev": true,
+      "requires": {
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "through2-filter": "^3.0.0"
+      }
+    },
+    "universalify": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+      "dev": true
+    },
+    "unset-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+      "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==",
+      "dev": true,
+      "requires": {
+        "has-value": "^0.3.1",
+        "isobject": "^3.0.0"
+      },
+      "dependencies": {
+        "has-value": {
+          "version": "0.3.1",
+          "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+          "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==",
+          "dev": true,
+          "requires": {
+            "get-value": "^2.0.3",
+            "has-values": "^0.1.4",
+            "isobject": "^2.0.0"
+          },
+          "dependencies": {
+            "isobject": {
+              "version": "2.1.0",
+              "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+              "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==",
+              "dev": true,
+              "requires": {
+                "isarray": "1.0.0"
+              }
+            }
+          }
+        },
+        "has-values": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+          "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==",
+          "dev": true
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+          "dev": true
+        }
+      }
+    },
+    "upath": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+      "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+      "dev": true
+    },
+    "update-browserslist-db": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz",
+      "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==",
+      "dev": true,
+      "requires": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      },
+      "dependencies": {
+        "picocolors": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+          "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+          "dev": true
+        }
+      }
+    },
+    "uri-js": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+      "dev": true,
+      "requires": {
+        "punycode": "^2.1.0"
+      },
+      "dependencies": {
+        "punycode": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+          "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+          "dev": true
+        }
+      }
+    },
+    "urix": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+      "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==",
+      "dev": true
+    },
+    "url": {
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+      "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==",
+      "dev": true,
+      "requires": {
+        "punycode": "1.3.2",
+        "querystring": "0.2.0"
+      },
+      "dependencies": {
+        "punycode": {
+          "version": "1.3.2",
+          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+          "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==",
+          "dev": true
+        }
+      }
+    },
+    "use": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+      "dev": true
+    },
+    "util": {
+      "version": "0.12.4",
+      "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz",
+      "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.3",
+        "is-arguments": "^1.0.4",
+        "is-generator-function": "^1.0.7",
+        "is-typed-array": "^1.1.3",
+        "safe-buffer": "^5.1.2",
+        "which-typed-array": "^1.1.2"
+      }
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+      "dev": true
+    },
+    "uuid": {
+      "version": "8.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+      "dev": true
+    },
+    "v8-compile-cache": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
+      "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
+      "dev": true
+    },
+    "v8flags": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz",
+      "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1"
+      }
+    },
+    "validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "dev": true,
+      "requires": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
+    "value-or-function": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
+      "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==",
+      "dev": true
+    },
+    "vinyl": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz",
+      "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==",
+      "dev": true,
+      "requires": {
+        "clone": "^2.1.1",
+        "clone-buffer": "^1.0.0",
+        "clone-stats": "^1.0.0",
+        "cloneable-readable": "^1.0.0",
+        "remove-trailing-separator": "^1.0.1",
+        "replace-ext": "^1.0.0"
+      }
+    },
+    "vinyl-buffer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/vinyl-buffer/-/vinyl-buffer-1.0.1.tgz",
+      "integrity": "sha512-LRBE2/g3C1hSHL2k/FynSZcVTRhEw8sb08oKGt/0hukZXwrh2m8nfy+r5yLhGEk7eFFuclhyIuPct/Bxlxk6rg==",
+      "dev": true,
+      "requires": {
+        "bl": "^1.2.1",
+        "through2": "^2.0.3"
+      }
+    },
+    "vinyl-fs": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz",
+      "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==",
+      "dev": true,
+      "requires": {
+        "fs-mkdirp-stream": "^1.0.0",
+        "glob-stream": "^6.1.0",
+        "graceful-fs": "^4.0.0",
+        "is-valid-glob": "^1.0.0",
+        "lazystream": "^1.0.0",
+        "lead": "^1.0.0",
+        "object.assign": "^4.0.4",
+        "pumpify": "^1.3.5",
+        "readable-stream": "^2.3.3",
+        "remove-bom-buffer": "^3.0.0",
+        "remove-bom-stream": "^1.2.0",
+        "resolve-options": "^1.1.0",
+        "through2": "^2.0.0",
+        "to-through": "^2.0.0",
+        "value-or-function": "^3.0.0",
+        "vinyl": "^2.0.0",
+        "vinyl-sourcemap": "^1.1.0"
+      }
+    },
+    "vinyl-source-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-2.0.0.tgz",
+      "integrity": "sha512-Y5f1wRGajOfYukhv8biIGA7iZiY8UOIc3zJ6zcUNIbRG1BVuXzBsfSfe7MUJTttVkuy64k/pGQtJdd/aIt+hbw==",
+      "dev": true,
+      "requires": {
+        "through2": "^2.0.3",
+        "vinyl": "^2.1.0"
+      }
+    },
+    "vinyl-sourcemap": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz",
+      "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==",
+      "dev": true,
+      "requires": {
+        "append-buffer": "^1.0.2",
+        "convert-source-map": "^1.5.0",
+        "graceful-fs": "^4.1.6",
+        "normalize-path": "^2.1.1",
+        "now-and-later": "^2.0.0",
+        "remove-bom-buffer": "^3.0.0",
+        "vinyl": "^2.0.0"
+      },
+      "dependencies": {
+        "convert-source-map": {
+          "version": "1.8.0",
+          "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
+          "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.1"
+          }
+        },
+        "normalize-path": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+          "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
+          "dev": true,
+          "requires": {
+            "remove-trailing-separator": "^1.0.1"
+          }
+        },
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+          "dev": true
+        }
+      }
+    },
+    "vinyl-sourcemaps-apply": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz",
+      "integrity": "sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==",
+      "dev": true,
+      "requires": {
+        "source-map": "^0.5.1"
+      }
+    },
+    "vm-browserify": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
+      "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
+      "dev": true
+    },
+    "which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "requires": {
+        "isexe": "^2.0.0"
+      }
+    },
+    "which-boxed-primitive": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
+      "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
+      "dev": true,
+      "requires": {
+        "is-bigint": "^1.0.1",
+        "is-boolean-object": "^1.1.0",
+        "is-number-object": "^1.0.4",
+        "is-string": "^1.0.5",
+        "is-symbol": "^1.0.3"
+      }
+    },
+    "which-collection": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
+      "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==",
+      "dev": true,
+      "requires": {
+        "is-map": "^2.0.1",
+        "is-set": "^2.0.1",
+        "is-weakmap": "^2.0.1",
+        "is-weakset": "^2.0.1"
+      }
+    },
+    "which-module": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
+      "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==",
+      "dev": true
+    },
+    "which-typed-array": {
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz",
+      "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==",
+      "dev": true,
+      "requires": {
+        "available-typed-arrays": "^1.0.5",
+        "call-bind": "^1.0.2",
+        "es-abstract": "^1.20.0",
+        "for-each": "^0.3.3",
+        "has-tostringtag": "^1.0.0",
+        "is-typed-array": "^1.1.9"
+      }
+    },
+    "word-wrap": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+      "dev": true
+    },
+    "wrap-ansi": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+      "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==",
+      "dev": true,
+      "requires": {
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+          "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+          "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^2.0.0"
+          }
+        }
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+      "dev": true
+    },
+    "write-file-atomic": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+      "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+      "dev": true,
+      "requires": {
+        "imurmurhash": "^0.1.4",
+        "is-typedarray": "^1.0.0",
+        "signal-exit": "^3.0.2",
+        "typedarray-to-buffer": "^3.1.5"
+      }
+    },
+    "xmlcreate": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz",
+      "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==",
+      "dev": true
+    },
+    "xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+      "dev": true
+    },
+    "y18n": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz",
+      "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==",
+      "dev": true
+    },
+    "yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
+    "yargs": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz",
+      "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==",
+      "dev": true,
+      "requires": {
+        "camelcase": "^3.0.0",
+        "cliui": "^3.2.0",
+        "decamelize": "^1.1.1",
+        "get-caller-file": "^1.0.1",
+        "os-locale": "^1.4.0",
+        "read-pkg-up": "^1.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^1.0.1",
+        "set-blocking": "^2.0.0",
+        "string-width": "^1.0.2",
+        "which-module": "^1.0.0",
+        "y18n": "^3.2.1",
+        "yargs-parser": "^5.0.1"
+      },
+      "dependencies": {
+        "camelcase": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+          "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==",
+          "dev": true
+        },
+        "find-up": {
+          "version": "1.1.2",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+          "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==",
+          "dev": true,
+          "requires": {
+            "path-exists": "^2.0.0",
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "hosted-git-info": {
+          "version": "2.8.9",
+          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+          "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+          "dev": true
+        },
+        "normalize-package-data": {
+          "version": "2.5.0",
+          "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+          "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+          "dev": true,
+          "requires": {
+            "hosted-git-info": "^2.1.4",
+            "resolve": "^1.10.0",
+            "semver": "2 || 3 || 4 || 5",
+            "validate-npm-package-license": "^3.0.1"
+          }
+        },
+        "path-exists": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+          "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==",
+          "dev": true,
+          "requires": {
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "path-type": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+          "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "^4.1.2",
+            "pify": "^2.0.0",
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "read-pkg": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+          "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==",
+          "dev": true,
+          "requires": {
+            "load-json-file": "^1.0.0",
+            "normalize-package-data": "^2.3.2",
+            "path-type": "^1.0.0"
+          }
+        },
+        "read-pkg-up": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+          "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==",
+          "dev": true,
+          "requires": {
+            "find-up": "^1.0.0",
+            "read-pkg": "^1.0.0"
+          }
+        },
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        },
+        "yargs-parser": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz",
+          "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==",
+          "dev": true,
+          "requires": {
+            "camelcase": "^3.0.0",
+            "object.assign": "^4.1.0"
+          }
+        }
+      }
+    },
+    "yargs-parser": {
+      "version": "20.2.9",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+      "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+      "dev": true
+    },
+    "yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true
+    }
+  }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..117dff9
--- /dev/null
+++ b/package.json
@@ -0,0 +1,111 @@
+{
+  "name": "protobufjs",
+  "version": "7.2.2",
+  "versionScheme": "~",
+  "description": "Protocol Buffers for JavaScript (& TypeScript).",
+  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
+  "license": "BSD-3-Clause",
+  "repository": "protobufjs/protobuf.js",
+  "bugs": "https://github.com/protobufjs/protobuf.js/issues",
+  "homepage": "https://protobufjs.github.io/protobuf.js/",
+  "engines": {
+    "node": ">=12.0.0"
+  },
+  "eslintConfig": {
+    "env": {
+      "es6": true
+    },
+    "parserOptions": {
+      "ecmaVersion": 6
+    }
+  },
+  "keywords": [
+    "protobuf",
+    "protocol-buffers",
+    "serialization",
+    "typescript"
+  ],
+  "main": "index.js",
+  "types": "index.d.ts",
+  "scripts": {
+    "bench": "node bench",
+    "build": "npm run build:bundle && npm run build:types",
+    "build:bundle": "gulp --gulpfile scripts/gulpfile.js",
+    "build:types": "node cli/bin/pbts --main --global protobuf --out index.d.ts src/ lib/aspromise/index.js lib/base64/index.js lib/codegen/index.js lib/eventemitter/index.js lib/float/index.js lib/fetch/index.js lib/inquire/index.js lib/path/index.js lib/pool/index.js lib/utf8/index.js",
+    "changelog": "node scripts/changelog -w",
+    "coverage": "nyc tape -r ./lib/tape-adapter tests/*.js tests/node/*.js",
+    "docs": "jsdoc -c config/jsdoc.json -R README.md --verbose --pedantic",
+    "lint": "npm run lint:sources && npm run lint:types",
+    "lint:sources": "eslint \"**/*.js\" -c config/eslint.json",
+    "lint:types": "tslint \"**/*.d.ts\" -e \"**/node_modules/**\" -t stylish -c config/tslint.json",
+    "pages": "node scripts/pages",
+    "prepublish": "cd cli && npm install && cd .. && npm run build",
+    "postinstall": "node scripts/postinstall",
+    "prof": "node bench/prof",
+    "test": "npm run test:sources && npm run test:types",
+    "test:sources": "tape -r ./lib/tape-adapter tests/*.js tests/node/*.js",
+    "test:types": "tsc tests/comp_typescript.ts --lib es2015 --esModuleInterop --strictNullChecks --experimentalDecorators --emitDecoratorMetadata && tsc tests/data/test.js.ts --lib es2015 --esModuleInterop --noEmit --strictNullChecks && tsc tests/data/*.ts --lib es2015 --esModuleInterop --noEmit --strictNullChecks",
+    "make": "npm run lint:sources && npm run build && npm run lint:types && node ./scripts/gentests.js && npm test"
+  },
+  "dependencies": {
+    "@protobufjs/aspromise": "^1.1.2",
+    "@protobufjs/base64": "^1.1.2",
+    "@protobufjs/codegen": "^2.0.4",
+    "@protobufjs/eventemitter": "^1.1.0",
+    "@protobufjs/fetch": "^1.1.0",
+    "@protobufjs/float": "^1.0.2",
+    "@protobufjs/inquire": "^1.1.0",
+    "@protobufjs/path": "^1.1.2",
+    "@protobufjs/pool": "^1.1.0",
+    "@protobufjs/utf8": "^1.1.0",
+    "@types/node": ">=13.7.0",
+    "long": "^5.0.0"
+  },
+  "devDependencies": {
+    "benchmark": "^2.1.4",
+    "browserify": "^17.0.0",
+    "browserify-wrap": "^1.0.2",
+    "bundle-collapser": "^1.3.0",
+    "chalk": "^4.0.0",
+    "escodegen": "^1.13.0",
+    "eslint": "^8.15.0",
+    "espree": "^9.0.0",
+    "estraverse": "^5.1.0",
+    "gh-pages": "^4.0.0",
+    "git-raw-commits": "^2.0.3",
+    "git-semver-tags": "^4.0.0",
+    "google-protobuf": "^3.11.3",
+    "gulp": "^4.0.2",
+    "gulp-header": "^2.0.9",
+    "gulp-if": "^3.0.0",
+    "gulp-sourcemaps": "^3.0.0",
+    "gulp-uglify": "^3.0.2",
+    "jaguarjs-jsdoc": "github:dcodeIO/jaguarjs-jsdoc",
+    "jsdoc": "^4.0.0",
+    "minimist": "^1.2.0",
+    "nyc": "^15.0.0",
+    "reflect-metadata": "^0.1.13",
+    "tape": "^5.0.0",
+    "tslint": "^6.0.0",
+    "typescript": "^3.7.5",
+    "uglify-js": "^3.7.7",
+    "vinyl-buffer": "^1.0.1",
+    "vinyl-fs": "^3.0.3",
+    "vinyl-source-stream": "^2.0.0"
+  },
+  "files": [
+    "index.js",
+    "index.d.ts",
+    "light.d.ts",
+    "light.js",
+    "minimal.d.ts",
+    "minimal.js",
+    "package-lock.json",
+    "tsconfig.json",
+    "scripts/postinstall.js",
+    "dist/**",
+    "ext/**",
+    "google/**",
+    "src/**"
+  ]
+}
diff --git a/pbjs.png b/pbjs.png
new file mode 100644
index 0000000..106f03b
--- /dev/null
+++ b/pbjs.png
Binary files differ
diff --git a/pbjs.svg b/pbjs.svg
new file mode 100644
index 0000000..143e05e
--- /dev/null
+++ b/pbjs.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<svg width="102" height="119" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
+ <g>
+  <title>protobuf.js</title>
+  <polygon points="51.039,5.185 97.658,32.723 97.61,86.277 51.055,113.814 4.467,86.734 4.448,32.418 " fill="#FFFFFF" id="background"/>
+  <path d="m51.038,0l-51.038,29.833l0.021,59.5l51.034,29.667l51,-30.167l0.054,-58.666l-51.071,-30.167zm46.572,86.277l-46.556,27.537l-46.587,-27.08l-0.019,-54.316l46.591,-27.233l46.619,27.538l-0.048,53.554z" fill="#171C1E" id="border"/>
+  <polygon points="91.721,49.529 67.825,63.597 67.812,97.283 91.811,83.15 " fill="#1EA8FF" id="blue_front"/>
+  <polygon points="82.002,43.789 91.721,49.529 67.825,63.597 67.812,97.283 56.695,90.821   56.785,58.97 " fill="#50BFFF" id="blue_side"/>
+  <polygon points="78.73,35.486 78.741,41.718 52.8,57.367 52.829,91.787 46.798,95.33   46.777,54.64 " fill="#97FF27" id="green_front"/>
+  <polygon points="68.089,29.2 78.73,35.486 46.777,54.64 46.798,95.33 34.877,88.403   34.859,48.505 " fill="#C2FF72" id="green_side"/>
+  <polygon points="64.764,19.575 64.764,27.088 30.699,47.063 30.699,89.983 24.738,93.451   24.853,43.677 " fill="#FF274B" id="red_front"/>
+  <polygon points="51.736,11.831 10.809,35.674 10.801,85.302 24.82,93.451 24.853,43.677   64.805,19.575 " fill="#FF5C77" id="red_side"/>
+ </g>
+</svg>
\ No newline at end of file
diff --git a/release-please-config.json b/release-please-config.json
new file mode 100644
index 0000000..ee2a5db
--- /dev/null
+++ b/release-please-config.json
@@ -0,0 +1,7 @@
+{
+  "bootstrap-sha": "6fc37d9ea3502cdc08ef988494c041aacd0f7e7f",
+  "packages": {
+    "cli": {},
+    ".": {}
+  }
+}
\ No newline at end of file
diff --git a/renovate.json b/renovate.json
new file mode 100644
index 0000000..61f31b7
--- /dev/null
+++ b/renovate.json
@@ -0,0 +1,18 @@
+{
+  "extends": [
+    "config:base",
+    "docker:disable"
+  ],
+  "pinVersions": false,
+  "rebaseStalePrs": true,
+  "schedule": [
+    "after 9am and before 3pm"
+  ],
+  "gitAuthor": null,
+  "packageRules": [
+    {
+      "extends": "packages:linters",
+      "groupName": "linters"
+    }
+  ]
+}
diff --git a/scripts/bundle.js b/scripts/bundle.js
new file mode 100644
index 0000000..42b7d51
--- /dev/null
+++ b/scripts/bundle.js
@@ -0,0 +1,92 @@
+"use strict";
+module.exports = bundle;
+
+var fs         = require("fs"),
+    path       = require("path");
+
+var browserify = require("browserify");
+
+var header     = require("gulp-header");
+var gulpif     = require("gulp-if");
+var sourcemaps = require("gulp-sourcemaps");
+var uglify     = require("gulp-uglify");
+
+var buffer     = require("vinyl-buffer");
+var vinylfs    = require("vinyl-fs");
+var source     = require("vinyl-source-stream");
+
+var pkg = require(path.join(__dirname, "..", "package.json"));
+
+/*eslint-disable no-template-curly-in-string*/
+var license = [
+    "/*!",
+    " * protobuf.js v${version} (c) 2016, daniel wirtz",
+    " * compiled ${date}",
+    " * licensed under the bsd-3-clause license",
+    " * see: https://github.com/dcodeio/protobuf.js for details",
+    " */"
+].join("\n") + "\n";
+/*eslint-enable no-template-curly-in-string*/
+
+var prelude = fs.readFileSync(require.resolve("../lib/prelude.js")).toString("utf8");
+
+/**
+ * Bundles the library.
+ * @param {Object} options Bundler options
+ * @param {string} options.entry Entry file
+ * @param {string} options.target Target directory
+ * @param {boolean} [options.compress=false] Whether to minify or not
+ * @param {string[]} [options.exclude] Excluded source files
+ * @returns {undefined}
+ */
+function bundle(options) {
+    if (!options || !options.entry || !options.target)
+        throw TypeError("missing options");
+    var bundler = browserify({
+        entries: options.entry,
+        insertGlobalVars: false,
+        detectGlobals: false,
+        debug: true,
+        prelude: prelude,
+        preludePath: "./lib/prelude.js"
+    })
+    .external("long");
+    if (options.exclude)
+        options.exclude.forEach(bundler.exclude, bundler);
+    return bundler
+    .plugin(require("browserify-wrap"), {
+        // undefined var and global strict-mode for uglify
+        prefix: "(function(undefined){\"use strict\";",
+        suffix: "})();"
+    })
+    .plugin(require("bundle-collapser/plugin"))
+    .bundle()
+    .pipe(source(options.compress ? "protobuf.min.js" : "protobuf.js"))
+    .pipe(buffer())
+    .pipe(sourcemaps.init({ loadMaps: true }))
+            .pipe(
+                gulpif(options.compress, uglify({
+                    mangle: {
+                        eval: true,
+                        properties: {
+                            regex: /^_/
+                        }
+                    },
+                    compress: {
+                        keep_fargs: false,
+                        unsafe: true
+                    },
+                    output: {
+                        max_line_len: 0x7fffffff
+                    }
+                }))
+            )
+            .pipe(header(license, {
+                date: (new Date()).toUTCString().replace("GMT", "UTC").toLowerCase(),
+                version: pkg.version
+            }))
+    .pipe(sourcemaps.write(".", { sourceRoot: "" }))
+    .pipe(vinylfs.dest(options.target))
+    .on("log", console.log)
+    .on("error", console.error);
+}
diff --git a/scripts/changelog.js b/scripts/changelog.js
new file mode 100644
index 0000000..7cc7ac4
--- /dev/null
+++ b/scripts/changelog.js
@@ -0,0 +1,150 @@
+"use strict";
+
+var path = require("path"),
+    fs   = require("fs");
+
+var gitSemverTags = require("git-semver-tags"),
+    gitRawCommits = require("git-raw-commits"),
+    minimist      = require("minimist");
+
+var basedir = path.join(__dirname, "..");
+var pkg = require(basedir + "/package.json");
+
+var argv = minimist(process.argv, {
+    alias: {
+        tag    : "t",
+        write  : "w"
+    },
+    string: [ "tag" ],
+    boolean: [ "write" ],
+    default: {
+        tag: null,
+        write: false
+    }
+});
+
+// categories to be used in the future and regexes for lazy / older subjects
+var validCategories = {
+    "Breaking": null,
+    "Fixed": /fix|properly|prevent|correctly/i,
+    "New": /added|initial/i,
+    "CLI": /pbjs|pbts|CLI/,
+    "Docs": /README/i,
+    "Other": null
+};
+var breakingFallback = /removed|stripped|dropped/i;
+
+var repo = "https://github.com/protobufjs/protobuf.js";
+
+gitSemverTags(function(err, tags) {
+    if (err)
+        throw err;
+
+    var categories = {};
+    Object.keys(validCategories).forEach(function(category) {
+        categories[category] = [];
+    });
+    var output = [];
+
+    var from = tags[0];
+    var to = "HEAD";
+    var tag;
+    if (argv.tag) {
+        var idx = tags.indexOf(argv.tag);
+        if (idx < 0)
+            throw Error("no such tag: " + argv.tag);
+        from = tags[idx + 1];
+        tag = to = tags[idx];
+    } else
+        tag = pkg.version;
+
+    var commits = gitRawCommits({
+        from: from,
+        to: to,
+        merges: false,
+        format: "%B%n#%H"
+    });
+
+    commits.on("error", function(err) {
+        throw err;
+    });
+
+    commits.on("data", function(chunk) {
+        var message = chunk.toString("utf8").trim();
+        var match = /##([0-9a-f]{40})$/.exec(message);
+        var hash;
+        if (match) {
+            message = message.substring(0, message.length - match[1].length).trim();
+            hash = match[1];
+        }
+        message.split(";").forEach(function(message) {
+            if (/^(Merge pull request |Post-merge)/.test(message))
+                return;
+            var match = /^(\w+):/i.exec(message = message.trim());
+            var category;
+            if (match && match[1] in validCategories) {
+                category = match[1];
+                message = message.substring(match[1].length + 1).trim();
+            } else {
+                var keys = Object.keys(validCategories);
+                for (var i = 0; i < keys.length; ++i) {
+                    var re = validCategories[keys[i]];
+                    if (re && re.test(message)) {
+                        category = keys[i];
+                        break;
+                    }
+                }
+                message = message.replace(/^(\w+):/i, "").trim();
+            }
+            if (!category) {
+                if (breakingFallback.test(message))
+                    category = "Breaking";
+                else
+                    category = "Other";
+            }
+            var nl = message.indexOf("\n");
+            if (nl > -1)
+                message = message.substring(0, nl).trim();
+            if (!hash || message.length < 12)
+                return;
+            message = message.replace(/\[ci skip\]/, "").trim();
+            categories[category].push({
+                text: message,
+                hash: hash
+            });
+        });
+    });
+
+    commits.on("end", function() {
+        output.push("## [" + tag + "](" + repo + "/releases/tag/" + tag + ")\n");
+        Object.keys(categories).forEach(function(category) {
+            var messages = categories[category];
+            if (!messages.length)
+                return;
+            output.push("\n### " + category + "\n");
+            messages.forEach(function(message) {
+                var text = message.text.replace(/#(\d+)/g, "[#$1](" + repo + "/issues/$1)");
+                output.push("[:hash:](" + repo + "/commit/" + message.hash + ") " + text + "<br />\n");
+            });
+        });
+        var current;
+        try {
+            current = fs.readFileSync(basedir + "/CHANGELOG.md").toString("utf8");
+        } catch (e) {
+            current = "";
+        }
+        var re = new RegExp("^## \\[" + tag + "\\]");
+        if (re.test(current)) { // regenerated, replace
+            var pos = current.indexOf("## [", 1);
+            if (pos > -1)
+                current = current.substring(pos).trim();
+            else
+                current = "";
+        }
+        var contents = output.join("") + "\n" + current;
+        if (argv.write)
+            fs.writeFileSync(basedir + "/CHANGELOG.md", contents, "utf8");
+        else
+            process.stdout.write(contents);
+    });
+});
diff --git a/scripts/gencommons.js b/scripts/gencommons.js
new file mode 100644
index 0000000..b1eecc4
--- /dev/null
+++ b/scripts/gencommons.js
@@ -0,0 +1,25 @@
+"use strict";
+var pbjs = require("../cli/pbjs");
+
+[
+    "google/protobuf/api.proto",
+    "google/protobuf/descriptor.proto",
+    "google/protobuf/source_context.proto",
+    "google/protobuf/type.proto",
+
+    "google/api/annotations.proto",
+    "google/api/http.proto"
+]
+.forEach(function(file) {
+    var out = file.replace(/\.proto$/, ".json");
+    pbjs.main([
+        "--target", "json",
+        "--sparse",
+        "--out", out,
+        file
+    ], function(err) {
+        if (err)
+            throw err;
+        process.stdout.write("pbjs: " + file + " -> " + out + "\n");
+    });
+});
\ No newline at end of file
diff --git a/scripts/gentests.js b/scripts/gentests.js
new file mode 100644
index 0000000..42be124
--- /dev/null
+++ b/scripts/gentests.js
@@ -0,0 +1,70 @@
+"use strict";
+var fs   = require("fs"),
+    path = require("path"),
+    pbjs = require("../cli/pbjs"),
+    pbts = require("../cli/pbts");
+
+[
+    { file: "tests/data/comments.proto", flags: [] },
+    { file: "tests/data/convert.proto", flags: [] },
+    { file: "tests/data/mapbox/vector_tile.proto", flags: [] },
+    { file: "tests/data/package.proto", flags: [] },
+    { file: "tests/data/rpc.proto", flags: [ "es6" ] },
+    { file: "tests/data/rpc.proto", flags: [] },
+    { file: "tests/data/rpc-reserved.proto", flags: [] },
+    { file: "tests/data/test.proto", flags: [] },
+    { file: "tests/data/type_url.proto", flags: [] },
+    { file: "bench/data/bench.proto", flags: ["no-create", "no-verify", "no-delimited", "no-convert", "no-verify", "no-typeurl", "no-comments"], out: "bench/data/static_pbjs.js" }
+]
+.forEach(function({ file, flags, out }) {
+    var basename = file.replace(/\.proto$/, "");
+    if (!out)
+        out = [ basename ].concat(flags).join("-") + ".js";
+    pbjs.main([
+        "--target", "static-module",
+        "--wrap", flags.includes('es6') ? 'es6' : "commonjs",
+        "--root", "test_" + path.basename(basename, ".js"),
+        file
+    ].concat(flags.map(function(flag) {
+        return "--" + flag;
+    })), function(err, output) {
+        if (err)
+            throw err;
+        var pathToProtobufjs = path.relative(path.dirname(out), "minimal").replace(/\\/g, "/");
+        fs.writeFileSync(out, output.replace(/"protobufjs\/minimal"/g, JSON.stringify(pathToProtobufjs)));
+        process.stdout.write("pbjs: " + file + " -> " + out + "\n");
+        try {
+            require(path.join(__dirname, "..", out));
+        } catch (err) {
+            if (!flags.includes("es6")) {
+                process.stderr.write("ERROR: " + err.message + "\n");
+            }
+        }
+    });
+});
+
+process.stdout.write("\n");
+
+[
+    { file: "tests/data/comments.js" },
+    { file: "tests/data/convert.js" },
+    { file: "tests/data/mapbox/vector_tile.js" },
+    { file: "tests/data/package.js" },
+    { file: "tests/data/rpc.js" },
+    { file: "tests/data/rpc-es6.js" },
+    { file: "tests/data/rpc-reserved.js" },
+    { file: "tests/data/test.js" },
+    { file: "ext/descriptor/index.js", ext: true }
+]
+.forEach(function({ file, ext }) {
+    var out = file.replace(/\.js$/, ".d.ts"),
+        args = [ "--no-comments" ];
+    pbts.main(args.concat(file), function(err, output) {
+        if (err)
+            throw err;
+        var pathToProtobufjs = path.relative(path.dirname(out), "").replace(/\\/g, "/");
+        output = output.replace(/"protobufjs"/g, JSON.stringify(pathToProtobufjs));
+        fs.writeFileSync(out, output);
+        process.stdout.write("pbts: " + file + " -> " + out + "\n");
+    });
+});
diff --git a/scripts/gulpfile.js b/scripts/gulpfile.js
new file mode 100644
index 0000000..cad94b4
--- /dev/null
+++ b/scripts/gulpfile.js
@@ -0,0 +1,45 @@
+var gulp   = require("gulp"),
+    bundle = require("./bundle");
+
+function defineTask(name, entry, target) {
+    gulp.task(name + "-bundle", bundle.bind(this, {
+        entry    : entry,
+        target   : target
+    }));
+    gulp.task(name + "-minify", bundle.bind(this, {
+        entry    : entry,
+        target   : target,
+        compress : true
+    }));
+    gulp.task(name, gulp.series(
+        name + "-bundle",
+        name + "-minify"
+    ), function(done) { done(); });
+}
+
+defineTask("full"   , "../src/index"        , "../dist"        );
+defineTask("light"  , "../src/index-light"  , "../dist/light"  );
+defineTask("minimal", "../src/index-minimal", "../dist/minimal");
+
+gulp.task("default", gulp.parallel(
+    "full",
+    "light",
+    "minimal"
+, function(done) { done(); }));
+
+/* var typedoc = require("gulp-typedoc");
+gulp.task("typedoc", function() {
+    return gulp
+        .src(["../index.d.ts"])
+        .pipe(typedoc({
+            module: "commonjs",
+            target: "es5",
+            mode: "file",
+            theme: "default",
+            includeDeclarations: true,
+            excludePrivate: true,
+            out: "../tsdocs",
+            name: "protobuf.js"
+        }))
+}); */
+
diff --git a/scripts/pages.js b/scripts/pages.js
new file mode 100644
index 0000000..e387255
--- /dev/null
+++ b/scripts/pages.js
@@ -0,0 +1,16 @@
+/*eslint-disable no-console*/
+"use strict";
+
+var ghpages = require("gh-pages"),
+    path    = require("path");
+
+ghpages.publish(path.join(__dirname, "..", "docs"), {
+    logger: function(message) {
+        console.log(message);
+    }
+}, function(err) {
+    if (err)
+        console.error(err);
+    else
+        console.log("done");
+});
diff --git a/scripts/postinstall.js b/scripts/postinstall.js
new file mode 100644
index 0000000..bf4ff45
--- /dev/null
+++ b/scripts/postinstall.js
@@ -0,0 +1,32 @@
+"use strict";
+
+var path = require("path"),
+    fs   = require("fs"),
+    pkg  = require(path.join(__dirname, "..", "package.json"));
+
+// check version scheme used by dependents
+if (!pkg.versionScheme)
+    return;
+
+var warn = process.stderr.isTTY
+    ? "\x1b[30m\x1b[43mWARN\x1b[0m \x1b[35m" + path.basename(process.argv[1], ".js") + "\x1b[0m"
+    : "WARN " + path.basename(process.argv[1], ".js");
+
+var basePkg;
+try {
+    basePkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "..", "package.json")));
+} catch (e) {
+    return;
+}
+
+[
+    "dependencies",
+    "devDependencies",
+    "optionalDependencies",
+    "peerDependencies"
+]
+.forEach(function(check) {
+    var version = basePkg && basePkg[check] && basePkg[check][pkg.name];
+    if (typeof version === "string" && version.charAt(0) !== pkg.versionScheme)
+        process.stderr.write(pkg.name + " " + warn + " " + pkg.name + "@" + version + " is configured as a dependency of " + basePkg.name + ". use " + pkg.name + "@" + pkg.versionScheme + version.substring(1) + " instead for API compatibility.\n");
+});
diff --git a/src/common.js b/src/common.js
new file mode 100644
index 0000000..489ee1c
--- /dev/null
+++ b/src/common.js
@@ -0,0 +1,399 @@
+"use strict";
+module.exports = common;
+
+var commonRe = /\/|\./;
+
+/**
+ * Provides common type definitions.
+ * Can also be used to provide additional google types or your own custom types.
+ * @param {string} name Short name as in `google/protobuf/[name].proto` or full file name
+ * @param {Object.<string,*>} json JSON definition within `google.protobuf` if a short name, otherwise the file's root definition
+ * @returns {undefined}
+ * @property {INamespace} google/protobuf/any.proto Any
+ * @property {INamespace} google/protobuf/duration.proto Duration
+ * @property {INamespace} google/protobuf/empty.proto Empty
+ * @property {INamespace} google/protobuf/field_mask.proto FieldMask
+ * @property {INamespace} google/protobuf/struct.proto Struct, Value, NullValue and ListValue
+ * @property {INamespace} google/protobuf/timestamp.proto Timestamp
+ * @property {INamespace} google/protobuf/wrappers.proto Wrappers
+ * @example
+ * // manually provides descriptor.proto (assumes google/protobuf/ namespace and .proto extension)
+ * protobuf.common("descriptor", descriptorJson);
+ *
+ * // manually provides a custom definition (uses my.foo namespace)
+ * protobuf.common("my/foo/bar.proto", myFooBarJson);
+ */
+function common(name, json) {
+    if (!commonRe.test(name)) {
+        name = "google/protobuf/" + name + ".proto";
+        json = { nested: { google: { nested: { protobuf: { nested: json } } } } };
+    }
+    common[name] = json;
+}
+
+// Not provided because of limited use (feel free to discuss or to provide yourself):
+//
+// google/protobuf/descriptor.proto
+// google/protobuf/source_context.proto
+// google/protobuf/type.proto
+//
+// Stripped and pre-parsed versions of these non-bundled files are instead available as part of
+// the repository or package within the google/protobuf directory.
+
+common("any", {
+
+    /**
+     * Properties of a google.protobuf.Any message.
+     * @interface IAny
+     * @type {Object}
+     * @property {string} [typeUrl]
+     * @property {Uint8Array} [bytes]
+     * @memberof common
+     */
+    Any: {
+        fields: {
+            type_url: {
+                type: "string",
+                id: 1
+            },
+            value: {
+                type: "bytes",
+                id: 2
+            }
+        }
+    }
+});
+
+var timeType;
+
+common("duration", {
+
+    /**
+     * Properties of a google.protobuf.Duration message.
+     * @interface IDuration
+     * @type {Object}
+     * @property {number|Long} [seconds]
+     * @property {number} [nanos]
+     * @memberof common
+     */
+    Duration: timeType = {
+        fields: {
+            seconds: {
+                type: "int64",
+                id: 1
+            },
+            nanos: {
+                type: "int32",
+                id: 2
+            }
+        }
+    }
+});
+
+common("timestamp", {
+
+    /**
+     * Properties of a google.protobuf.Timestamp message.
+     * @interface ITimestamp
+     * @type {Object}
+     * @property {number|Long} [seconds]
+     * @property {number} [nanos]
+     * @memberof common
+     */
+    Timestamp: timeType
+});
+
+common("empty", {
+
+    /**
+     * Properties of a google.protobuf.Empty message.
+     * @interface IEmpty
+     * @memberof common
+     */
+    Empty: {
+        fields: {}
+    }
+});
+
+common("struct", {
+
+    /**
+     * Properties of a google.protobuf.Struct message.
+     * @interface IStruct
+     * @type {Object}
+     * @property {Object.<string,IValue>} [fields]
+     * @memberof common
+     */
+    Struct: {
+        fields: {
+            fields: {
+                keyType: "string",
+                type: "Value",
+                id: 1
+            }
+        }
+    },
+
+    /**
+     * Properties of a google.protobuf.Value message.
+     * @interface IValue
+     * @type {Object}
+     * @property {string} [kind]
+     * @property {0} [nullValue]
+     * @property {number} [numberValue]
+     * @property {string} [stringValue]
+     * @property {boolean} [boolValue]
+     * @property {IStruct} [structValue]
+     * @property {IListValue} [listValue]
+     * @memberof common
+     */
+    Value: {
+        oneofs: {
+            kind: {
+                oneof: [
+                    "nullValue",
+                    "numberValue",
+                    "stringValue",
+                    "boolValue",
+                    "structValue",
+                    "listValue"
+                ]
+            }
+        },
+        fields: {
+            nullValue: {
+                type: "NullValue",
+                id: 1
+            },
+            numberValue: {
+                type: "double",
+                id: 2
+            },
+            stringValue: {
+                type: "string",
+                id: 3
+            },
+            boolValue: {
+                type: "bool",
+                id: 4
+            },
+            structValue: {
+                type: "Struct",
+                id: 5
+            },
+            listValue: {
+                type: "ListValue",
+                id: 6
+            }
+        }
+    },
+
+    NullValue: {
+        values: {
+            NULL_VALUE: 0
+        }
+    },
+
+    /**
+     * Properties of a google.protobuf.ListValue message.
+     * @interface IListValue
+     * @type {Object}
+     * @property {Array.<IValue>} [values]
+     * @memberof common
+     */
+    ListValue: {
+        fields: {
+            values: {
+                rule: "repeated",
+                type: "Value",
+                id: 1
+            }
+        }
+    }
+});
+
+common("wrappers", {
+
+    /**
+     * Properties of a google.protobuf.DoubleValue message.
+     * @interface IDoubleValue
+     * @type {Object}
+     * @property {number} [value]
+     * @memberof common
+     */
+    DoubleValue: {
+        fields: {
+            value: {
+                type: "double",
+                id: 1
+            }
+        }
+    },
+
+    /**
+     * Properties of a google.protobuf.FloatValue message.
+     * @interface IFloatValue
+     * @type {Object}
+     * @property {number} [value]
+     * @memberof common
+     */
+    FloatValue: {
+        fields: {
+            value: {
+                type: "float",
+                id: 1
+            }
+        }
+    },
+
+    /**
+     * Properties of a google.protobuf.Int64Value message.
+     * @interface IInt64Value
+     * @type {Object}
+     * @property {number|Long} [value]
+     * @memberof common
+     */
+    Int64Value: {
+        fields: {
+            value: {
+                type: "int64",
+                id: 1
+            }
+        }
+    },
+
+    /**
+     * Properties of a google.protobuf.UInt64Value message.
+     * @interface IUInt64Value
+     * @type {Object}
+     * @property {number|Long} [value]
+     * @memberof common
+     */
+    UInt64Value: {
+        fields: {
+            value: {
+                type: "uint64",
+                id: 1
+            }
+        }
+    },
+
+    /**
+     * Properties of a google.protobuf.Int32Value message.
+     * @interface IInt32Value
+     * @type {Object}
+     * @property {number} [value]
+     * @memberof common
+     */
+    Int32Value: {
+        fields: {
+            value: {
+                type: "int32",
+                id: 1
+            }
+        }
+    },
+
+    /**
+     * Properties of a google.protobuf.UInt32Value message.
+     * @interface IUInt32Value
+     * @type {Object}
+     * @property {number} [value]
+     * @memberof common
+     */
+    UInt32Value: {
+        fields: {
+            value: {
+                type: "uint32",
+                id: 1
+            }
+        }
+    },
+
+    /**
+     * Properties of a google.protobuf.BoolValue message.
+     * @interface IBoolValue
+     * @type {Object}
+     * @property {boolean} [value]
+     * @memberof common
+     */
+    BoolValue: {
+        fields: {
+            value: {
+                type: "bool",
+                id: 1
+            }
+        }
+    },
+
+    /**
+     * Properties of a google.protobuf.StringValue message.
+     * @interface IStringValue
+     * @type {Object}
+     * @property {string} [value]
+     * @memberof common
+     */
+    StringValue: {
+        fields: {
+            value: {
+                type: "string",
+                id: 1
+            }
+        }
+    },
+
+    /**
+     * Properties of a google.protobuf.BytesValue message.
+     * @interface IBytesValue
+     * @type {Object}
+     * @property {Uint8Array} [value]
+     * @memberof common
+     */
+    BytesValue: {
+        fields: {
+            value: {
+                type: "bytes",
+                id: 1
+            }
+        }
+    }
+});
+
+common("field_mask", {
+
+    /**
+     * Properties of a google.protobuf.FieldMask message.
+     * @interface IDoubleValue
+     * @type {Object}
+     * @property {number} [value]
+     * @memberof common
+     */
+    FieldMask: {
+        fields: {
+            paths: {
+                rule: "repeated",
+                type: "string",
+                id: 1
+            }
+        }
+    }
+});
+
+/**
+ * Gets the root definition of the specified common proto file.
+ *
+ * Bundled definitions are:
+ * - google/protobuf/any.proto
+ * - google/protobuf/duration.proto
+ * - google/protobuf/empty.proto
+ * - google/protobuf/field_mask.proto
+ * - google/protobuf/struct.proto
+ * - google/protobuf/timestamp.proto
+ * - google/protobuf/wrappers.proto
+ *
+ * @param {string} file Proto file name
+ * @returns {INamespace|null} Root definition or `null` if not defined
+ */
+common.get = function get(file) {
+    return common[file] || null;
+};
diff --git a/src/converter.js b/src/converter.js
new file mode 100644
index 0000000..c9e68b5
--- /dev/null
+++ b/src/converter.js
@@ -0,0 +1,301 @@
+"use strict";
+/**
+ * Runtime message from/to plain object converters.
+ * @namespace
+ */
+var converter = exports;
+
+var Enum = require("./enum"),
+    util = require("./util");
+
+/**
+ * Generates a partial value fromObject conveter.
+ * @param {Codegen} gen Codegen instance
+ * @param {Field} field Reflected field
+ * @param {number} fieldIndex Field index
+ * @param {string} prop Property reference
+ * @returns {Codegen} Codegen instance
+ * @ignore
+ */
+function genValuePartial_fromObject(gen, field, fieldIndex, prop) {
+    var defaultAlreadyEmitted = false;
+    /* eslint-disable no-unexpected-multiline, block-scoped-var, no-redeclare */
+    if (field.resolvedType) {
+        if (field.resolvedType instanceof Enum) { gen
+            ("switch(d%s){", prop);
+            for (var values = field.resolvedType.values, keys = Object.keys(values), i = 0; i < keys.length; ++i) {
+                // enum unknown values passthrough
+                if (values[keys[i]] === field.typeDefault && !defaultAlreadyEmitted) { gen
+                    ("default:")
+                        ("if(typeof(d%s)===\"number\"){m%s=d%s;break}", prop, prop, prop);
+                    if (!field.repeated) gen // fallback to default value only for
+                                             // arrays, to avoid leaving holes.
+                        ("break");           // for non-repeated fields, just ignore
+                    defaultAlreadyEmitted = true;
+                }
+                gen
+                ("case%j:", keys[i])
+                ("case %i:", values[keys[i]])
+                    ("m%s=%j", prop, values[keys[i]])
+                    ("break");
+            } gen
+            ("}");
+        } else gen
+            ("if(typeof d%s!==\"object\")", prop)
+                ("throw TypeError(%j)", field.fullName + ": object expected")
+            ("m%s=types[%i].fromObject(d%s)", prop, fieldIndex, prop);
+    } else {
+        var isUnsigned = false;
+        switch (field.type) {
+            case "double":
+            case "float": gen
+                ("m%s=Number(d%s)", prop, prop); // also catches "NaN", "Infinity"
+                break;
+            case "uint32":
+            case "fixed32": gen
+                ("m%s=d%s>>>0", prop, prop);
+                break;
+            case "int32":
+            case "sint32":
+            case "sfixed32": gen
+                ("m%s=d%s|0", prop, prop);
+                break;
+            case "uint64":
+                isUnsigned = true;
+                // eslint-disable-line no-fallthrough
+            case "int64":
+            case "sint64":
+            case "fixed64":
+            case "sfixed64": gen
+                ("if(util.Long)")
+                    ("(m%s=util.Long.fromValue(d%s)).unsigned=%j", prop, prop, isUnsigned)
+                ("else if(typeof d%s===\"string\")", prop)
+                    ("m%s=parseInt(d%s,10)", prop, prop)
+                ("else if(typeof d%s===\"number\")", prop)
+                    ("m%s=d%s", prop, prop)
+                ("else if(typeof d%s===\"object\")", prop)
+                    ("m%s=new util.LongBits(d%s.low>>>0,d%s.high>>>0).toNumber(%s)", prop, prop, prop, isUnsigned ? "true" : "");
+                break;
+            case "bytes": gen
+                ("if(typeof d%s===\"string\")", prop)
+                    ("util.base64.decode(d%s,m%s=util.newBuffer(util.base64.length(d%s)),0)", prop, prop, prop)
+                ("else if(d%s.length >= 0)", prop)
+                    ("m%s=d%s", prop, prop);
+                break;
+            case "string": gen
+                ("m%s=String(d%s)", prop, prop);
+                break;
+            case "bool": gen
+                ("m%s=Boolean(d%s)", prop, prop);
+                break;
+            /* default: gen
+                ("m%s=d%s", prop, prop);
+                break; */
+        }
+    }
+    return gen;
+    /* eslint-enable no-unexpected-multiline, block-scoped-var, no-redeclare */
+}
+
+/**
+ * Generates a plain object to runtime message converter specific to the specified message type.
+ * @param {Type} mtype Message type
+ * @returns {Codegen} Codegen instance
+ */
+converter.fromObject = function fromObject(mtype) {
+    /* eslint-disable no-unexpected-multiline, block-scoped-var, no-redeclare */
+    var fields = mtype.fieldsArray;
+    var gen = util.codegen(["d"], mtype.name + "$fromObject")
+    ("if(d instanceof this.ctor)")
+        ("return d");
+    if (!fields.length) return gen
+    ("return new this.ctor");
+    gen
+    ("var m=new this.ctor");
+    for (var i = 0; i < fields.length; ++i) {
+        var field  = fields[i].resolve(),
+            prop   = util.safeProp(field.name);
+
+        // Map fields
+        if (field.map) { gen
+    ("if(d%s){", prop)
+        ("if(typeof d%s!==\"object\")", prop)
+            ("throw TypeError(%j)", field.fullName + ": object expected")
+        ("m%s={}", prop)
+        ("for(var ks=Object.keys(d%s),i=0;i<ks.length;++i){", prop);
+            genValuePartial_fromObject(gen, field, /* not sorted */ i, prop + "[ks[i]]")
+        ("}")
+    ("}");
+
+        // Repeated fields
+        } else if (field.repeated) { gen
+    ("if(d%s){", prop)
+        ("if(!Array.isArray(d%s))", prop)
+            ("throw TypeError(%j)", field.fullName + ": array expected")
+        ("m%s=[]", prop)
+        ("for(var i=0;i<d%s.length;++i){", prop);
+            genValuePartial_fromObject(gen, field, /* not sorted */ i, prop + "[i]")
+        ("}")
+    ("}");
+
+        // Non-repeated fields
+        } else {
+            if (!(field.resolvedType instanceof Enum)) gen // no need to test for null/undefined if an enum (uses switch)
+    ("if(d%s!=null){", prop); // !== undefined && !== null
+        genValuePartial_fromObject(gen, field, /* not sorted */ i, prop);
+            if (!(field.resolvedType instanceof Enum)) gen
+    ("}");
+        }
+    } return gen
+    ("return m");
+    /* eslint-enable no-unexpected-multiline, block-scoped-var, no-redeclare */
+};
+
+/**
+ * Generates a partial value toObject converter.
+ * @param {Codegen} gen Codegen instance
+ * @param {Field} field Reflected field
+ * @param {number} fieldIndex Field index
+ * @param {string} prop Property reference
+ * @returns {Codegen} Codegen instance
+ * @ignore
+ */
+function genValuePartial_toObject(gen, field, fieldIndex, prop) {
+    /* eslint-disable no-unexpected-multiline, block-scoped-var, no-redeclare */
+    if (field.resolvedType) {
+        if (field.resolvedType instanceof Enum) gen
+            ("d%s=o.enums===String?(types[%i].values[m%s]===undefined?m%s:types[%i].values[m%s]):m%s", prop, fieldIndex, prop, prop, fieldIndex, prop, prop);
+        else gen
+            ("d%s=types[%i].toObject(m%s,o)", prop, fieldIndex, prop);
+    } else {
+        var isUnsigned = false;
+        switch (field.type) {
+            case "double":
+            case "float": gen
+            ("d%s=o.json&&!isFinite(m%s)?String(m%s):m%s", prop, prop, prop, prop);
+                break;
+            case "uint64":
+                isUnsigned = true;
+                // eslint-disable-line no-fallthrough
+            case "int64":
+            case "sint64":
+            case "fixed64":
+            case "sfixed64": gen
+            ("if(typeof m%s===\"number\")", prop)
+                ("d%s=o.longs===String?String(m%s):m%s", prop, prop, prop)
+            ("else") // Long-like
+                ("d%s=o.longs===String?util.Long.prototype.toString.call(m%s):o.longs===Number?new util.LongBits(m%s.low>>>0,m%s.high>>>0).toNumber(%s):m%s", prop, prop, prop, prop, isUnsigned ? "true": "", prop);
+                break;
+            case "bytes": gen
+            ("d%s=o.bytes===String?util.base64.encode(m%s,0,m%s.length):o.bytes===Array?Array.prototype.slice.call(m%s):m%s", prop, prop, prop, prop, prop);
+                break;
+            default: gen
+            ("d%s=m%s", prop, prop);
+                break;
+        }
+    }
+    return gen;
+    /* eslint-enable no-unexpected-multiline, block-scoped-var, no-redeclare */
+}
+
+/**
+ * Generates a runtime message to plain object converter specific to the specified message type.
+ * @param {Type} mtype Message type
+ * @returns {Codegen} Codegen instance
+ */
+converter.toObject = function toObject(mtype) {
+    /* eslint-disable no-unexpected-multiline, block-scoped-var, no-redeclare */
+    var fields = mtype.fieldsArray.slice().sort(util.compareFieldsById);
+    if (!fields.length)
+        return util.codegen()("return {}");
+    var gen = util.codegen(["m", "o"], mtype.name + "$toObject")
+    ("if(!o)")
+        ("o={}")
+    ("var d={}");
+
+    var repeatedFields = [],
+        mapFields = [],
+        normalFields = [],
+        i = 0;
+    for (; i < fields.length; ++i)
+        if (!fields[i].partOf)
+            ( fields[i].resolve().repeated ? repeatedFields
+            : fields[i].map ? mapFields
+            : normalFields).push(fields[i]);
+
+    if (repeatedFields.length) { gen
+    ("if(o.arrays||o.defaults){");
+        for (i = 0; i < repeatedFields.length; ++i) gen
+        ("d%s=[]", util.safeProp(repeatedFields[i].name));
+        gen
+    ("}");
+    }
+
+    if (mapFields.length) { gen
+    ("if(o.objects||o.defaults){");
+        for (i = 0; i < mapFields.length; ++i) gen
+        ("d%s={}", util.safeProp(mapFields[i].name));
+        gen
+    ("}");
+    }
+
+    if (normalFields.length) { gen
+    ("if(o.defaults){");
+        for (i = 0; i < normalFields.length; ++i) {
+            var field = normalFields[i],
+                prop  = util.safeProp(field.name);
+            if (field.resolvedType instanceof Enum) gen
+        ("d%s=o.enums===String?%j:%j", prop, field.resolvedType.valuesById[field.typeDefault], field.typeDefault);
+            else if (field.long) gen
+        ("if(util.Long){")
+            ("var n=new util.Long(%i,%i,%j)", field.typeDefault.low, field.typeDefault.high, field.typeDefault.unsigned)
+            ("d%s=o.longs===String?n.toString():o.longs===Number?n.toNumber():n", prop)
+        ("}else")
+            ("d%s=o.longs===String?%j:%i", prop, field.typeDefault.toString(), field.typeDefault.toNumber());
+            else if (field.bytes) {
+                var arrayDefault = "[" + Array.prototype.slice.call(field.typeDefault).join(",") + "]";
+                gen
+        ("if(o.bytes===String)d%s=%j", prop, String.fromCharCode.apply(String, field.typeDefault))
+        ("else{")
+            ("d%s=%s", prop, arrayDefault)
+            ("if(o.bytes!==Array)d%s=util.newBuffer(d%s)", prop, prop)
+        ("}");
+            } else gen
+        ("d%s=%j", prop, field.typeDefault); // also messages (=null)
+        } gen
+    ("}");
+    }
+    var hasKs2 = false;
+    for (i = 0; i < fields.length; ++i) {
+        var field = fields[i],
+            index = mtype._fieldsArray.indexOf(field),
+            prop  = util.safeProp(field.name);
+        if (field.map) {
+            if (!hasKs2) { hasKs2 = true; gen
+    ("var ks2");
+            } gen
+    ("if(m%s&&(ks2=Object.keys(m%s)).length){", prop, prop)
+        ("d%s={}", prop)
+        ("for(var j=0;j<ks2.length;++j){");
+            genValuePartial_toObject(gen, field, /* sorted */ index, prop + "[ks2[j]]")
+        ("}");
+        } else if (field.repeated) { gen
+    ("if(m%s&&m%s.length){", prop, prop)
+        ("d%s=[]", prop)
+        ("for(var j=0;j<m%s.length;++j){", prop);
+            genValuePartial_toObject(gen, field, /* sorted */ index, prop + "[j]")
+        ("}");
+        } else { gen
+    ("if(m%s!=null&&m.hasOwnProperty(%j)){", prop, field.name); // !== undefined && !== null
+        genValuePartial_toObject(gen, field, /* sorted */ index, prop);
+        if (field.partOf) gen
+        ("if(o.oneofs)")
+            ("d%s=%j", util.safeProp(field.partOf.name), field.name);
+        }
+        gen
+    ("}");
+    }
+    return gen
+    ("return d");
+    /* eslint-enable no-unexpected-multiline, block-scoped-var, no-redeclare */
+};
diff --git a/src/decoder.js b/src/decoder.js
new file mode 100644
index 0000000..f55451f
--- /dev/null
+++ b/src/decoder.js
@@ -0,0 +1,129 @@
+"use strict";
+module.exports = decoder;
+
+var Enum    = require("./enum"),
+    types   = require("./types"),
+    util    = require("./util");
+
+function missing(field) {
+    return "missing required '" + field.name + "'";
+}
+
+/**
+ * Generates a decoder specific to the specified message type.
+ * @param {Type} mtype Message type
+ * @returns {Codegen} Codegen instance
+ */
+function decoder(mtype) {
+    /* eslint-disable no-unexpected-multiline */
+    var gen = util.codegen(["r", "l"], mtype.name + "$decode")
+    ("if(!(r instanceof Reader))")
+        ("r=Reader.create(r)")
+    ("var c=l===undefined?r.len:r.pos+l,m=new this.ctor" + (mtype.fieldsArray.filter(function(field) { return field.map; }).length ? ",k,value" : ""))
+    ("while(r.pos<c){")
+        ("var t=r.uint32()");
+    if (mtype.group) gen
+        ("if((t&7)===4)")
+            ("break");
+    gen
+        ("switch(t>>>3){");
+
+    var i = 0;
+    for (; i < /* initializes */ mtype.fieldsArray.length; ++i) {
+        var field = mtype._fieldsArray[i].resolve(),
+            type  = field.resolvedType instanceof Enum ? "int32" : field.type,
+            ref   = "m" + util.safeProp(field.name); gen
+            ("case %i: {", field.id);
+
+        // Map fields
+        if (field.map) { gen
+                ("if(%s===util.emptyObject)", ref)
+                    ("%s={}", ref)
+                ("var c2 = r.uint32()+r.pos");
+
+            if (types.defaults[field.keyType] !== undefined) gen
+                ("k=%j", types.defaults[field.keyType]);
+            else gen
+                ("k=null");
+
+            if (types.defaults[type] !== undefined) gen
+                ("value=%j", types.defaults[type]);
+            else gen
+                ("value=null");
+
+            gen
+                ("while(r.pos<c2){")
+                    ("var tag2=r.uint32()")
+                    ("switch(tag2>>>3){")
+                        ("case 1: k=r.%s(); break", field.keyType)
+                        ("case 2:");
+
+            if (types.basic[type] === undefined) gen
+                            ("value=types[%i].decode(r,r.uint32())", i); // can't be groups
+            else gen
+                            ("value=r.%s()", type);
+
+            gen
+                            ("break")
+                        ("default:")
+                            ("r.skipType(tag2&7)")
+                            ("break")
+                    ("}")
+                ("}");
+
+            if (types.long[field.keyType] !== undefined) gen
+                ("%s[typeof k===\"object\"?util.longToHash(k):k]=value", ref);
+            else gen
+                ("%s[k]=value", ref);
+
+        // Repeated fields
+        } else if (field.repeated) { gen
+
+                ("if(!(%s&&%s.length))", ref, ref)
+                    ("%s=[]", ref);
+
+            // Packable (always check for forward and backward compatiblity)
+            if (types.packed[type] !== undefined) gen
+                ("if((t&7)===2){")
+                    ("var c2=r.uint32()+r.pos")
+                    ("while(r.pos<c2)")
+                        ("%s.push(r.%s())", ref, type)
+                ("}else");
+
+            // Non-packed
+            if (types.basic[type] === undefined) gen(field.resolvedType.group
+                    ? "%s.push(types[%i].decode(r))"
+                    : "%s.push(types[%i].decode(r,r.uint32()))", ref, i);
+            else gen
+                    ("%s.push(r.%s())", ref, type);
+
+        // Non-repeated
+        } else if (types.basic[type] === undefined) gen(field.resolvedType.group
+                ? "%s=types[%i].decode(r)"
+                : "%s=types[%i].decode(r,r.uint32())", ref, i);
+        else gen
+                ("%s=r.%s()", ref, type);
+        gen
+                ("break")
+            ("}");
+        // Unknown fields
+    } gen
+            ("default:")
+                ("r.skipType(t&7)")
+                ("break")
+
+        ("}")
+    ("}");
+
+    // Field presence
+    for (i = 0; i < mtype._fieldsArray.length; ++i) {
+        var rfield = mtype._fieldsArray[i];
+        if (rfield.required) gen
+    ("if(!m.hasOwnProperty(%j))", rfield.name)
+        ("throw util.ProtocolError(%j,{instance:m})", missing(rfield));
+    }
+
+    return gen
+    ("return m");
+    /* eslint-enable no-unexpected-multiline */
+}
diff --git a/src/encoder.js b/src/encoder.js
new file mode 100644
index 0000000..c803e99
--- /dev/null
+++ b/src/encoder.js
@@ -0,0 +1,100 @@
+"use strict";
+module.exports = encoder;
+
+var Enum     = require("./enum"),
+    types    = require("./types"),
+    util     = require("./util");
+
+/**
+ * Generates a partial message type encoder.
+ * @param {Codegen} gen Codegen instance
+ * @param {Field} field Reflected field
+ * @param {number} fieldIndex Field index
+ * @param {string} ref Variable reference
+ * @returns {Codegen} Codegen instance
+ * @ignore
+ */
+function genTypePartial(gen, field, fieldIndex, ref) {
+    return field.resolvedType.group
+        ? gen("types[%i].encode(%s,w.uint32(%i)).uint32(%i)", fieldIndex, ref, (field.id << 3 | 3) >>> 0, (field.id << 3 | 4) >>> 0)
+        : gen("types[%i].encode(%s,w.uint32(%i).fork()).ldelim()", fieldIndex, ref, (field.id << 3 | 2) >>> 0);
+}
+
+/**
+ * Generates an encoder specific to the specified message type.
+ * @param {Type} mtype Message type
+ * @returns {Codegen} Codegen instance
+ */
+function encoder(mtype) {
+    /* eslint-disable no-unexpected-multiline, block-scoped-var, no-redeclare */
+    var gen = util.codegen(["m", "w"], mtype.name + "$encode")
+    ("if(!w)")
+        ("w=Writer.create()");
+
+    var i, ref;
+
+    // "when a message is serialized its known fields should be written sequentially by field number"
+    var fields = /* initializes */ mtype.fieldsArray.slice().sort(util.compareFieldsById);
+
+    for (var i = 0; i < fields.length; ++i) {
+        var field    = fields[i].resolve(),
+            index    = mtype._fieldsArray.indexOf(field),
+            type     = field.resolvedType instanceof Enum ? "int32" : field.type,
+            wireType = types.basic[type];
+            ref      = "m" + util.safeProp(field.name);
+
+        // Map fields
+        if (field.map) {
+            gen
+    ("if(%s!=null&&Object.hasOwnProperty.call(m,%j)){", ref, field.name) // !== undefined && !== null
+        ("for(var ks=Object.keys(%s),i=0;i<ks.length;++i){", ref)
+            ("w.uint32(%i).fork().uint32(%i).%s(ks[i])", (field.id << 3 | 2) >>> 0, 8 | types.mapKey[field.keyType], field.keyType);
+            if (wireType === undefined) gen
+            ("types[%i].encode(%s[ks[i]],w.uint32(18).fork()).ldelim().ldelim()", index, ref); // can't be groups
+            else gen
+            (".uint32(%i).%s(%s[ks[i]]).ldelim()", 16 | wireType, type, ref);
+            gen
+        ("}")
+    ("}");
+
+            // Repeated fields
+        } else if (field.repeated) { gen
+    ("if(%s!=null&&%s.length){", ref, ref); // !== undefined && !== null
+
+            // Packed repeated
+            if (field.packed && types.packed[type] !== undefined) { gen
+
+        ("w.uint32(%i).fork()", (field.id << 3 | 2) >>> 0)
+        ("for(var i=0;i<%s.length;++i)", ref)
+            ("w.%s(%s[i])", type, ref)
+        ("w.ldelim()");
+
+            // Non-packed
+            } else { gen
+
+        ("for(var i=0;i<%s.length;++i)", ref);
+                if (wireType === undefined)
+            genTypePartial(gen, field, index, ref + "[i]");
+                else gen
+            ("w.uint32(%i).%s(%s[i])", (field.id << 3 | wireType) >>> 0, type, ref);
+
+            } gen
+    ("}");
+
+        // Non-repeated
+        } else {
+            if (field.optional) gen
+    ("if(%s!=null&&Object.hasOwnProperty.call(m,%j))", ref, field.name); // !== undefined && !== null
+
+            if (wireType === undefined)
+        genTypePartial(gen, field, index, ref);
+            else gen
+        ("w.uint32(%i).%s(%s)", (field.id << 3 | wireType) >>> 0, type, ref);
+
+        }
+    }
+
+    return gen
+    ("return w");
+    /* eslint-enable no-unexpected-multiline, block-scoped-var, no-redeclare */
+}
diff --git a/src/enum.js b/src/enum.js
new file mode 100644
index 0000000..1c01620
--- /dev/null
+++ b/src/enum.js
@@ -0,0 +1,198 @@
+"use strict";
+module.exports = Enum;
+
+// extends ReflectionObject
+var ReflectionObject = require("./object");
+((Enum.prototype = Object.create(ReflectionObject.prototype)).constructor = Enum).className = "Enum";
+
+var Namespace = require("./namespace"),
+    util = require("./util");
+
+/**
+ * Constructs a new enum instance.
+ * @classdesc Reflected enum.
+ * @extends ReflectionObject
+ * @constructor
+ * @param {string} name Unique name within its namespace
+ * @param {Object.<string,number>} [values] Enum values as an object, by name
+ * @param {Object.<string,*>} [options] Declared options
+ * @param {string} [comment] The comment for this enum
+ * @param {Object.<string,string>} [comments] The value comments for this enum
+ * @param {Object.<string,Object<string,*>>|undefined} [valuesOptions] The value options for this enum
+ */
+function Enum(name, values, options, comment, comments, valuesOptions) {
+    ReflectionObject.call(this, name, options);
+
+    if (values && typeof values !== "object")
+        throw TypeError("values must be an object");
+
+    /**
+     * Enum values by id.
+     * @type {Object.<number,string>}
+     */
+    this.valuesById = {};
+
+    /**
+     * Enum values by name.
+     * @type {Object.<string,number>}
+     */
+    this.values = Object.create(this.valuesById); // toJSON, marker
+
+    /**
+     * Enum comment text.
+     * @type {string|null}
+     */
+    this.comment = comment;
+
+    /**
+     * Value comment texts, if any.
+     * @type {Object.<string,string>}
+     */
+    this.comments = comments || {};
+
+    /**
+     * Values options, if any
+     * @type {Object<string, Object<string, *>>|undefined}
+     */
+    this.valuesOptions = valuesOptions;
+
+    /**
+     * Reserved ranges, if any.
+     * @type {Array.<number[]|string>}
+     */
+    this.reserved = undefined; // toJSON
+
+    // Note that values inherit valuesById on their prototype which makes them a TypeScript-
+    // compatible enum. This is used by pbts to write actual enum definitions that work for
+    // static and reflection code alike instead of emitting generic object definitions.
+
+    if (values)
+        for (var keys = Object.keys(values), i = 0; i < keys.length; ++i)
+            if (typeof values[keys[i]] === "number") // use forward entries only
+                this.valuesById[ this.values[keys[i]] = values[keys[i]] ] = keys[i];
+}
+
+/**
+ * Enum descriptor.
+ * @interface IEnum
+ * @property {Object.<string,number>} values Enum values
+ * @property {Object.<string,*>} [options] Enum options
+ */
+
+/**
+ * Constructs an enum from an enum descriptor.
+ * @param {string} name Enum name
+ * @param {IEnum} json Enum descriptor
+ * @returns {Enum} Created enum
+ * @throws {TypeError} If arguments are invalid
+ */
+Enum.fromJSON = function fromJSON(name, json) {
+    var enm = new Enum(name, json.values, json.options, json.comment, json.comments);
+    enm.reserved = json.reserved;
+    return enm;
+};
+
+/**
+ * Converts this enum to an enum descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {IEnum} Enum descriptor
+ */
+Enum.prototype.toJSON = function toJSON(toJSONOptions) {
+    var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
+    return util.toObject([
+        "options"       , this.options,
+        "valuesOptions" , this.valuesOptions,
+        "values"        , this.values,
+        "reserved"      , this.reserved && this.reserved.length ? this.reserved : undefined,
+        "comment"       , keepComments ? this.comment : undefined,
+        "comments"      , keepComments ? this.comments : undefined
+    ]);
+};
+
+/**
+ * Adds a value to this enum.
+ * @param {string} name Value name
+ * @param {number} id Value id
+ * @param {string} [comment] Comment, if any
+ * @param {Object.<string, *>|undefined} [options] Options, if any
+ * @returns {Enum} `this`
+ * @throws {TypeError} If arguments are invalid
+ * @throws {Error} If there is already a value with this name or id
+ */
+Enum.prototype.add = function add(name, id, comment, options) {
+    // utilized by the parser but not by .fromJSON
+
+    if (!util.isString(name))
+        throw TypeError("name must be a string");
+
+    if (!util.isInteger(id))
+        throw TypeError("id must be an integer");
+
+    if (this.values[name] !== undefined)
+        throw Error("duplicate name '" + name + "' in " + this);
+
+    if (this.isReservedId(id))
+        throw Error("id " + id + " is reserved in " + this);
+
+    if (this.isReservedName(name))
+        throw Error("name '" + name + "' is reserved in " + this);
+
+    if (this.valuesById[id] !== undefined) {
+        if (!(this.options && this.options.allow_alias))
+            throw Error("duplicate id " + id + " in " + this);
+        this.values[name] = id;
+    } else
+        this.valuesById[this.values[name] = id] = name;
+
+    if (options) {
+        if (this.valuesOptions === undefined)
+            this.valuesOptions = {};
+        this.valuesOptions[name] = options || null;
+    }
+
+    this.comments[name] = comment || null;
+    return this;
+};
+
+/**
+ * Removes a value from this enum
+ * @param {string} name Value name
+ * @returns {Enum} `this`
+ * @throws {TypeError} If arguments are invalid
+ * @throws {Error} If `name` is not a name of this enum
+ */
+Enum.prototype.remove = function remove(name) {
+
+    if (!util.isString(name))
+        throw TypeError("name must be a string");
+
+    var val = this.values[name];
+    if (val == null)
+        throw Error("name '" + name + "' does not exist in " + this);
+
+    delete this.valuesById[val];
+    delete this.values[name];
+    delete this.comments[name];
+    if (this.valuesOptions)
+        delete this.valuesOptions[name];
+
+    return this;
+};
+
+/**
+ * Tests if the specified id is reserved.
+ * @param {number} id Id to test
+ * @returns {boolean} `true` if reserved, otherwise `false`
+ */
+Enum.prototype.isReservedId = function isReservedId(id) {
+    return Namespace.isReservedId(this.reserved, id);
+};
+
+/**
+ * Tests if the specified name is reserved.
+ * @param {string} name Name to test
+ * @returns {boolean} `true` if reserved, otherwise `false`
+ */
+Enum.prototype.isReservedName = function isReservedName(name) {
+    return Namespace.isReservedName(this.reserved, name);
+};
diff --git a/src/field.js b/src/field.js
new file mode 100644
index 0000000..e0feb8b
--- /dev/null
+++ b/src/field.js
@@ -0,0 +1,377 @@
+"use strict";
+module.exports = Field;
+
+// extends ReflectionObject
+var ReflectionObject = require("./object");
+((Field.prototype = Object.create(ReflectionObject.prototype)).constructor = Field).className = "Field";
+
+var Enum  = require("./enum"),
+    types = require("./types"),
+    util  = require("./util");
+
+var Type; // cyclic
+
+var ruleRe = /^required|optional|repeated$/;
+
+/**
+ * Constructs a new message field instance. Note that {@link MapField|map fields} have their own class.
+ * @name Field
+ * @classdesc Reflected message field.
+ * @extends FieldBase
+ * @constructor
+ * @param {string} name Unique name within its namespace
+ * @param {number} id Unique id within its namespace
+ * @param {string} type Value type
+ * @param {string|Object.<string,*>} [rule="optional"] Field rule
+ * @param {string|Object.<string,*>} [extend] Extended type if different from parent
+ * @param {Object.<string,*>} [options] Declared options
+ */
+
+/**
+ * Constructs a field from a field descriptor.
+ * @param {string} name Field name
+ * @param {IField} json Field descriptor
+ * @returns {Field} Created field
+ * @throws {TypeError} If arguments are invalid
+ */
+Field.fromJSON = function fromJSON(name, json) {
+    return new Field(name, json.id, json.type, json.rule, json.extend, json.options, json.comment);
+};
+
+/**
+ * Not an actual constructor. Use {@link Field} instead.
+ * @classdesc Base class of all reflected message fields. This is not an actual class but here for the sake of having consistent type definitions.
+ * @exports FieldBase
+ * @extends ReflectionObject
+ * @constructor
+ * @param {string} name Unique name within its namespace
+ * @param {number} id Unique id within its namespace
+ * @param {string} type Value type
+ * @param {string|Object.<string,*>} [rule="optional"] Field rule
+ * @param {string|Object.<string,*>} [extend] Extended type if different from parent
+ * @param {Object.<string,*>} [options] Declared options
+ * @param {string} [comment] Comment associated with this field
+ */
+function Field(name, id, type, rule, extend, options, comment) {
+
+    if (util.isObject(rule)) {
+        comment = extend;
+        options = rule;
+        rule = extend = undefined;
+    } else if (util.isObject(extend)) {
+        comment = options;
+        options = extend;
+        extend = undefined;
+    }
+
+    ReflectionObject.call(this, name, options);
+
+    if (!util.isInteger(id) || id < 0)
+        throw TypeError("id must be a non-negative integer");
+
+    if (!util.isString(type))
+        throw TypeError("type must be a string");
+
+    if (rule !== undefined && !ruleRe.test(rule = rule.toString().toLowerCase()))
+        throw TypeError("rule must be a string rule");
+
+    if (extend !== undefined && !util.isString(extend))
+        throw TypeError("extend must be a string");
+
+    /**
+     * Field rule, if any.
+     * @type {string|undefined}
+     */
+    if (rule === "proto3_optional") {
+        rule = "optional";
+    }
+    this.rule = rule && rule !== "optional" ? rule : undefined; // toJSON
+
+    /**
+     * Field type.
+     * @type {string}
+     */
+    this.type = type; // toJSON
+
+    /**
+     * Unique field id.
+     * @type {number}
+     */
+    this.id = id; // toJSON, marker
+
+    /**
+     * Extended type if different from parent.
+     * @type {string|undefined}
+     */
+    this.extend = extend || undefined; // toJSON
+
+    /**
+     * Whether this field is required.
+     * @type {boolean}
+     */
+    this.required = rule === "required";
+
+    /**
+     * Whether this field is optional.
+     * @type {boolean}
+     */
+    this.optional = !this.required;
+
+    /**
+     * Whether this field is repeated.
+     * @type {boolean}
+     */
+    this.repeated = rule === "repeated";
+
+    /**
+     * Whether this field is a map or not.
+     * @type {boolean}
+     */
+    this.map = false;
+
+    /**
+     * Message this field belongs to.
+     * @type {Type|null}
+     */
+    this.message = null;
+
+    /**
+     * OneOf this field belongs to, if any,
+     * @type {OneOf|null}
+     */
+    this.partOf = null;
+
+    /**
+     * The field type's default value.
+     * @type {*}
+     */
+    this.typeDefault = null;
+
+    /**
+     * The field's default value on prototypes.
+     * @type {*}
+     */
+    this.defaultValue = null;
+
+    /**
+     * Whether this field's value should be treated as a long.
+     * @type {boolean}
+     */
+    this.long = util.Long ? types.long[type] !== undefined : /* istanbul ignore next */ false;
+
+    /**
+     * Whether this field's value is a buffer.
+     * @type {boolean}
+     */
+    this.bytes = type === "bytes";
+
+    /**
+     * Resolved type if not a basic type.
+     * @type {Type|Enum|null}
+     */
+    this.resolvedType = null;
+
+    /**
+     * Sister-field within the extended type if a declaring extension field.
+     * @type {Field|null}
+     */
+    this.extensionField = null;
+
+    /**
+     * Sister-field within the declaring namespace if an extended field.
+     * @type {Field|null}
+     */
+    this.declaringField = null;
+
+    /**
+     * Internally remembers whether this field is packed.
+     * @type {boolean|null}
+     * @private
+     */
+    this._packed = null;
+
+    /**
+     * Comment for this field.
+     * @type {string|null}
+     */
+    this.comment = comment;
+}
+
+/**
+ * Determines whether this field is packed. Only relevant when repeated and working with proto2.
+ * @name Field#packed
+ * @type {boolean}
+ * @readonly
+ */
+Object.defineProperty(Field.prototype, "packed", {
+    get: function() {
+        // defaults to packed=true if not explicity set to false
+        if (this._packed === null)
+            this._packed = this.getOption("packed") !== false;
+        return this._packed;
+    }
+});
+
+/**
+ * @override
+ */
+Field.prototype.setOption = function setOption(name, value, ifNotSet) {
+    if (name === "packed") // clear cached before setting
+        this._packed = null;
+    return ReflectionObject.prototype.setOption.call(this, name, value, ifNotSet);
+};
+
+/**
+ * Field descriptor.
+ * @interface IField
+ * @property {string} [rule="optional"] Field rule
+ * @property {string} type Field type
+ * @property {number} id Field id
+ * @property {Object.<string,*>} [options] Field options
+ */
+
+/**
+ * Extension field descriptor.
+ * @interface IExtensionField
+ * @extends IField
+ * @property {string} extend Extended type
+ */
+
+/**
+ * Converts this field to a field descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {IField} Field descriptor
+ */
+Field.prototype.toJSON = function toJSON(toJSONOptions) {
+    var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
+    return util.toObject([
+        "rule"    , this.rule !== "optional" && this.rule || undefined,
+        "type"    , this.type,
+        "id"      , this.id,
+        "extend"  , this.extend,
+        "options" , this.options,
+        "comment" , keepComments ? this.comment : undefined
+    ]);
+};
+
+/**
+ * Resolves this field's type references.
+ * @returns {Field} `this`
+ * @throws {Error} If any reference cannot be resolved
+ */
+Field.prototype.resolve = function resolve() {
+
+    if (this.resolved)
+        return this;
+
+    if ((this.typeDefault = types.defaults[this.type]) === undefined) { // if not a basic type, resolve it
+        this.resolvedType = (this.declaringField ? this.declaringField.parent : this.parent).lookupTypeOrEnum(this.type);
+        if (this.resolvedType instanceof Type)
+            this.typeDefault = null;
+        else // instanceof Enum
+            this.typeDefault = this.resolvedType.values[Object.keys(this.resolvedType.values)[0]]; // first defined
+    } else if (this.options && this.options.proto3_optional) {
+        // proto3 scalar value marked optional; should default to null
+        this.typeDefault = null;
+    }
+
+    // use explicitly set default value if present
+    if (this.options && this.options["default"] != null) {
+        this.typeDefault = this.options["default"];
+        if (this.resolvedType instanceof Enum && typeof this.typeDefault === "string")
+            this.typeDefault = this.resolvedType.values[this.typeDefault];
+    }
+
+    // remove unnecessary options
+    if (this.options) {
+        if (this.options.packed === true || this.options.packed !== undefined && this.resolvedType && !(this.resolvedType instanceof Enum))
+            delete this.options.packed;
+        if (!Object.keys(this.options).length)
+            this.options = undefined;
+    }
+
+    // convert to internal data type if necesssary
+    if (this.long) {
+        this.typeDefault = util.Long.fromNumber(this.typeDefault, this.type.charAt(0) === "u");
+
+        /* istanbul ignore else */
+        if (Object.freeze)
+            Object.freeze(this.typeDefault); // long instances are meant to be immutable anyway (i.e. use small int cache that even requires it)
+
+    } else if (this.bytes && typeof this.typeDefault === "string") {
+        var buf;
+        if (util.base64.test(this.typeDefault))
+            util.base64.decode(this.typeDefault, buf = util.newBuffer(util.base64.length(this.typeDefault)), 0);
+        else
+            util.utf8.write(this.typeDefault, buf = util.newBuffer(util.utf8.length(this.typeDefault)), 0);
+        this.typeDefault = buf;
+    }
+
+    // take special care of maps and repeated fields
+    if (this.map)
+        this.defaultValue = util.emptyObject;
+    else if (this.repeated)
+        this.defaultValue = util.emptyArray;
+    else
+        this.defaultValue = this.typeDefault;
+
+    // ensure proper value on prototype
+    if (this.parent instanceof Type)
+        this.parent.ctor.prototype[this.name] = this.defaultValue;
+
+    return ReflectionObject.prototype.resolve.call(this);
+};
+
+/**
+ * Decorator function as returned by {@link Field.d} and {@link MapField.d} (TypeScript).
+ * @typedef FieldDecorator
+ * @type {function}
+ * @param {Object} prototype Target prototype
+ * @param {string} fieldName Field name
+ * @returns {undefined}
+ */
+
+/**
+ * Field decorator (TypeScript).
+ * @name Field.d
+ * @function
+ * @param {number} fieldId Field id
+ * @param {"double"|"float"|"int32"|"uint32"|"sint32"|"fixed32"|"sfixed32"|"int64"|"uint64"|"sint64"|"fixed64"|"sfixed64"|"string"|"bool"|"bytes"|Object} fieldType Field type
+ * @param {"optional"|"required"|"repeated"} [fieldRule="optional"] Field rule
+ * @param {T} [defaultValue] Default value
+ * @returns {FieldDecorator} Decorator function
+ * @template T extends number | number[] | Long | Long[] | string | string[] | boolean | boolean[] | Uint8Array | Uint8Array[] | Buffer | Buffer[]
+ */
+Field.d = function decorateField(fieldId, fieldType, fieldRule, defaultValue) {
+
+    // submessage: decorate the submessage and use its name as the type
+    if (typeof fieldType === "function")
+        fieldType = util.decorateType(fieldType).name;
+
+    // enum reference: create a reflected copy of the enum and keep reuseing it
+    else if (fieldType && typeof fieldType === "object")
+        fieldType = util.decorateEnum(fieldType).name;
+
+    return function fieldDecorator(prototype, fieldName) {
+        util.decorateType(prototype.constructor)
+            .add(new Field(fieldName, fieldId, fieldType, fieldRule, { "default": defaultValue }));
+    };
+};
+
+/**
+ * Field decorator (TypeScript).
+ * @name Field.d
+ * @function
+ * @param {number} fieldId Field id
+ * @param {Constructor<T>|string} fieldType Field type
+ * @param {"optional"|"required"|"repeated"} [fieldRule="optional"] Field rule
+ * @returns {FieldDecorator} Decorator function
+ * @template T extends Message<T>
+ * @variation 2
+ */
+// like Field.d but without a default value
+
+// Sets up cyclic dependencies (called in index-light)
+Field._configure = function configure(Type_) {
+    Type = Type_;
+};
diff --git a/src/index-light.js b/src/index-light.js
new file mode 100644
index 0000000..32c6a05
--- /dev/null
+++ b/src/index-light.js
@@ -0,0 +1,104 @@
+"use strict";
+var protobuf = module.exports = require("./index-minimal");
+
+protobuf.build = "light";
+
+/**
+ * A node-style callback as used by {@link load} and {@link Root#load}.
+ * @typedef LoadCallback
+ * @type {function}
+ * @param {Error|null} error Error, if any, otherwise `null`
+ * @param {Root} [root] Root, if there hasn't been an error
+ * @returns {undefined}
+ */
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into a common root namespace and calls the callback.
+ * @param {string|string[]} filename One or multiple files to load
+ * @param {Root} root Root namespace, defaults to create a new one if omitted.
+ * @param {LoadCallback} callback Callback function
+ * @returns {undefined}
+ * @see {@link Root#load}
+ */
+function load(filename, root, callback) {
+    if (typeof root === "function") {
+        callback = root;
+        root = new protobuf.Root();
+    } else if (!root)
+        root = new protobuf.Root();
+    return root.load(filename, callback);
+}
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into a common root namespace and calls the callback.
+ * @name load
+ * @function
+ * @param {string|string[]} filename One or multiple files to load
+ * @param {LoadCallback} callback Callback function
+ * @returns {undefined}
+ * @see {@link Root#load}
+ * @variation 2
+ */
+// function load(filename:string, callback:LoadCallback):undefined
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into a common root namespace and returns a promise.
+ * @name load
+ * @function
+ * @param {string|string[]} filename One or multiple files to load
+ * @param {Root} [root] Root namespace, defaults to create a new one if omitted.
+ * @returns {Promise<Root>} Promise
+ * @see {@link Root#load}
+ * @variation 3
+ */
+// function load(filename:string, [root:Root]):Promise<Root>
+
+protobuf.load = load;
+
+/**
+ * Synchronously loads one or multiple .proto or preprocessed .json files into a common root namespace (node only).
+ * @param {string|string[]} filename One or multiple files to load
+ * @param {Root} [root] Root namespace, defaults to create a new one if omitted.
+ * @returns {Root} Root namespace
+ * @throws {Error} If synchronous fetching is not supported (i.e. in browsers) or if a file's syntax is invalid
+ * @see {@link Root#loadSync}
+ */
+function loadSync(filename, root) {
+    if (!root)
+        root = new protobuf.Root();
+    return root.loadSync(filename);
+}
+
+protobuf.loadSync = loadSync;
+
+// Serialization
+protobuf.encoder          = require("./encoder");
+protobuf.decoder          = require("./decoder");
+protobuf.verifier         = require("./verifier");
+protobuf.converter        = require("./converter");
+
+// Reflection
+protobuf.ReflectionObject = require("./object");
+protobuf.Namespace        = require("./namespace");
+protobuf.Root             = require("./root");
+protobuf.Enum             = require("./enum");
+protobuf.Type             = require("./type");
+protobuf.Field            = require("./field");
+protobuf.OneOf            = require("./oneof");
+protobuf.MapField         = require("./mapfield");
+protobuf.Service          = require("./service");
+protobuf.Method           = require("./method");
+
+// Runtime
+protobuf.Message          = require("./message");
+protobuf.wrappers         = require("./wrappers");
+
+// Utility
+protobuf.types            = require("./types");
+protobuf.util             = require("./util");
+
+// Set up possibly cyclic reflection dependencies
+protobuf.ReflectionObject._configure(protobuf.Root);
+protobuf.Namespace._configure(protobuf.Type, protobuf.Service, protobuf.Enum);
+protobuf.Root._configure(protobuf.Type);
+protobuf.Field._configure(protobuf.Type);
diff --git a/src/index-minimal.js b/src/index-minimal.js
new file mode 100644
index 0000000..1f4aaea
--- /dev/null
+++ b/src/index-minimal.js
@@ -0,0 +1,36 @@
+"use strict";
+var protobuf = exports;
+
+/**
+ * Build type, one of `"full"`, `"light"` or `"minimal"`.
+ * @name build
+ * @type {string}
+ * @const
+ */
+protobuf.build = "minimal";
+
+// Serialization
+protobuf.Writer       = require("./writer");
+protobuf.BufferWriter = require("./writer_buffer");
+protobuf.Reader       = require("./reader");
+protobuf.BufferReader = require("./reader_buffer");
+
+// Utility
+protobuf.util         = require("./util/minimal");
+protobuf.rpc          = require("./rpc");
+protobuf.roots        = require("./roots");
+protobuf.configure    = configure;
+
+/* istanbul ignore next */
+/**
+ * Reconfigures the library according to the environment.
+ * @returns {undefined}
+ */
+function configure() {
+    protobuf.util._configure();
+    protobuf.Writer._configure(protobuf.BufferWriter);
+    protobuf.Reader._configure(protobuf.BufferReader);
+}
+
+// Set up buffer utility according to the environment
+configure();
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 0000000..56bd3d5
--- /dev/null
+++ b/src/index.js
@@ -0,0 +1,12 @@
+"use strict";
+var protobuf = module.exports = require("./index-light");
+
+protobuf.build = "full";
+
+// Parser
+protobuf.tokenize         = require("./tokenize");
+protobuf.parse            = require("./parse");
+protobuf.common           = require("./common");
+
+// Configure parser
+protobuf.Root._configure(protobuf.Type, protobuf.parse, protobuf.common);
diff --git a/src/mapfield.js b/src/mapfield.js
new file mode 100644
index 0000000..67c7097
--- /dev/null
+++ b/src/mapfield.js
@@ -0,0 +1,126 @@
+"use strict";
+module.exports = MapField;
+
+// extends Field
+var Field = require("./field");
+((MapField.prototype = Object.create(Field.prototype)).constructor = MapField).className = "MapField";
+
+var types   = require("./types"),
+    util    = require("./util");
+
+/**
+ * Constructs a new map field instance.
+ * @classdesc Reflected map field.
+ * @extends FieldBase
+ * @constructor
+ * @param {string} name Unique name within its namespace
+ * @param {number} id Unique id within its namespace
+ * @param {string} keyType Key type
+ * @param {string} type Value type
+ * @param {Object.<string,*>} [options] Declared options
+ * @param {string} [comment] Comment associated with this field
+ */
+function MapField(name, id, keyType, type, options, comment) {
+    Field.call(this, name, id, type, undefined, undefined, options, comment);
+
+    /* istanbul ignore if */
+    if (!util.isString(keyType))
+        throw TypeError("keyType must be a string");
+
+    /**
+     * Key type.
+     * @type {string}
+     */
+    this.keyType = keyType; // toJSON, marker
+
+    /**
+     * Resolved key type if not a basic type.
+     * @type {ReflectionObject|null}
+     */
+    this.resolvedKeyType = null;
+
+    // Overrides Field#map
+    this.map = true;
+}
+
+/**
+ * Map field descriptor.
+ * @interface IMapField
+ * @extends {IField}
+ * @property {string} keyType Key type
+ */
+
+/**
+ * Extension map field descriptor.
+ * @interface IExtensionMapField
+ * @extends IMapField
+ * @property {string} extend Extended type
+ */
+
+/**
+ * Constructs a map field from a map field descriptor.
+ * @param {string} name Field name
+ * @param {IMapField} json Map field descriptor
+ * @returns {MapField} Created map field
+ * @throws {TypeError} If arguments are invalid
+ */
+MapField.fromJSON = function fromJSON(name, json) {
+    return new MapField(name, json.id, json.keyType, json.type, json.options, json.comment);
+};
+
+/**
+ * Converts this map field to a map field descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {IMapField} Map field descriptor
+ */
+MapField.prototype.toJSON = function toJSON(toJSONOptions) {
+    var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
+    return util.toObject([
+        "keyType" , this.keyType,
+        "type"    , this.type,
+        "id"      , this.id,
+        "extend"  , this.extend,
+        "options" , this.options,
+        "comment" , keepComments ? this.comment : undefined
+    ]);
+};
+
+/**
+ * @override
+ */
+MapField.prototype.resolve = function resolve() {
+    if (this.resolved)
+        return this;
+
+    // Besides a value type, map fields have a key type that may be "any scalar type except for floating point types and bytes"
+    if (types.mapKey[this.keyType] === undefined)
+        throw Error("invalid key type: " + this.keyType);
+
+    return Field.prototype.resolve.call(this);
+};
+
+/**
+ * Map field decorator (TypeScript).
+ * @name MapField.d
+ * @function
+ * @param {number} fieldId Field id
+ * @param {"int32"|"uint32"|"sint32"|"fixed32"|"sfixed32"|"int64"|"uint64"|"sint64"|"fixed64"|"sfixed64"|"bool"|"string"} fieldKeyType Field key type
+ * @param {"double"|"float"|"int32"|"uint32"|"sint32"|"fixed32"|"sfixed32"|"int64"|"uint64"|"sint64"|"fixed64"|"sfixed64"|"bool"|"string"|"bytes"|Object|Constructor<{}>} fieldValueType Field value type
+ * @returns {FieldDecorator} Decorator function
+ * @template T extends { [key: string]: number | Long | string | boolean | Uint8Array | Buffer | number[] | Message<{}> }
+ */
+MapField.d = function decorateMapField(fieldId, fieldKeyType, fieldValueType) {
+
+    // submessage value: decorate the submessage and use its name as the type
+    if (typeof fieldValueType === "function")
+        fieldValueType = util.decorateType(fieldValueType).name;
+
+    // enum reference value: create a reflected copy of the enum and keep reuseing it
+    else if (fieldValueType && typeof fieldValueType === "object")
+        fieldValueType = util.decorateEnum(fieldValueType).name;
+
+    return function mapFieldDecorator(prototype, fieldName) {
+        util.decorateType(prototype.constructor)
+            .add(new MapField(fieldName, fieldId, fieldKeyType, fieldValueType));
+    };
+};
diff --git a/src/message.js b/src/message.js
new file mode 100644
index 0000000..3f94bf6
--- /dev/null
+++ b/src/message.js
@@ -0,0 +1,139 @@
+"use strict";
+module.exports = Message;
+
+var util = require("./util/minimal");
+
+/**
+ * Constructs a new message instance.
+ * @classdesc Abstract runtime message.
+ * @constructor
+ * @param {Properties<T>} [properties] Properties to set
+ * @template T extends object = object
+ */
+function Message(properties) {
+    // not used internally
+    if (properties)
+        for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+            this[keys[i]] = properties[keys[i]];
+}
+
+/**
+ * Reference to the reflected type.
+ * @name Message.$type
+ * @type {Type}
+ * @readonly
+ */
+
+/**
+ * Reference to the reflected type.
+ * @name Message#$type
+ * @type {Type}
+ * @readonly
+ */
+
+/*eslint-disable valid-jsdoc*/
+
+/**
+ * Creates a new message of this type using the specified properties.
+ * @param {Object.<string,*>} [properties] Properties to set
+ * @returns {Message<T>} Message instance
+ * @template T extends Message<T>
+ * @this Constructor<T>
+ */
+Message.create = function create(properties) {
+    return this.$type.create(properties);
+};
+
+/**
+ * Encodes a message of this type.
+ * @param {T|Object.<string,*>} message Message to encode
+ * @param {Writer} [writer] Writer to use
+ * @returns {Writer} Writer
+ * @template T extends Message<T>
+ * @this Constructor<T>
+ */
+Message.encode = function encode(message, writer) {
+    return this.$type.encode(message, writer);
+};
+
+/**
+ * Encodes a message of this type preceeded by its length as a varint.
+ * @param {T|Object.<string,*>} message Message to encode
+ * @param {Writer} [writer] Writer to use
+ * @returns {Writer} Writer
+ * @template T extends Message<T>
+ * @this Constructor<T>
+ */
+Message.encodeDelimited = function encodeDelimited(message, writer) {
+    return this.$type.encodeDelimited(message, writer);
+};
+
+/**
+ * Decodes a message of this type.
+ * @name Message.decode
+ * @function
+ * @param {Reader|Uint8Array} reader Reader or buffer to decode
+ * @returns {T} Decoded message
+ * @template T extends Message<T>
+ * @this Constructor<T>
+ */
+Message.decode = function decode(reader) {
+    return this.$type.decode(reader);
+};
+
+/**
+ * Decodes a message of this type preceeded by its length as a varint.
+ * @name Message.decodeDelimited
+ * @function
+ * @param {Reader|Uint8Array} reader Reader or buffer to decode
+ * @returns {T} Decoded message
+ * @template T extends Message<T>
+ * @this Constructor<T>
+ */
+Message.decodeDelimited = function decodeDelimited(reader) {
+    return this.$type.decodeDelimited(reader);
+};
+
+/**
+ * Verifies a message of this type.
+ * @name Message.verify
+ * @function
+ * @param {Object.<string,*>} message Plain object to verify
+ * @returns {string|null} `null` if valid, otherwise the reason why it is not
+ */
+Message.verify = function verify(message) {
+    return this.$type.verify(message);
+};
+
+/**
+ * Creates a new message of this type from a plain object. Also converts values to their respective internal types.
+ * @param {Object.<string,*>} object Plain object
+ * @returns {T} Message instance
+ * @template T extends Message<T>
+ * @this Constructor<T>
+ */
+Message.fromObject = function fromObject(object) {
+    return this.$type.fromObject(object);
+};
+
+/**
+ * Creates a plain object from a message of this type. Also converts values to other types if specified.
+ * @param {T} message Message instance
+ * @param {IConversionOptions} [options] Conversion options
+ * @returns {Object.<string,*>} Plain object
+ * @template T extends Message<T>
+ * @this Constructor<T>
+ */
+Message.toObject = function toObject(message, options) {
+    return this.$type.toObject(message, options);
+};
+
+/**
+ * Converts this message to JSON.
+ * @returns {Object.<string,*>} JSON object
+ */
+Message.prototype.toJSON = function toJSON() {
+    return this.$type.toObject(this, util.toJSONOptions);
+};
+
+/*eslint-enable valid-jsdoc*/
\ No newline at end of file
diff --git a/src/method.js b/src/method.js
new file mode 100644
index 0000000..18a6ab2
--- /dev/null
+++ b/src/method.js
@@ -0,0 +1,160 @@
+"use strict";
+module.exports = Method;
+
+// extends ReflectionObject
+var ReflectionObject = require("./object");
+((Method.prototype = Object.create(ReflectionObject.prototype)).constructor = Method).className = "Method";
+
+var util = require("./util");
+
+/**
+ * Constructs a new service method instance.
+ * @classdesc Reflected service method.
+ * @extends ReflectionObject
+ * @constructor
+ * @param {string} name Method name
+ * @param {string|undefined} type Method type, usually `"rpc"`
+ * @param {string} requestType Request message type
+ * @param {string} responseType Response message type
+ * @param {boolean|Object.<string,*>} [requestStream] Whether the request is streamed
+ * @param {boolean|Object.<string,*>} [responseStream] Whether the response is streamed
+ * @param {Object.<string,*>} [options] Declared options
+ * @param {string} [comment] The comment for this method
+ * @param {Object.<string,*>} [parsedOptions] Declared options, properly parsed into an object
+ */
+function Method(name, type, requestType, responseType, requestStream, responseStream, options, comment, parsedOptions) {
+
+    /* istanbul ignore next */
+    if (util.isObject(requestStream)) {
+        options = requestStream;
+        requestStream = responseStream = undefined;
+    } else if (util.isObject(responseStream)) {
+        options = responseStream;
+        responseStream = undefined;
+    }
+
+    /* istanbul ignore if */
+    if (!(type === undefined || util.isString(type)))
+        throw TypeError("type must be a string");
+
+    /* istanbul ignore if */
+    if (!util.isString(requestType))
+        throw TypeError("requestType must be a string");
+
+    /* istanbul ignore if */
+    if (!util.isString(responseType))
+        throw TypeError("responseType must be a string");
+
+    ReflectionObject.call(this, name, options);
+
+    /**
+     * Method type.
+     * @type {string}
+     */
+    this.type = type || "rpc"; // toJSON
+
+    /**
+     * Request type.
+     * @type {string}
+     */
+    this.requestType = requestType; // toJSON, marker
+
+    /**
+     * Whether requests are streamed or not.
+     * @type {boolean|undefined}
+     */
+    this.requestStream = requestStream ? true : undefined; // toJSON
+
+    /**
+     * Response type.
+     * @type {string}
+     */
+    this.responseType = responseType; // toJSON
+
+    /**
+     * Whether responses are streamed or not.
+     * @type {boolean|undefined}
+     */
+    this.responseStream = responseStream ? true : undefined; // toJSON
+
+    /**
+     * Resolved request type.
+     * @type {Type|null}
+     */
+    this.resolvedRequestType = null;
+
+    /**
+     * Resolved response type.
+     * @type {Type|null}
+     */
+    this.resolvedResponseType = null;
+
+    /**
+     * Comment for this method
+     * @type {string|null}
+     */
+    this.comment = comment;
+
+    /**
+     * Options properly parsed into an object
+     */
+    this.parsedOptions = parsedOptions;
+}
+
+/**
+ * Method descriptor.
+ * @interface IMethod
+ * @property {string} [type="rpc"] Method type
+ * @property {string} requestType Request type
+ * @property {string} responseType Response type
+ * @property {boolean} [requestStream=false] Whether requests are streamed
+ * @property {boolean} [responseStream=false] Whether responses are streamed
+ * @property {Object.<string,*>} [options] Method options
+ * @property {string} comment Method comments
+ * @property {Object.<string,*>} [parsedOptions] Method options properly parsed into an object
+ */
+
+/**
+ * Constructs a method from a method descriptor.
+ * @param {string} name Method name
+ * @param {IMethod} json Method descriptor
+ * @returns {Method} Created method
+ * @throws {TypeError} If arguments are invalid
+ */
+Method.fromJSON = function fromJSON(name, json) {
+    return new Method(name, json.type, json.requestType, json.responseType, json.requestStream, json.responseStream, json.options, json.comment, json.parsedOptions);
+};
+
+/**
+ * Converts this method to a method descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {IMethod} Method descriptor
+ */
+Method.prototype.toJSON = function toJSON(toJSONOptions) {
+    var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
+    return util.toObject([
+        "type"           , this.type !== "rpc" && /* istanbul ignore next */ this.type || undefined,
+        "requestType"    , this.requestType,
+        "requestStream"  , this.requestStream,
+        "responseType"   , this.responseType,
+        "responseStream" , this.responseStream,
+        "options"        , this.options,
+        "comment"        , keepComments ? this.comment : undefined,
+        "parsedOptions"  , this.parsedOptions,
+    ]);
+};
+
+/**
+ * @override
+ */
+Method.prototype.resolve = function resolve() {
+
+    /* istanbul ignore if */
+    if (this.resolved)
+        return this;
+
+    this.resolvedRequestType = this.parent.lookupType(this.requestType);
+    this.resolvedResponseType = this.parent.lookupType(this.responseType);
+
+    return ReflectionObject.prototype.resolve.call(this);
+};
diff --git a/src/namespace.js b/src/namespace.js
new file mode 100644
index 0000000..731afc7
--- /dev/null
+++ b/src/namespace.js
@@ -0,0 +1,433 @@
+"use strict";
+module.exports = Namespace;
+
+// extends ReflectionObject
+var ReflectionObject = require("./object");
+((Namespace.prototype = Object.create(ReflectionObject.prototype)).constructor = Namespace).className = "Namespace";
+
+var Field    = require("./field"),
+    util     = require("./util"),
+    OneOf    = require("./oneof");
+
+var Type,    // cyclic
+    Service,
+    Enum;
+
+/**
+ * Constructs a new namespace instance.
+ * @name Namespace
+ * @classdesc Reflected namespace.
+ * @extends NamespaceBase
+ * @constructor
+ * @param {string} name Namespace name
+ * @param {Object.<string,*>} [options] Declared options
+ */
+
+/**
+ * Constructs a namespace from JSON.
+ * @memberof Namespace
+ * @function
+ * @param {string} name Namespace name
+ * @param {Object.<string,*>} json JSON object
+ * @returns {Namespace} Created namespace
+ * @throws {TypeError} If arguments are invalid
+ */
+Namespace.fromJSON = function fromJSON(name, json) {
+    return new Namespace(name, json.options).addJSON(json.nested);
+};
+
+/**
+ * Converts an array of reflection objects to JSON.
+ * @memberof Namespace
+ * @param {ReflectionObject[]} array Object array
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {Object.<string,*>|undefined} JSON object or `undefined` when array is empty
+ */
+function arrayToJSON(array, toJSONOptions) {
+    if (!(array && array.length))
+        return undefined;
+    var obj = {};
+    for (var i = 0; i < array.length; ++i)
+        obj[array[i].name] = array[i].toJSON(toJSONOptions);
+    return obj;
+}
+
+Namespace.arrayToJSON = arrayToJSON;
+
+/**
+ * Tests if the specified id is reserved.
+ * @param {Array.<number[]|string>|undefined} reserved Array of reserved ranges and names
+ * @param {number} id Id to test
+ * @returns {boolean} `true` if reserved, otherwise `false`
+ */
+Namespace.isReservedId = function isReservedId(reserved, id) {
+    if (reserved)
+        for (var i = 0; i < reserved.length; ++i)
+            if (typeof reserved[i] !== "string" && reserved[i][0] <= id && reserved[i][1] > id)
+                return true;
+    return false;
+};
+
+/**
+ * Tests if the specified name is reserved.
+ * @param {Array.<number[]|string>|undefined} reserved Array of reserved ranges and names
+ * @param {string} name Name to test
+ * @returns {boolean} `true` if reserved, otherwise `false`
+ */
+Namespace.isReservedName = function isReservedName(reserved, name) {
+    if (reserved)
+        for (var i = 0; i < reserved.length; ++i)
+            if (reserved[i] === name)
+                return true;
+    return false;
+};
+
+/**
+ * Not an actual constructor. Use {@link Namespace} instead.
+ * @classdesc Base class of all reflection objects containing nested objects. This is not an actual class but here for the sake of having consistent type definitions.
+ * @exports NamespaceBase
+ * @extends ReflectionObject
+ * @abstract
+ * @constructor
+ * @param {string} name Namespace name
+ * @param {Object.<string,*>} [options] Declared options
+ * @see {@link Namespace}
+ */
+function Namespace(name, options) {
+    ReflectionObject.call(this, name, options);
+
+    /**
+     * Nested objects by name.
+     * @type {Object.<string,ReflectionObject>|undefined}
+     */
+    this.nested = undefined; // toJSON
+
+    /**
+     * Cached nested objects as an array.
+     * @type {ReflectionObject[]|null}
+     * @private
+     */
+    this._nestedArray = null;
+}
+
+function clearCache(namespace) {
+    namespace._nestedArray = null;
+    return namespace;
+}
+
+/**
+ * Nested objects of this namespace as an array for iteration.
+ * @name NamespaceBase#nestedArray
+ * @type {ReflectionObject[]}
+ * @readonly
+ */
+Object.defineProperty(Namespace.prototype, "nestedArray", {
+    get: function() {
+        return this._nestedArray || (this._nestedArray = util.toArray(this.nested));
+    }
+});
+
+/**
+ * Namespace descriptor.
+ * @interface INamespace
+ * @property {Object.<string,*>} [options] Namespace options
+ * @property {Object.<string,AnyNestedObject>} [nested] Nested object descriptors
+ */
+
+/**
+ * Any extension field descriptor.
+ * @typedef AnyExtensionField
+ * @type {IExtensionField|IExtensionMapField}
+ */
+
+/**
+ * Any nested object descriptor.
+ * @typedef AnyNestedObject
+ * @type {IEnum|IType|IService|AnyExtensionField|INamespace|IOneOf}
+ */
+
+/**
+ * Converts this namespace to a namespace descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {INamespace} Namespace descriptor
+ */
+Namespace.prototype.toJSON = function toJSON(toJSONOptions) {
+    return util.toObject([
+        "options" , this.options,
+        "nested"  , arrayToJSON(this.nestedArray, toJSONOptions)
+    ]);
+};
+
+/**
+ * Adds nested objects to this namespace from nested object descriptors.
+ * @param {Object.<string,AnyNestedObject>} nestedJson Any nested object descriptors
+ * @returns {Namespace} `this`
+ */
+Namespace.prototype.addJSON = function addJSON(nestedJson) {
+    var ns = this;
+    /* istanbul ignore else */
+    if (nestedJson) {
+        for (var names = Object.keys(nestedJson), i = 0, nested; i < names.length; ++i) {
+            nested = nestedJson[names[i]];
+            ns.add( // most to least likely
+                ( nested.fields !== undefined
+                ? Type.fromJSON
+                : nested.values !== undefined
+                ? Enum.fromJSON
+                : nested.methods !== undefined
+                ? Service.fromJSON
+                : nested.id !== undefined
+                ? Field.fromJSON
+                : Namespace.fromJSON )(names[i], nested)
+            );
+        }
+    }
+    return this;
+};
+
+/**
+ * Gets the nested object of the specified name.
+ * @param {string} name Nested object name
+ * @returns {ReflectionObject|null} The reflection object or `null` if it doesn't exist
+ */
+Namespace.prototype.get = function get(name) {
+    return this.nested && this.nested[name]
+        || null;
+};
+
+/**
+ * Gets the values of the nested {@link Enum|enum} of the specified name.
+ * This methods differs from {@link Namespace#get|get} in that it returns an enum's values directly and throws instead of returning `null`.
+ * @param {string} name Nested enum name
+ * @returns {Object.<string,number>} Enum values
+ * @throws {Error} If there is no such enum
+ */
+Namespace.prototype.getEnum = function getEnum(name) {
+    if (this.nested && this.nested[name] instanceof Enum)
+        return this.nested[name].values;
+    throw Error("no such enum: " + name);
+};
+
+/**
+ * Adds a nested object to this namespace.
+ * @param {ReflectionObject} object Nested object to add
+ * @returns {Namespace} `this`
+ * @throws {TypeError} If arguments are invalid
+ * @throws {Error} If there is already a nested object with this name
+ */
+Namespace.prototype.add = function add(object) {
+
+    if (!(object instanceof Field && object.extend !== undefined || object instanceof Type  || object instanceof OneOf || object instanceof Enum || object instanceof Service || object instanceof Namespace))
+        throw TypeError("object must be a valid nested object");
+
+    if (!this.nested)
+        this.nested = {};
+    else {
+        var prev = this.get(object.name);
+        if (prev) {
+            if (prev instanceof Namespace && object instanceof Namespace && !(prev instanceof Type || prev instanceof Service)) {
+                // replace plain namespace but keep existing nested elements and options
+                var nested = prev.nestedArray;
+                for (var i = 0; i < nested.length; ++i)
+                    object.add(nested[i]);
+                this.remove(prev);
+                if (!this.nested)
+                    this.nested = {};
+                object.setOptions(prev.options, true);
+
+            } else
+                throw Error("duplicate name '" + object.name + "' in " + this);
+        }
+    }
+    this.nested[object.name] = object;
+    object.onAdd(this);
+    return clearCache(this);
+};
+
+/**
+ * Removes a nested object from this namespace.
+ * @param {ReflectionObject} object Nested object to remove
+ * @returns {Namespace} `this`
+ * @throws {TypeError} If arguments are invalid
+ * @throws {Error} If `object` is not a member of this namespace
+ */
+Namespace.prototype.remove = function remove(object) {
+
+    if (!(object instanceof ReflectionObject))
+        throw TypeError("object must be a ReflectionObject");
+    if (object.parent !== this)
+        throw Error(object + " is not a member of " + this);
+
+    delete this.nested[object.name];
+    if (!Object.keys(this.nested).length)
+        this.nested = undefined;
+
+    object.onRemove(this);
+    return clearCache(this);
+};
+
+/**
+ * Defines additial namespaces within this one if not yet existing.
+ * @param {string|string[]} path Path to create
+ * @param {*} [json] Nested types to create from JSON
+ * @returns {Namespace} Pointer to the last namespace created or `this` if path is empty
+ */
+Namespace.prototype.define = function define(path, json) {
+
+    if (util.isString(path))
+        path = path.split(".");
+    else if (!Array.isArray(path))
+        throw TypeError("illegal path");
+    if (path && path.length && path[0] === "")
+        throw Error("path must be relative");
+
+    var ptr = this;
+    while (path.length > 0) {
+        var part = path.shift();
+        if (ptr.nested && ptr.nested[part]) {
+            ptr = ptr.nested[part];
+            if (!(ptr instanceof Namespace))
+                throw Error("path conflicts with non-namespace objects");
+        } else
+            ptr.add(ptr = new Namespace(part));
+    }
+    if (json)
+        ptr.addJSON(json);
+    return ptr;
+};
+
+/**
+ * Resolves this namespace's and all its nested objects' type references. Useful to validate a reflection tree, but comes at a cost.
+ * @returns {Namespace} `this`
+ */
+Namespace.prototype.resolveAll = function resolveAll() {
+    var nested = this.nestedArray, i = 0;
+    while (i < nested.length)
+        if (nested[i] instanceof Namespace)
+            nested[i++].resolveAll();
+        else
+            nested[i++].resolve();
+    return this.resolve();
+};
+
+/**
+ * Recursively looks up the reflection object matching the specified path in the scope of this namespace.
+ * @param {string|string[]} path Path to look up
+ * @param {*|Array.<*>} filterTypes Filter types, any combination of the constructors of `protobuf.Type`, `protobuf.Enum`, `protobuf.Service` etc.
+ * @param {boolean} [parentAlreadyChecked=false] If known, whether the parent has already been checked
+ * @returns {ReflectionObject|null} Looked up object or `null` if none could be found
+ */
+Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChecked) {
+
+    /* istanbul ignore next */
+    if (typeof filterTypes === "boolean") {
+        parentAlreadyChecked = filterTypes;
+        filterTypes = undefined;
+    } else if (filterTypes && !Array.isArray(filterTypes))
+        filterTypes = [ filterTypes ];
+
+    if (util.isString(path) && path.length) {
+        if (path === ".")
+            return this.root;
+        path = path.split(".");
+    } else if (!path.length)
+        return this;
+
+    // Start at root if path is absolute
+    if (path[0] === "")
+        return this.root.lookup(path.slice(1), filterTypes);
+
+    // Test if the first part matches any nested object, and if so, traverse if path contains more
+    var found = this.get(path[0]);
+    if (found) {
+        if (path.length === 1) {
+            if (!filterTypes || filterTypes.indexOf(found.constructor) > -1)
+                return found;
+        } else if (found instanceof Namespace && (found = found.lookup(path.slice(1), filterTypes, true)))
+            return found;
+
+    // Otherwise try each nested namespace
+    } else
+        for (var i = 0; i < this.nestedArray.length; ++i)
+            if (this._nestedArray[i] instanceof Namespace && (found = this._nestedArray[i].lookup(path, filterTypes, true)))
+                return found;
+
+    // If there hasn't been a match, try again at the parent
+    if (this.parent === null || parentAlreadyChecked)
+        return null;
+    return this.parent.lookup(path, filterTypes);
+};
+
+/**
+ * Looks up the reflection object at the specified path, relative to this namespace.
+ * @name NamespaceBase#lookup
+ * @function
+ * @param {string|string[]} path Path to look up
+ * @param {boolean} [parentAlreadyChecked=false] Whether the parent has already been checked
+ * @returns {ReflectionObject|null} Looked up object or `null` if none could be found
+ * @variation 2
+ */
+// lookup(path: string, [parentAlreadyChecked: boolean])
+
+/**
+ * Looks up the {@link Type|type} at the specified path, relative to this namespace.
+ * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
+ * @param {string|string[]} path Path to look up
+ * @returns {Type} Looked up type
+ * @throws {Error} If `path` does not point to a type
+ */
+Namespace.prototype.lookupType = function lookupType(path) {
+    var found = this.lookup(path, [ Type ]);
+    if (!found)
+        throw Error("no such type: " + path);
+    return found;
+};
+
+/**
+ * Looks up the values of the {@link Enum|enum} at the specified path, relative to this namespace.
+ * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
+ * @param {string|string[]} path Path to look up
+ * @returns {Enum} Looked up enum
+ * @throws {Error} If `path` does not point to an enum
+ */
+Namespace.prototype.lookupEnum = function lookupEnum(path) {
+    var found = this.lookup(path, [ Enum ]);
+    if (!found)
+        throw Error("no such Enum '" + path + "' in " + this);
+    return found;
+};
+
+/**
+ * Looks up the {@link Type|type} or {@link Enum|enum} at the specified path, relative to this namespace.
+ * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
+ * @param {string|string[]} path Path to look up
+ * @returns {Type} Looked up type or enum
+ * @throws {Error} If `path` does not point to a type or enum
+ */
+Namespace.prototype.lookupTypeOrEnum = function lookupTypeOrEnum(path) {
+    var found = this.lookup(path, [ Type, Enum ]);
+    if (!found)
+        throw Error("no such Type or Enum '" + path + "' in " + this);
+    return found;
+};
+
+/**
+ * Looks up the {@link Service|service} at the specified path, relative to this namespace.
+ * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
+ * @param {string|string[]} path Path to look up
+ * @returns {Service} Looked up service
+ * @throws {Error} If `path` does not point to a service
+ */
+Namespace.prototype.lookupService = function lookupService(path) {
+    var found = this.lookup(path, [ Service ]);
+    if (!found)
+        throw Error("no such Service '" + path + "' in " + this);
+    return found;
+};
+
+// Sets up cyclic dependencies (called in index-light)
+Namespace._configure = function(Type_, Service_, Enum_) {
+    Type    = Type_;
+    Service = Service_;
+    Enum    = Enum_;
+};
diff --git a/src/object.js b/src/object.js
new file mode 100644
index 0000000..bd04cec
--- /dev/null
+++ b/src/object.js
@@ -0,0 +1,243 @@
+"use strict";
+module.exports = ReflectionObject;
+
+ReflectionObject.className = "ReflectionObject";
+
+var util = require("./util");
+
+var Root; // cyclic
+
+/**
+ * Constructs a new reflection object instance.
+ * @classdesc Base class of all reflection objects.
+ * @constructor
+ * @param {string} name Object name
+ * @param {Object.<string,*>} [options] Declared options
+ * @abstract
+ */
+function ReflectionObject(name, options) {
+
+    if (!util.isString(name))
+        throw TypeError("name must be a string");
+
+    if (options && !util.isObject(options))
+        throw TypeError("options must be an object");
+
+    /**
+     * Options.
+     * @type {Object.<string,*>|undefined}
+     */
+    this.options = options; // toJSON
+
+    /**
+     * Parsed Options.
+     * @type {Array.<Object.<string,*>>|undefined}
+     */
+    this.parsedOptions = null;
+
+    /**
+     * Unique name within its namespace.
+     * @type {string}
+     */
+    this.name = name;
+
+    /**
+     * Parent namespace.
+     * @type {Namespace|null}
+     */
+    this.parent = null;
+
+    /**
+     * Whether already resolved or not.
+     * @type {boolean}
+     */
+    this.resolved = false;
+
+    /**
+     * Comment text, if any.
+     * @type {string|null}
+     */
+    this.comment = null;
+
+    /**
+     * Defining file name.
+     * @type {string|null}
+     */
+    this.filename = null;
+}
+
+Object.defineProperties(ReflectionObject.prototype, {
+
+    /**
+     * Reference to the root namespace.
+     * @name ReflectionObject#root
+     * @type {Root}
+     * @readonly
+     */
+    root: {
+        get: function() {
+            var ptr = this;
+            while (ptr.parent !== null)
+                ptr = ptr.parent;
+            return ptr;
+        }
+    },
+
+    /**
+     * Full name including leading dot.
+     * @name ReflectionObject#fullName
+     * @type {string}
+     * @readonly
+     */
+    fullName: {
+        get: function() {
+            var path = [ this.name ],
+                ptr = this.parent;
+            while (ptr) {
+                path.unshift(ptr.name);
+                ptr = ptr.parent;
+            }
+            return path.join(".");
+        }
+    }
+});
+
+/**
+ * Converts this reflection object to its descriptor representation.
+ * @returns {Object.<string,*>} Descriptor
+ * @abstract
+ */
+ReflectionObject.prototype.toJSON = /* istanbul ignore next */ function toJSON() {
+    throw Error(); // not implemented, shouldn't happen
+};
+
+/**
+ * Called when this object is added to a parent.
+ * @param {ReflectionObject} parent Parent added to
+ * @returns {undefined}
+ */
+ReflectionObject.prototype.onAdd = function onAdd(parent) {
+    if (this.parent && this.parent !== parent)
+        this.parent.remove(this);
+    this.parent = parent;
+    this.resolved = false;
+    var root = parent.root;
+    if (root instanceof Root)
+        root._handleAdd(this);
+};
+
+/**
+ * Called when this object is removed from a parent.
+ * @param {ReflectionObject} parent Parent removed from
+ * @returns {undefined}
+ */
+ReflectionObject.prototype.onRemove = function onRemove(parent) {
+    var root = parent.root;
+    if (root instanceof Root)
+        root._handleRemove(this);
+    this.parent = null;
+    this.resolved = false;
+};
+
+/**
+ * Resolves this objects type references.
+ * @returns {ReflectionObject} `this`
+ */
+ReflectionObject.prototype.resolve = function resolve() {
+    if (this.resolved)
+        return this;
+    if (this.root instanceof Root)
+        this.resolved = true; // only if part of a root
+    return this;
+};
+
+/**
+ * Gets an option value.
+ * @param {string} name Option name
+ * @returns {*} Option value or `undefined` if not set
+ */
+ReflectionObject.prototype.getOption = function getOption(name) {
+    if (this.options)
+        return this.options[name];
+    return undefined;
+};
+
+/**
+ * Sets an option.
+ * @param {string} name Option name
+ * @param {*} value Option value
+ * @param {boolean} [ifNotSet] Sets the option only if it isn't currently set
+ * @returns {ReflectionObject} `this`
+ */
+ReflectionObject.prototype.setOption = function setOption(name, value, ifNotSet) {
+    if (!ifNotSet || !this.options || this.options[name] === undefined)
+        (this.options || (this.options = {}))[name] = value;
+    return this;
+};
+
+/**
+ * Sets a parsed option.
+ * @param {string} name parsed Option name
+ * @param {*} value Option value
+ * @param {string} propName dot '.' delimited full path of property within the option to set. if undefined\empty, will add a new option with that value
+ * @returns {ReflectionObject} `this`
+ */
+ReflectionObject.prototype.setParsedOption = function setParsedOption(name, value, propName) {
+    if (!this.parsedOptions) {
+        this.parsedOptions = [];
+    }
+    var parsedOptions = this.parsedOptions;
+    if (propName) {
+        // If setting a sub property of an option then try to merge it
+        // with an existing option
+        var opt = parsedOptions.find(function (opt) {
+            return Object.prototype.hasOwnProperty.call(opt, name);
+        });
+        if (opt) {
+            // If we found an existing option - just merge the property value
+            var newValue = opt[name];
+            util.setProperty(newValue, propName, value);
+        } else {
+            // otherwise, create a new option, set it's property and add it to the list
+            opt = {};
+            opt[name] = util.setProperty({}, propName, value);
+            parsedOptions.push(opt);
+        }
+    } else {
+        // Always create a new option when setting the value of the option itself
+        var newOpt = {};
+        newOpt[name] = value;
+        parsedOptions.push(newOpt);
+    }
+    return this;
+};
+
+/**
+ * Sets multiple options.
+ * @param {Object.<string,*>} options Options to set
+ * @param {boolean} [ifNotSet] Sets an option only if it isn't currently set
+ * @returns {ReflectionObject} `this`
+ */
+ReflectionObject.prototype.setOptions = function setOptions(options, ifNotSet) {
+    if (options)
+        for (var keys = Object.keys(options), i = 0; i < keys.length; ++i)
+            this.setOption(keys[i], options[keys[i]], ifNotSet);
+    return this;
+};
+
+/**
+ * Converts this instance to its string representation.
+ * @returns {string} Class name[, space, full name]
+ */
+ReflectionObject.prototype.toString = function toString() {
+    var className = this.constructor.className,
+        fullName  = this.fullName;
+    if (fullName.length)
+        return className + " " + fullName;
+    return className;
+};
+
+// Sets up cyclic dependencies (called in index-light)
+ReflectionObject._configure = function(Root_) {
+    Root = Root_;
+};
diff --git a/src/oneof.js b/src/oneof.js
new file mode 100644
index 0000000..ba0e902
--- /dev/null
+++ b/src/oneof.js
@@ -0,0 +1,203 @@
+"use strict";
+module.exports = OneOf;
+
+// extends ReflectionObject
+var ReflectionObject = require("./object");
+((OneOf.prototype = Object.create(ReflectionObject.prototype)).constructor = OneOf).className = "OneOf";
+
+var Field = require("./field"),
+    util  = require("./util");
+
+/**
+ * Constructs a new oneof instance.
+ * @classdesc Reflected oneof.
+ * @extends ReflectionObject
+ * @constructor
+ * @param {string} name Oneof name
+ * @param {string[]|Object.<string,*>} [fieldNames] Field names
+ * @param {Object.<string,*>} [options] Declared options
+ * @param {string} [comment] Comment associated with this field
+ */
+function OneOf(name, fieldNames, options, comment) {
+    if (!Array.isArray(fieldNames)) {
+        options = fieldNames;
+        fieldNames = undefined;
+    }
+    ReflectionObject.call(this, name, options);
+
+    /* istanbul ignore if */
+    if (!(fieldNames === undefined || Array.isArray(fieldNames)))
+        throw TypeError("fieldNames must be an Array");
+
+    /**
+     * Field names that belong to this oneof.
+     * @type {string[]}
+     */
+    this.oneof = fieldNames || []; // toJSON, marker
+
+    /**
+     * Fields that belong to this oneof as an array for iteration.
+     * @type {Field[]}
+     * @readonly
+     */
+    this.fieldsArray = []; // declared readonly for conformance, possibly not yet added to parent
+
+    /**
+     * Comment for this field.
+     * @type {string|null}
+     */
+    this.comment = comment;
+}
+
+/**
+ * Oneof descriptor.
+ * @interface IOneOf
+ * @property {Array.<string>} oneof Oneof field names
+ * @property {Object.<string,*>} [options] Oneof options
+ */
+
+/**
+ * Constructs a oneof from a oneof descriptor.
+ * @param {string} name Oneof name
+ * @param {IOneOf} json Oneof descriptor
+ * @returns {OneOf} Created oneof
+ * @throws {TypeError} If arguments are invalid
+ */
+OneOf.fromJSON = function fromJSON(name, json) {
+    return new OneOf(name, json.oneof, json.options, json.comment);
+};
+
+/**
+ * Converts this oneof to a oneof descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {IOneOf} Oneof descriptor
+ */
+OneOf.prototype.toJSON = function toJSON(toJSONOptions) {
+    var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
+    return util.toObject([
+        "options" , this.options,
+        "oneof"   , this.oneof,
+        "comment" , keepComments ? this.comment : undefined
+    ]);
+};
+
+/**
+ * Adds the fields of the specified oneof to the parent if not already done so.
+ * @param {OneOf} oneof The oneof
+ * @returns {undefined}
+ * @inner
+ * @ignore
+ */
+function addFieldsToParent(oneof) {
+    if (oneof.parent)
+        for (var i = 0; i < oneof.fieldsArray.length; ++i)
+            if (!oneof.fieldsArray[i].parent)
+                oneof.parent.add(oneof.fieldsArray[i]);
+}
+
+/**
+ * Adds a field to this oneof and removes it from its current parent, if any.
+ * @param {Field} field Field to add
+ * @returns {OneOf} `this`
+ */
+OneOf.prototype.add = function add(field) {
+
+    /* istanbul ignore if */
+    if (!(field instanceof Field))
+        throw TypeError("field must be a Field");
+
+    if (field.parent && field.parent !== this.parent)
+        field.parent.remove(field);
+    this.oneof.push(field.name);
+    this.fieldsArray.push(field);
+    field.partOf = this; // field.parent remains null
+    addFieldsToParent(this);
+    return this;
+};
+
+/**
+ * Removes a field from this oneof and puts it back to the oneof's parent.
+ * @param {Field} field Field to remove
+ * @returns {OneOf} `this`
+ */
+OneOf.prototype.remove = function remove(field) {
+
+    /* istanbul ignore if */
+    if (!(field instanceof Field))
+        throw TypeError("field must be a Field");
+
+    var index = this.fieldsArray.indexOf(field);
+
+    /* istanbul ignore if */
+    if (index < 0)
+        throw Error(field + " is not a member of " + this);
+
+    this.fieldsArray.splice(index, 1);
+    index = this.oneof.indexOf(field.name);
+
+    /* istanbul ignore else */
+    if (index > -1) // theoretical
+        this.oneof.splice(index, 1);
+
+    field.partOf = null;
+    return this;
+};
+
+/**
+ * @override
+ */
+OneOf.prototype.onAdd = function onAdd(parent) {
+    ReflectionObject.prototype.onAdd.call(this, parent);
+    var self = this;
+    // Collect present fields
+    for (var i = 0; i < this.oneof.length; ++i) {
+        var field = parent.get(this.oneof[i]);
+        if (field && !field.partOf) {
+            field.partOf = self;
+            self.fieldsArray.push(field);
+        }
+    }
+    // Add not yet present fields
+    addFieldsToParent(this);
+};
+
+/**
+ * @override
+ */
+OneOf.prototype.onRemove = function onRemove(parent) {
+    for (var i = 0, field; i < this.fieldsArray.length; ++i)
+        if ((field = this.fieldsArray[i]).parent)
+            field.parent.remove(field);
+    ReflectionObject.prototype.onRemove.call(this, parent);
+};
+
+/**
+ * Decorator function as returned by {@link OneOf.d} (TypeScript).
+ * @typedef OneOfDecorator
+ * @type {function}
+ * @param {Object} prototype Target prototype
+ * @param {string} oneofName OneOf name
+ * @returns {undefined}
+ */
+
+/**
+ * OneOf decorator (TypeScript).
+ * @function
+ * @param {...string} fieldNames Field names
+ * @returns {OneOfDecorator} Decorator function
+ * @template T extends string
+ */
+OneOf.d = function decorateOneOf() {
+    var fieldNames = new Array(arguments.length),
+        index = 0;
+    while (index < arguments.length)
+        fieldNames[index] = arguments[index++];
+    return function oneOfDecorator(prototype, oneofName) {
+        util.decorateType(prototype.constructor)
+            .add(new OneOf(oneofName, fieldNames));
+        Object.defineProperty(prototype, oneofName, {
+            get: util.oneOfGetter(fieldNames),
+            set: util.oneOfSetter(fieldNames)
+        });
+    };
+};
diff --git a/src/parse.js b/src/parse.js
new file mode 100644
index 0000000..be9dd5a
--- /dev/null
+++ b/src/parse.js
@@ -0,0 +1,859 @@
+"use strict";
+module.exports = parse;
+
+parse.filename = null;
+parse.defaults = { keepCase: false };
+
+var tokenize  = require("./tokenize"),
+    Root      = require("./root"),
+    Type      = require("./type"),
+    Field     = require("./field"),
+    MapField  = require("./mapfield"),
+    OneOf     = require("./oneof"),
+    Enum      = require("./enum"),
+    Service   = require("./service"),
+    Method    = require("./method"),
+    types     = require("./types"),
+    util      = require("./util");
+
+var base10Re    = /^[1-9][0-9]*$/,
+    base10NegRe = /^-?[1-9][0-9]*$/,
+    base16Re    = /^0[x][0-9a-fA-F]+$/,
+    base16NegRe = /^-?0[x][0-9a-fA-F]+$/,
+    base8Re     = /^0[0-7]+$/,
+    base8NegRe  = /^-?0[0-7]+$/,
+    numberRe    = /^(?![eE])[0-9]*(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?$/,
+    nameRe      = /^[a-zA-Z_][a-zA-Z_0-9]*$/,
+    typeRefRe   = /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*$/,
+    fqTypeRefRe = /^(?:\.[a-zA-Z_][a-zA-Z_0-9]*)+$/;
+
+/**
+ * Result object returned from {@link parse}.
+ * @interface IParserResult
+ * @property {string|undefined} package Package name, if declared
+ * @property {string[]|undefined} imports Imports, if any
+ * @property {string[]|undefined} weakImports Weak imports, if any
+ * @property {string|undefined} syntax Syntax, if specified (either `"proto2"` or `"proto3"`)
+ * @property {Root} root Populated root instance
+ */
+
+/**
+ * Options modifying the behavior of {@link parse}.
+ * @interface IParseOptions
+ * @property {boolean} [keepCase=false] Keeps field casing instead of converting to camel case
+ * @property {boolean} [alternateCommentMode=false] Recognize double-slash comments in addition to doc-block comments.
+ * @property {boolean} [preferTrailingComment=false] Use trailing comment when both leading comment and trailing comment exist.
+ */
+
+/**
+ * Options modifying the behavior of JSON serialization.
+ * @interface IToJSONOptions
+ * @property {boolean} [keepComments=false] Serializes comments.
+ */
+
+/**
+ * Parses the given .proto source and returns an object with the parsed contents.
+ * @param {string} source Source contents
+ * @param {Root} root Root to populate
+ * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+ * @returns {IParserResult} Parser result
+ * @property {string} filename=null Currently processing file name for error reporting, if known
+ * @property {IParseOptions} defaults Default {@link IParseOptions}
+ */
+function parse(source, root, options) {
+    /* eslint-disable callback-return */
+    if (!(root instanceof Root)) {
+        options = root;
+        root = new Root();
+    }
+    if (!options)
+        options = parse.defaults;
+
+    var preferTrailingComment = options.preferTrailingComment || false;
+    var tn = tokenize(source, options.alternateCommentMode || false),
+        next = tn.next,
+        push = tn.push,
+        peek = tn.peek,
+        skip = tn.skip,
+        cmnt = tn.cmnt;
+
+    var head = true,
+        pkg,
+        imports,
+        weakImports,
+        syntax,
+        isProto3 = false;
+
+    var ptr = root;
+
+    var applyCase = options.keepCase ? function(name) { return name; } : util.camelCase;
+
+    /* istanbul ignore next */
+    function illegal(token, name, insideTryCatch) {
+        var filename = parse.filename;
+        if (!insideTryCatch)
+            parse.filename = null;
+        return Error("illegal " + (name || "token") + " '" + token + "' (" + (filename ? filename + ", " : "") + "line " + tn.line + ")");
+    }
+
+    function readString() {
+        var values = [],
+            token;
+        do {
+            /* istanbul ignore if */
+            if ((token = next()) !== "\"" && token !== "'")
+                throw illegal(token);
+
+            values.push(next());
+            skip(token);
+            token = peek();
+        } while (token === "\"" || token === "'");
+        return values.join("");
+    }
+
+    function readValue(acceptTypeRef) {
+        var token = next();
+        switch (token) {
+            case "'":
+            case "\"":
+                push(token);
+                return readString();
+            case "true": case "TRUE":
+                return true;
+            case "false": case "FALSE":
+                return false;
+        }
+        try {
+            return parseNumber(token, /* insideTryCatch */ true);
+        } catch (e) {
+
+            /* istanbul ignore else */
+            if (acceptTypeRef && typeRefRe.test(token))
+                return token;
+
+            /* istanbul ignore next */
+            throw illegal(token, "value");
+        }
+    }
+
+    function readRanges(target, acceptStrings) {
+        var token, start;
+        do {
+            if (acceptStrings && ((token = peek()) === "\"" || token === "'"))
+                target.push(readString());
+            else
+                target.push([ start = parseId(next()), skip("to", true) ? parseId(next()) : start ]);
+        } while (skip(",", true));
+        skip(";");
+    }
+
+    function parseNumber(token, insideTryCatch) {
+        var sign = 1;
+        if (token.charAt(0) === "-") {
+            sign = -1;
+            token = token.substring(1);
+        }
+        switch (token) {
+            case "inf": case "INF": case "Inf":
+                return sign * Infinity;
+            case "nan": case "NAN": case "Nan": case "NaN":
+                return NaN;
+            case "0":
+                return 0;
+        }
+        if (base10Re.test(token))
+            return sign * parseInt(token, 10);
+        if (base16Re.test(token))
+            return sign * parseInt(token, 16);
+        if (base8Re.test(token))
+            return sign * parseInt(token, 8);
+
+        /* istanbul ignore else */
+        if (numberRe.test(token))
+            return sign * parseFloat(token);
+
+        /* istanbul ignore next */
+        throw illegal(token, "number", insideTryCatch);
+    }
+
+    function parseId(token, acceptNegative) {
+        switch (token) {
+            case "max": case "MAX": case "Max":
+                return 536870911;
+            case "0":
+                return 0;
+        }
+
+        /* istanbul ignore if */
+        if (!acceptNegative && token.charAt(0) === "-")
+            throw illegal(token, "id");
+
+        if (base10NegRe.test(token))
+            return parseInt(token, 10);
+        if (base16NegRe.test(token))
+            return parseInt(token, 16);
+
+        /* istanbul ignore else */
+        if (base8NegRe.test(token))
+            return parseInt(token, 8);
+
+        /* istanbul ignore next */
+        throw illegal(token, "id");
+    }
+
+    function parsePackage() {
+
+        /* istanbul ignore if */
+        if (pkg !== undefined)
+            throw illegal("package");
+
+        pkg = next();
+
+        /* istanbul ignore if */
+        if (!typeRefRe.test(pkg))
+            throw illegal(pkg, "name");
+
+        ptr = ptr.define(pkg);
+        skip(";");
+    }
+
+    function parseImport() {
+        var token = peek();
+        var whichImports;
+        switch (token) {
+            case "weak":
+                whichImports = weakImports || (weakImports = []);
+                next();
+                break;
+            case "public":
+                next();
+                // eslint-disable-line no-fallthrough
+            default:
+                whichImports = imports || (imports = []);
+                break;
+        }
+        token = readString();
+        skip(";");
+        whichImports.push(token);
+    }
+
+    function parseSyntax() {
+        skip("=");
+        syntax = readString();
+        isProto3 = syntax === "proto3";
+
+        /* istanbul ignore if */
+        if (!isProto3 && syntax !== "proto2")
+            throw illegal(syntax, "syntax");
+
+        skip(";");
+    }
+
+    function parseCommon(parent, token) {
+        switch (token) {
+
+            case "option":
+                parseOption(parent, token);
+                skip(";");
+                return true;
+
+            case "message":
+                parseType(parent, token);
+                return true;
+
+            case "enum":
+                parseEnum(parent, token);
+                return true;
+
+            case "service":
+                parseService(parent, token);
+                return true;
+
+            case "extend":
+                parseExtension(parent, token);
+                return true;
+        }
+        return false;
+    }
+
+    function ifBlock(obj, fnIf, fnElse) {
+        var trailingLine = tn.line;
+        if (obj) {
+            if(typeof obj.comment !== "string") {
+              obj.comment = cmnt(); // try block-type comment
+            }
+            obj.filename = parse.filename;
+        }
+        if (skip("{", true)) {
+            var token;
+            while ((token = next()) !== "}")
+                fnIf(token);
+            skip(";", true);
+        } else {
+            if (fnElse)
+                fnElse();
+            skip(";");
+            if (obj && (typeof obj.comment !== "string" || preferTrailingComment))
+                obj.comment = cmnt(trailingLine) || obj.comment; // try line-type comment
+        }
+    }
+
+    function parseType(parent, token) {
+
+        /* istanbul ignore if */
+        if (!nameRe.test(token = next()))
+            throw illegal(token, "type name");
+
+        var type = new Type(token);
+        ifBlock(type, function parseType_block(token) {
+            if (parseCommon(type, token))
+                return;
+
+            switch (token) {
+
+                case "map":
+                    parseMapField(type, token);
+                    break;
+
+                case "required":
+                case "repeated":
+                    parseField(type, token);
+                    break;
+
+                case "optional":
+                    /* istanbul ignore if */
+                    if (isProto3) {
+                        parseField(type, "proto3_optional");
+                    } else {
+                        parseField(type, "optional");
+                    }
+                    break;
+
+                case "oneof":
+                    parseOneOf(type, token);
+                    break;
+
+                case "extensions":
+                    readRanges(type.extensions || (type.extensions = []));
+                    break;
+
+                case "reserved":
+                    readRanges(type.reserved || (type.reserved = []), true);
+                    break;
+
+                default:
+                    /* istanbul ignore if */
+                    if (!isProto3 || !typeRefRe.test(token))
+                        throw illegal(token);
+
+                    push(token);
+                    parseField(type, "optional");
+                    break;
+            }
+        });
+        parent.add(type);
+    }
+
+    function parseField(parent, rule, extend) {
+        var type = next();
+        if (type === "group") {
+            parseGroup(parent, rule);
+            return;
+        }
+
+        /* istanbul ignore if */
+        if (!typeRefRe.test(type))
+            throw illegal(type, "type");
+
+        var name = next();
+
+        /* istanbul ignore if */
+        if (!nameRe.test(name))
+            throw illegal(name, "name");
+
+        name = applyCase(name);
+        skip("=");
+
+        var field = new Field(name, parseId(next()), type, rule, extend);
+        ifBlock(field, function parseField_block(token) {
+
+            /* istanbul ignore else */
+            if (token === "option") {
+                parseOption(field, token);
+                skip(";");
+            } else
+                throw illegal(token);
+
+        }, function parseField_line() {
+            parseInlineOptions(field);
+        });
+
+        if (rule === "proto3_optional") {
+            // for proto3 optional fields, we create a single-member Oneof to mimic "optional" behavior
+            var oneof = new OneOf("_" + name);
+            field.setOption("proto3_optional", true);
+            oneof.add(field);
+            parent.add(oneof);
+        } else {
+            parent.add(field);
+        }
+
+        // JSON defaults to packed=true if not set so we have to set packed=false explicity when
+        // parsing proto2 descriptors without the option, where applicable. This must be done for
+        // all known packable types and anything that could be an enum (= is not a basic type).
+        if (!isProto3 && field.repeated && (types.packed[type] !== undefined || types.basic[type] === undefined))
+            field.setOption("packed", false, /* ifNotSet */ true);
+    }
+
+    function parseGroup(parent, rule) {
+        var name = next();
+
+        /* istanbul ignore if */
+        if (!nameRe.test(name))
+            throw illegal(name, "name");
+
+        var fieldName = util.lcFirst(name);
+        if (name === fieldName)
+            name = util.ucFirst(name);
+        skip("=");
+        var id = parseId(next());
+        var type = new Type(name);
+        type.group = true;
+        var field = new Field(fieldName, id, name, rule);
+        field.filename = parse.filename;
+        ifBlock(type, function parseGroup_block(token) {
+            switch (token) {
+
+                case "option":
+                    parseOption(type, token);
+                    skip(";");
+                    break;
+
+                case "required":
+                case "repeated":
+                    parseField(type, token);
+                    break;
+
+                case "optional":
+                    /* istanbul ignore if */
+                    if (isProto3) {
+                        parseField(type, "proto3_optional");
+                    } else {
+                        parseField(type, "optional");
+                    }
+                    break;
+
+                case "message":
+                    parseType(type, token);
+                    break;
+
+                case "enum":
+                    parseEnum(type, token);
+                    break;
+
+                /* istanbul ignore next */
+                default:
+                    throw illegal(token); // there are no groups with proto3 semantics
+            }
+        });
+        parent.add(type)
+              .add(field);
+    }
+
+    function parseMapField(parent) {
+        skip("<");
+        var keyType = next();
+
+        /* istanbul ignore if */
+        if (types.mapKey[keyType] === undefined)
+            throw illegal(keyType, "type");
+
+        skip(",");
+        var valueType = next();
+
+        /* istanbul ignore if */
+        if (!typeRefRe.test(valueType))
+            throw illegal(valueType, "type");
+
+        skip(">");
+        var name = next();
+
+        /* istanbul ignore if */
+        if (!nameRe.test(name))
+            throw illegal(name, "name");
+
+        skip("=");
+        var field = new MapField(applyCase(name), parseId(next()), keyType, valueType);
+        ifBlock(field, function parseMapField_block(token) {
+
+            /* istanbul ignore else */
+            if (token === "option") {
+                parseOption(field, token);
+                skip(";");
+            } else
+                throw illegal(token);
+
+        }, function parseMapField_line() {
+            parseInlineOptions(field);
+        });
+        parent.add(field);
+    }
+
+    function parseOneOf(parent, token) {
+
+        /* istanbul ignore if */
+        if (!nameRe.test(token = next()))
+            throw illegal(token, "name");
+
+        var oneof = new OneOf(applyCase(token));
+        ifBlock(oneof, function parseOneOf_block(token) {
+            if (token === "option") {
+                parseOption(oneof, token);
+                skip(";");
+            } else {
+                push(token);
+                parseField(oneof, "optional");
+            }
+        });
+        parent.add(oneof);
+    }
+
+    function parseEnum(parent, token) {
+
+        /* istanbul ignore if */
+        if (!nameRe.test(token = next()))
+            throw illegal(token, "name");
+
+        var enm = new Enum(token);
+        ifBlock(enm, function parseEnum_block(token) {
+          switch(token) {
+            case "option":
+              parseOption(enm, token);
+              skip(";");
+              break;
+
+            case "reserved":
+              readRanges(enm.reserved || (enm.reserved = []), true);
+              break;
+
+            default:
+              parseEnumValue(enm, token);
+          }
+        });
+        parent.add(enm);
+    }
+
+    function parseEnumValue(parent, token) {
+
+        /* istanbul ignore if */
+        if (!nameRe.test(token))
+            throw illegal(token, "name");
+
+        skip("=");
+        var value = parseId(next(), true),
+            dummy = {
+                options: undefined
+            };
+        dummy.setOption = function(name, value) {
+            if (this.options === undefined)
+                this.options = {};
+            this.options[name] = value;
+        };
+        ifBlock(dummy, function parseEnumValue_block(token) {
+
+            /* istanbul ignore else */
+            if (token === "option") {
+                parseOption(dummy, token); // skip
+                skip(";");
+            } else
+                throw illegal(token);
+
+        }, function parseEnumValue_line() {
+            parseInlineOptions(dummy); // skip
+        });
+        parent.add(token, value, dummy.comment, dummy.options);
+    }
+
+    function parseOption(parent, token) {
+        var isCustom = skip("(", true);
+
+        /* istanbul ignore if */
+        if (!typeRefRe.test(token = next()))
+            throw illegal(token, "name");
+
+        var name = token;
+        var option = name;
+        var propName;
+
+        if (isCustom) {
+            skip(")");
+            name = "(" + name + ")";
+            option = name;
+            token = peek();
+            if (fqTypeRefRe.test(token)) {
+                propName = token.slice(1); //remove '.' before property name
+                name += token;
+                next();
+            }
+        }
+        skip("=");
+        var optionValue = parseOptionValue(parent, name);
+        setParsedOption(parent, option, optionValue, propName);
+    }
+
+    function parseOptionValue(parent, name) {
+        // { a: "foo" b { c: "bar" } }
+        if (skip("{", true)) {
+            var objectResult = {};
+
+            while (!skip("}", true)) {
+                /* istanbul ignore if */
+                if (!nameRe.test(token = next())) {
+                    throw illegal(token, "name");
+                }
+
+                var value;
+                var propName = token;
+
+                skip(":", true);
+
+                if (peek() === "{")
+                    value = parseOptionValue(parent, name + "." + token);
+                else if (peek() === "[") {
+                    // option (my_option) = {
+                    //     repeated_value: [ "foo", "bar" ]
+                    // };
+                    value = [];
+                    var lastValue;
+                    if (skip("[", true)) {
+                        do {
+                            lastValue = readValue(true);
+                            value.push(lastValue);
+                        } while (skip(",", true));
+                        skip("]");
+                        if (typeof lastValue !== "undefined") {
+                            setOption(parent, name + "." + token, lastValue);
+                        }
+                    }
+                } else {
+                    value = readValue(true);
+                    setOption(parent, name + "." + token, value);
+                }
+
+                var prevValue = objectResult[propName];
+
+                if (prevValue)
+                    value = [].concat(prevValue).concat(value);
+
+                objectResult[propName] = value;
+
+                // Semicolons and commas can be optional
+                skip(",", true);
+                skip(";", true);
+            }
+
+            return objectResult;
+        }
+
+        var simpleValue = readValue(true);
+        setOption(parent, name, simpleValue);
+        return simpleValue;
+        // Does not enforce a delimiter to be universal
+    }
+
+    function setOption(parent, name, value) {
+        if (parent.setOption)
+            parent.setOption(name, value);
+    }
+
+    function setParsedOption(parent, name, value, propName) {
+        if (parent.setParsedOption)
+            parent.setParsedOption(name, value, propName);
+    }
+
+    function parseInlineOptions(parent) {
+        if (skip("[", true)) {
+            do {
+                parseOption(parent, "option");
+            } while (skip(",", true));
+            skip("]");
+        }
+        return parent;
+    }
+
+    function parseService(parent, token) {
+
+        /* istanbul ignore if */
+        if (!nameRe.test(token = next()))
+            throw illegal(token, "service name");
+
+        var service = new Service(token);
+        ifBlock(service, function parseService_block(token) {
+            if (parseCommon(service, token))
+                return;
+
+            /* istanbul ignore else */
+            if (token === "rpc")
+                parseMethod(service, token);
+            else
+                throw illegal(token);
+        });
+        parent.add(service);
+    }
+
+    function parseMethod(parent, token) {
+        // Get the comment of the preceding line now (if one exists) in case the
+        // method is defined across multiple lines.
+        var commentText = cmnt();
+
+        var type = token;
+
+        /* istanbul ignore if */
+        if (!nameRe.test(token = next()))
+            throw illegal(token, "name");
+
+        var name = token,
+            requestType, requestStream,
+            responseType, responseStream;
+
+        skip("(");
+        if (skip("stream", true))
+            requestStream = true;
+
+        /* istanbul ignore if */
+        if (!typeRefRe.test(token = next()))
+            throw illegal(token);
+
+        requestType = token;
+        skip(")"); skip("returns"); skip("(");
+        if (skip("stream", true))
+            responseStream = true;
+
+        /* istanbul ignore if */
+        if (!typeRefRe.test(token = next()))
+            throw illegal(token);
+
+        responseType = token;
+        skip(")");
+
+        var method = new Method(name, type, requestType, responseType, requestStream, responseStream);
+        method.comment = commentText;
+        ifBlock(method, function parseMethod_block(token) {
+
+            /* istanbul ignore else */
+            if (token === "option") {
+                parseOption(method, token);
+                skip(";");
+            } else
+                throw illegal(token);
+
+        });
+        parent.add(method);
+    }
+
+    function parseExtension(parent, token) {
+
+        /* istanbul ignore if */
+        if (!typeRefRe.test(token = next()))
+            throw illegal(token, "reference");
+
+        var reference = token;
+        ifBlock(null, function parseExtension_block(token) {
+            switch (token) {
+
+                case "required":
+                case "repeated":
+                    parseField(parent, token, reference);
+                    break;
+
+                case "optional":
+                    /* istanbul ignore if */
+                    if (isProto3) {
+                        parseField(parent, "proto3_optional", reference);
+                    } else {
+                        parseField(parent, "optional", reference);
+                    }
+                    break;
+
+                default:
+                    /* istanbul ignore if */
+                    if (!isProto3 || !typeRefRe.test(token))
+                        throw illegal(token);
+                    push(token);
+                    parseField(parent, "optional", reference);
+                    break;
+            }
+        });
+    }
+
+    var token;
+    while ((token = next()) !== null) {
+        switch (token) {
+
+            case "package":
+
+                /* istanbul ignore if */
+                if (!head)
+                    throw illegal(token);
+
+                parsePackage();
+                break;
+
+            case "import":
+
+                /* istanbul ignore if */
+                if (!head)
+                    throw illegal(token);
+
+                parseImport();
+                break;
+
+            case "syntax":
+
+                /* istanbul ignore if */
+                if (!head)
+                    throw illegal(token);
+
+                parseSyntax();
+                break;
+
+            case "option":
+
+                parseOption(ptr, token);
+                skip(";");
+                break;
+
+            default:
+
+                /* istanbul ignore else */
+                if (parseCommon(ptr, token)) {
+                    head = false;
+                    continue;
+                }
+
+                /* istanbul ignore next */
+                throw illegal(token);
+        }
+    }
+
+    parse.filename = null;
+    return {
+        "package"     : pkg,
+        "imports"     : imports,
+         weakImports  : weakImports,
+         syntax       : syntax,
+         root         : root
+    };
+}
+
+/**
+ * Parses the given .proto source and returns an object with the parsed contents.
+ * @name parse
+ * @function
+ * @param {string} source Source contents
+ * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+ * @returns {IParserResult} Parser result
+ * @property {string} filename=null Currently processing file name for error reporting, if known
+ * @property {IParseOptions} defaults Default {@link IParseOptions}
+ * @variation 2
+ */
diff --git a/src/reader.js b/src/reader.js
new file mode 100644
index 0000000..1b6ae13
--- /dev/null
+++ b/src/reader.js
@@ -0,0 +1,411 @@
+"use strict";
+module.exports = Reader;
+
+var util      = require("./util/minimal");
+
+var BufferReader; // cyclic
+
+var LongBits  = util.LongBits,
+    utf8      = util.utf8;
+
+/* istanbul ignore next */
+function indexOutOfRange(reader, writeLength) {
+    return RangeError("index out of range: " + reader.pos + " + " + (writeLength || 1) + " > " + reader.len);
+}
+
+/**
+ * Constructs a new reader instance using the specified buffer.
+ * @classdesc Wire format reader using `Uint8Array` if available, otherwise `Array`.
+ * @constructor
+ * @param {Uint8Array} buffer Buffer to read from
+ */
+function Reader(buffer) {
+
+    /**
+     * Read buffer.
+     * @type {Uint8Array}
+     */
+    this.buf = buffer;
+
+    /**
+     * Read buffer position.
+     * @type {number}
+     */
+    this.pos = 0;
+
+    /**
+     * Read buffer length.
+     * @type {number}
+     */
+    this.len = buffer.length;
+}
+
+var create_array = typeof Uint8Array !== "undefined"
+    ? function create_typed_array(buffer) {
+        if (buffer instanceof Uint8Array || Array.isArray(buffer))
+            return new Reader(buffer);
+        throw Error("illegal buffer");
+    }
+    /* istanbul ignore next */
+    : function create_array(buffer) {
+        if (Array.isArray(buffer))
+            return new Reader(buffer);
+        throw Error("illegal buffer");
+    };
+
+var create = function create() {
+    return util.Buffer
+        ? function create_buffer_setup(buffer) {
+            return (Reader.create = function create_buffer(buffer) {
+                return util.Buffer.isBuffer(buffer)
+                    ? new BufferReader(buffer)
+                    /* istanbul ignore next */
+                    : create_array(buffer);
+            })(buffer);
+        }
+        /* istanbul ignore next */
+        : create_array;
+};
+
+/**
+ * Creates a new reader using the specified buffer.
+ * @function
+ * @param {Uint8Array|Buffer} buffer Buffer to read from
+ * @returns {Reader|BufferReader} A {@link BufferReader} if `buffer` is a Buffer, otherwise a {@link Reader}
+ * @throws {Error} If `buffer` is not a valid buffer
+ */
+Reader.create = create();
+
+Reader.prototype._slice = util.Array.prototype.subarray || /* istanbul ignore next */ util.Array.prototype.slice;
+
+/**
+ * Reads a varint as an unsigned 32 bit value.
+ * @function
+ * @returns {number} Value read
+ */
+Reader.prototype.uint32 = (function read_uint32_setup() {
+    var value = 4294967295; // optimizer type-hint, tends to deopt otherwise (?!)
+    return function read_uint32() {
+        value = (         this.buf[this.pos] & 127       ) >>> 0; if (this.buf[this.pos++] < 128) return value;
+        value = (value | (this.buf[this.pos] & 127) <<  7) >>> 0; if (this.buf[this.pos++] < 128) return value;
+        value = (value | (this.buf[this.pos] & 127) << 14) >>> 0; if (this.buf[this.pos++] < 128) return value;
+        value = (value | (this.buf[this.pos] & 127) << 21) >>> 0; if (this.buf[this.pos++] < 128) return value;
+        value = (value | (this.buf[this.pos] &  15) << 28) >>> 0; if (this.buf[this.pos++] < 128) return value;
+
+        /* istanbul ignore if */
+        if ((this.pos += 5) > this.len) {
+            this.pos = this.len;
+            throw indexOutOfRange(this, 10);
+        }
+        return value;
+    };
+})();
+
+/**
+ * Reads a varint as a signed 32 bit value.
+ * @returns {number} Value read
+ */
+Reader.prototype.int32 = function read_int32() {
+    return this.uint32() | 0;
+};
+
+/**
+ * Reads a zig-zag encoded varint as a signed 32 bit value.
+ * @returns {number} Value read
+ */
+Reader.prototype.sint32 = function read_sint32() {
+    var value = this.uint32();
+    return value >>> 1 ^ -(value & 1) | 0;
+};
+
+/* eslint-disable no-invalid-this */
+
+function readLongVarint() {
+    // tends to deopt with local vars for octet etc.
+    var bits = new LongBits(0, 0);
+    var i = 0;
+    if (this.len - this.pos > 4) { // fast route (lo)
+        for (; i < 4; ++i) {
+            // 1st..4th
+            bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0;
+            if (this.buf[this.pos++] < 128)
+                return bits;
+        }
+        // 5th
+        bits.lo = (bits.lo | (this.buf[this.pos] & 127) << 28) >>> 0;
+        bits.hi = (bits.hi | (this.buf[this.pos] & 127) >>  4) >>> 0;
+        if (this.buf[this.pos++] < 128)
+            return bits;
+        i = 0;
+    } else {
+        for (; i < 3; ++i) {
+            /* istanbul ignore if */
+            if (this.pos >= this.len)
+                throw indexOutOfRange(this);
+            // 1st..3th
+            bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0;
+            if (this.buf[this.pos++] < 128)
+                return bits;
+        }
+        // 4th
+        bits.lo = (bits.lo | (this.buf[this.pos++] & 127) << i * 7) >>> 0;
+        return bits;
+    }
+    if (this.len - this.pos > 4) { // fast route (hi)
+        for (; i < 5; ++i) {
+            // 6th..10th
+            bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0;
+            if (this.buf[this.pos++] < 128)
+                return bits;
+        }
+    } else {
+        for (; i < 5; ++i) {
+            /* istanbul ignore if */
+            if (this.pos >= this.len)
+                throw indexOutOfRange(this);
+            // 6th..10th
+            bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0;
+            if (this.buf[this.pos++] < 128)
+                return bits;
+        }
+    }
+    /* istanbul ignore next */
+    throw Error("invalid varint encoding");
+}
+
+/* eslint-enable no-invalid-this */
+
+/**
+ * Reads a varint as a signed 64 bit value.
+ * @name Reader#int64
+ * @function
+ * @returns {Long} Value read
+ */
+
+/**
+ * Reads a varint as an unsigned 64 bit value.
+ * @name Reader#uint64
+ * @function
+ * @returns {Long} Value read
+ */
+
+/**
+ * Reads a zig-zag encoded varint as a signed 64 bit value.
+ * @name Reader#sint64
+ * @function
+ * @returns {Long} Value read
+ */
+
+/**
+ * Reads a varint as a boolean.
+ * @returns {boolean} Value read
+ */
+Reader.prototype.bool = function read_bool() {
+    return this.uint32() !== 0;
+};
+
+function readFixed32_end(buf, end) { // note that this uses `end`, not `pos`
+    return (buf[end - 4]
+          | buf[end - 3] << 8
+          | buf[end - 2] << 16
+          | buf[end - 1] << 24) >>> 0;
+}
+
+/**
+ * Reads fixed 32 bits as an unsigned 32 bit integer.
+ * @returns {number} Value read
+ */
+Reader.prototype.fixed32 = function read_fixed32() {
+
+    /* istanbul ignore if */
+    if (this.pos + 4 > this.len)
+        throw indexOutOfRange(this, 4);
+
+    return readFixed32_end(this.buf, this.pos += 4);
+};
+
+/**
+ * Reads fixed 32 bits as a signed 32 bit integer.
+ * @returns {number} Value read
+ */
+Reader.prototype.sfixed32 = function read_sfixed32() {
+
+    /* istanbul ignore if */
+    if (this.pos + 4 > this.len)
+        throw indexOutOfRange(this, 4);
+
+    return readFixed32_end(this.buf, this.pos += 4) | 0;
+};
+
+/* eslint-disable no-invalid-this */
+
+function readFixed64(/* this: Reader */) {
+
+    /* istanbul ignore if */
+    if (this.pos + 8 > this.len)
+        throw indexOutOfRange(this, 8);
+
+    return new LongBits(readFixed32_end(this.buf, this.pos += 4), readFixed32_end(this.buf, this.pos += 4));
+}
+
+/* eslint-enable no-invalid-this */
+
+/**
+ * Reads fixed 64 bits.
+ * @name Reader#fixed64
+ * @function
+ * @returns {Long} Value read
+ */
+
+/**
+ * Reads zig-zag encoded fixed 64 bits.
+ * @name Reader#sfixed64
+ * @function
+ * @returns {Long} Value read
+ */
+
+/**
+ * Reads a float (32 bit) as a number.
+ * @function
+ * @returns {number} Value read
+ */
+Reader.prototype.float = function read_float() {
+
+    /* istanbul ignore if */
+    if (this.pos + 4 > this.len)
+        throw indexOutOfRange(this, 4);
+
+    var value = util.float.readFloatLE(this.buf, this.pos);
+    this.pos += 4;
+    return value;
+};
+
+/**
+ * Reads a double (64 bit float) as a number.
+ * @function
+ * @returns {number} Value read
+ */
+Reader.prototype.double = function read_double() {
+
+    /* istanbul ignore if */
+    if (this.pos + 8 > this.len)
+        throw indexOutOfRange(this, 4);
+
+    var value = util.float.readDoubleLE(this.buf, this.pos);
+    this.pos += 8;
+    return value;
+};
+
+/**
+ * Reads a sequence of bytes preceeded by its length as a varint.
+ * @returns {Uint8Array} Value read
+ */
+Reader.prototype.bytes = function read_bytes() {
+    var length = this.uint32(),
+        start  = this.pos,
+        end    = this.pos + length;
+
+    /* istanbul ignore if */
+    if (end > this.len)
+        throw indexOutOfRange(this, length);
+
+    this.pos += length;
+    if (Array.isArray(this.buf)) // plain array
+        return this.buf.slice(start, end);
+    return start === end // fix for IE 10/Win8 and others' subarray returning array of size 1
+        ? new this.buf.constructor(0)
+        : this._slice.call(this.buf, start, end);
+};
+
+/**
+ * Reads a string preceeded by its byte length as a varint.
+ * @returns {string} Value read
+ */
+Reader.prototype.string = function read_string() {
+    var bytes = this.bytes();
+    return utf8.read(bytes, 0, bytes.length);
+};
+
+/**
+ * Skips the specified number of bytes if specified, otherwise skips a varint.
+ * @param {number} [length] Length if known, otherwise a varint is assumed
+ * @returns {Reader} `this`
+ */
+Reader.prototype.skip = function skip(length) {
+    if (typeof length === "number") {
+        /* istanbul ignore if */
+        if (this.pos + length > this.len)
+            throw indexOutOfRange(this, length);
+        this.pos += length;
+    } else {
+        do {
+            /* istanbul ignore if */
+            if (this.pos >= this.len)
+                throw indexOutOfRange(this);
+        } while (this.buf[this.pos++] & 128);
+    }
+    return this;
+};
+
+/**
+ * Skips the next element of the specified wire type.
+ * @param {number} wireType Wire type received
+ * @returns {Reader} `this`
+ */
+Reader.prototype.skipType = function(wireType) {
+    switch (wireType) {
+        case 0:
+            this.skip();
+            break;
+        case 1:
+            this.skip(8);
+            break;
+        case 2:
+            this.skip(this.uint32());
+            break;
+        case 3:
+            while ((wireType = this.uint32() & 7) !== 4) {
+                this.skipType(wireType);
+            }
+            break;
+        case 5:
+            this.skip(4);
+            break;
+
+        /* istanbul ignore next */
+        default:
+            throw Error("invalid wire type " + wireType + " at offset " + this.pos);
+    }
+    return this;
+};
+
+Reader._configure = function(BufferReader_) {
+    BufferReader = BufferReader_;
+    Reader.create = create();
+    BufferReader._configure();
+
+    var fn = util.Long ? "toLong" : /* istanbul ignore next */ "toNumber";
+    util.merge(Reader.prototype, {
+
+        int64: function read_int64() {
+            return readLongVarint.call(this)[fn](false);
+        },
+
+        uint64: function read_uint64() {
+            return readLongVarint.call(this)[fn](true);
+        },
+
+        sint64: function read_sint64() {
+            return readLongVarint.call(this).zzDecode()[fn](false);
+        },
+
+        fixed64: function read_fixed64() {
+            return readFixed64.call(this)[fn](true);
+        },
+
+        sfixed64: function read_sfixed64() {
+            return readFixed64.call(this)[fn](false);
+        }
+
+    });
+};
diff --git a/src/reader_buffer.js b/src/reader_buffer.js
new file mode 100644
index 0000000..e547424
--- /dev/null
+++ b/src/reader_buffer.js
@@ -0,0 +1,51 @@
+"use strict";
+module.exports = BufferReader;
+
+// extends Reader
+var Reader = require("./reader");
+(BufferReader.prototype = Object.create(Reader.prototype)).constructor = BufferReader;
+
+var util = require("./util/minimal");
+
+/**
+ * Constructs a new buffer reader instance.
+ * @classdesc Wire format reader using node buffers.
+ * @extends Reader
+ * @constructor
+ * @param {Buffer} buffer Buffer to read from
+ */
+function BufferReader(buffer) {
+    Reader.call(this, buffer);
+
+    /**
+     * Read buffer.
+     * @name BufferReader#buf
+     * @type {Buffer}
+     */
+}
+
+BufferReader._configure = function () {
+    /* istanbul ignore else */
+    if (util.Buffer)
+        BufferReader.prototype._slice = util.Buffer.prototype.slice;
+};
+
+
+/**
+ * @override
+ */
+BufferReader.prototype.string = function read_string_buffer() {
+    var len = this.uint32(); // modifies pos
+    return this.buf.utf8Slice
+        ? this.buf.utf8Slice(this.pos, this.pos = Math.min(this.pos + len, this.len))
+        : this.buf.toString("utf-8", this.pos, this.pos = Math.min(this.pos + len, this.len));
+};
+
+/**
+ * Reads a sequence of bytes preceeded by its length as a varint.
+ * @name BufferReader#bytes
+ * @function
+ * @returns {Buffer} Value read
+ */
+
+BufferReader._configure();
diff --git a/src/root.js b/src/root.js
new file mode 100644
index 0000000..9441a7f
--- /dev/null
+++ b/src/root.js
@@ -0,0 +1,368 @@
+"use strict";
+module.exports = Root;
+
+// extends Namespace
+var Namespace = require("./namespace");
+((Root.prototype = Object.create(Namespace.prototype)).constructor = Root).className = "Root";
+
+var Field   = require("./field"),
+    Enum    = require("./enum"),
+    OneOf   = require("./oneof"),
+    util    = require("./util");
+
+var Type,   // cyclic
+    parse,  // might be excluded
+    common; // "
+
+/**
+ * Constructs a new root namespace instance.
+ * @classdesc Root namespace wrapping all types, enums, services, sub-namespaces etc. that belong together.
+ * @extends NamespaceBase
+ * @constructor
+ * @param {Object.<string,*>} [options] Top level options
+ */
+function Root(options) {
+    Namespace.call(this, "", options);
+
+    /**
+     * Deferred extension fields.
+     * @type {Field[]}
+     */
+    this.deferred = [];
+
+    /**
+     * Resolved file names of loaded files.
+     * @type {string[]}
+     */
+    this.files = [];
+}
+
+/**
+ * Loads a namespace descriptor into a root namespace.
+ * @param {INamespace} json Nameespace descriptor
+ * @param {Root} [root] Root namespace, defaults to create a new one if omitted
+ * @returns {Root} Root namespace
+ */
+Root.fromJSON = function fromJSON(json, root) {
+    if (!root)
+        root = new Root();
+    if (json.options)
+        root.setOptions(json.options);
+    return root.addJSON(json.nested);
+};
+
+/**
+ * Resolves the path of an imported file, relative to the importing origin.
+ * This method exists so you can override it with your own logic in case your imports are scattered over multiple directories.
+ * @function
+ * @param {string} origin The file name of the importing file
+ * @param {string} target The file name being imported
+ * @returns {string|null} Resolved path to `target` or `null` to skip the file
+ */
+Root.prototype.resolvePath = util.path.resolve;
+
+/**
+ * Fetch content from file path or url
+ * This method exists so you can override it with your own logic.
+ * @function
+ * @param {string} path File path or url
+ * @param {FetchCallback} callback Callback function
+ * @returns {undefined}
+ */
+Root.prototype.fetch = util.fetch;
+
+// A symbol-like function to safely signal synchronous loading
+/* istanbul ignore next */
+function SYNC() {} // eslint-disable-line no-empty-function
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into this root namespace and calls the callback.
+ * @param {string|string[]} filename Names of one or multiple files to load
+ * @param {IParseOptions} options Parse options
+ * @param {LoadCallback} callback Callback function
+ * @returns {undefined}
+ */
+Root.prototype.load = function load(filename, options, callback) {
+    if (typeof options === "function") {
+        callback = options;
+        options = undefined;
+    }
+    var self = this;
+    if (!callback)
+        return util.asPromise(load, self, filename, options);
+
+    var sync = callback === SYNC; // undocumented
+
+    // Finishes loading by calling the callback (exactly once)
+    function finish(err, root) {
+        /* istanbul ignore if */
+        if (!callback)
+            return;
+        var cb = callback;
+        callback = null;
+        if (sync)
+            throw err;
+        cb(err, root);
+    }
+
+    // Bundled definition existence checking
+    function getBundledFileName(filename) {
+        var idx = filename.lastIndexOf("google/protobuf/");
+        if (idx > -1) {
+            var altname = filename.substring(idx);
+            if (altname in common) return altname;
+        }
+        return null;
+    }
+
+    // Processes a single file
+    function process(filename, source) {
+        try {
+            if (util.isString(source) && source.charAt(0) === "{")
+                source = JSON.parse(source);
+            if (!util.isString(source))
+                self.setOptions(source.options).addJSON(source.nested);
+            else {
+                parse.filename = filename;
+                var parsed = parse(source, self, options),
+                    resolved,
+                    i = 0;
+                if (parsed.imports)
+                    for (; i < parsed.imports.length; ++i)
+                        if (resolved = getBundledFileName(parsed.imports[i]) || self.resolvePath(filename, parsed.imports[i]))
+                            fetch(resolved);
+                if (parsed.weakImports)
+                    for (i = 0; i < parsed.weakImports.length; ++i)
+                        if (resolved = getBundledFileName(parsed.weakImports[i]) || self.resolvePath(filename, parsed.weakImports[i]))
+                            fetch(resolved, true);
+            }
+        } catch (err) {
+            finish(err);
+        }
+        if (!sync && !queued)
+            finish(null, self); // only once anyway
+    }
+
+    // Fetches a single file
+    function fetch(filename, weak) {
+        filename = getBundledFileName(filename) || filename;
+
+        // Skip if already loaded / attempted
+        if (self.files.indexOf(filename) > -1)
+            return;
+        self.files.push(filename);
+
+        // Shortcut bundled definitions
+        if (filename in common) {
+            if (sync)
+                process(filename, common[filename]);
+            else {
+                ++queued;
+                setTimeout(function() {
+                    --queued;
+                    process(filename, common[filename]);
+                });
+            }
+            return;
+        }
+
+        // Otherwise fetch from disk or network
+        if (sync) {
+            var source;
+            try {
+                source = util.fs.readFileSync(filename).toString("utf8");
+            } catch (err) {
+                if (!weak)
+                    finish(err);
+                return;
+            }
+            process(filename, source);
+        } else {
+            ++queued;
+            self.fetch(filename, function(err, source) {
+                --queued;
+                /* istanbul ignore if */
+                if (!callback)
+                    return; // terminated meanwhile
+                if (err) {
+                    /* istanbul ignore else */
+                    if (!weak)
+                        finish(err);
+                    else if (!queued) // can't be covered reliably
+                        finish(null, self);
+                    return;
+                }
+                process(filename, source);
+            });
+        }
+    }
+    var queued = 0;
+
+    // Assembling the root namespace doesn't require working type
+    // references anymore, so we can load everything in parallel
+    if (util.isString(filename))
+        filename = [ filename ];
+    for (var i = 0, resolved; i < filename.length; ++i)
+        if (resolved = self.resolvePath("", filename[i]))
+            fetch(resolved);
+
+    if (sync)
+        return self;
+    if (!queued)
+        finish(null, self);
+    return undefined;
+};
+// function load(filename:string, options:IParseOptions, callback:LoadCallback):undefined
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into this root namespace and calls the callback.
+ * @function Root#load
+ * @param {string|string[]} filename Names of one or multiple files to load
+ * @param {LoadCallback} callback Callback function
+ * @returns {undefined}
+ * @variation 2
+ */
+// function load(filename:string, callback:LoadCallback):undefined
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into this root namespace and returns a promise.
+ * @function Root#load
+ * @param {string|string[]} filename Names of one or multiple files to load
+ * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+ * @returns {Promise<Root>} Promise
+ * @variation 3
+ */
+// function load(filename:string, [options:IParseOptions]):Promise<Root>
+
+/**
+ * Synchronously loads one or multiple .proto or preprocessed .json files into this root namespace (node only).
+ * @function Root#loadSync
+ * @param {string|string[]} filename Names of one or multiple files to load
+ * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+ * @returns {Root} Root namespace
+ * @throws {Error} If synchronous fetching is not supported (i.e. in browsers) or if a file's syntax is invalid
+ */
+Root.prototype.loadSync = function loadSync(filename, options) {
+    if (!util.isNode)
+        throw Error("not supported");
+    return this.load(filename, options, SYNC);
+};
+
+/**
+ * @override
+ */
+Root.prototype.resolveAll = function resolveAll() {
+    if (this.deferred.length)
+        throw Error("unresolvable extensions: " + this.deferred.map(function(field) {
+            return "'extend " + field.extend + "' in " + field.parent.fullName;
+        }).join(", "));
+    return Namespace.prototype.resolveAll.call(this);
+};
+
+// only uppercased (and thus conflict-free) children are exposed, see below
+var exposeRe = /^[A-Z]/;
+
+/**
+ * Handles a deferred declaring extension field by creating a sister field to represent it within its extended type.
+ * @param {Root} root Root instance
+ * @param {Field} field Declaring extension field witin the declaring type
+ * @returns {boolean} `true` if successfully added to the extended type, `false` otherwise
+ * @inner
+ * @ignore
+ */
+function tryHandleExtension(root, field) {
+    var extendedType = field.parent.lookup(field.extend);
+    if (extendedType) {
+        var sisterField = new Field(field.fullName, field.id, field.type, field.rule, undefined, field.options);
+        //do not allow to extend same field twice to prevent the error
+        if (extendedType.get(sisterField.name)) {
+            return true;
+        }
+        sisterField.declaringField = field;
+        field.extensionField = sisterField;
+        extendedType.add(sisterField);
+        return true;
+    }
+    return false;
+}
+
+/**
+ * Called when any object is added to this root or its sub-namespaces.
+ * @param {ReflectionObject} object Object added
+ * @returns {undefined}
+ * @private
+ */
+Root.prototype._handleAdd = function _handleAdd(object) {
+    if (object instanceof Field) {
+
+        if (/* an extension field (implies not part of a oneof) */ object.extend !== undefined && /* not already handled */ !object.extensionField)
+            if (!tryHandleExtension(this, object))
+                this.deferred.push(object);
+
+    } else if (object instanceof Enum) {
+
+        if (exposeRe.test(object.name))
+            object.parent[object.name] = object.values; // expose enum values as property of its parent
+
+    } else if (!(object instanceof OneOf)) /* everything else is a namespace */ {
+
+        if (object instanceof Type) // Try to handle any deferred extensions
+            for (var i = 0; i < this.deferred.length;)
+                if (tryHandleExtension(this, this.deferred[i]))
+                    this.deferred.splice(i, 1);
+                else
+                    ++i;
+        for (var j = 0; j < /* initializes */ object.nestedArray.length; ++j) // recurse into the namespace
+            this._handleAdd(object._nestedArray[j]);
+        if (exposeRe.test(object.name))
+            object.parent[object.name] = object; // expose namespace as property of its parent
+    }
+
+    // The above also adds uppercased (and thus conflict-free) nested types, services and enums as
+    // properties of namespaces just like static code does. This allows using a .d.ts generated for
+    // a static module with reflection-based solutions where the condition is met.
+};
+
+/**
+ * Called when any object is removed from this root or its sub-namespaces.
+ * @param {ReflectionObject} object Object removed
+ * @returns {undefined}
+ * @private
+ */
+Root.prototype._handleRemove = function _handleRemove(object) {
+    if (object instanceof Field) {
+
+        if (/* an extension field */ object.extend !== undefined) {
+            if (/* already handled */ object.extensionField) { // remove its sister field
+                object.extensionField.parent.remove(object.extensionField);
+                object.extensionField = null;
+            } else { // cancel the extension
+                var index = this.deferred.indexOf(object);
+                /* istanbul ignore else */
+                if (index > -1)
+                    this.deferred.splice(index, 1);
+            }
+        }
+
+    } else if (object instanceof Enum) {
+
+        if (exposeRe.test(object.name))
+            delete object.parent[object.name]; // unexpose enum values
+
+    } else if (object instanceof Namespace) {
+
+        for (var i = 0; i < /* initializes */ object.nestedArray.length; ++i) // recurse into the namespace
+            this._handleRemove(object._nestedArray[i]);
+
+        if (exposeRe.test(object.name))
+            delete object.parent[object.name]; // unexpose namespaces
+
+    }
+};
+
+// Sets up cyclic dependencies (called in index-light)
+Root._configure = function(Type_, parse_, common_) {
+    Type   = Type_;
+    parse  = parse_;
+    common = common_;
+};
diff --git a/src/roots.js b/src/roots.js
new file mode 100644
index 0000000..1d93086
--- /dev/null
+++ b/src/roots.js
@@ -0,0 +1,18 @@
+"use strict";
+module.exports = {};
+
+/**
+ * Named roots.
+ * This is where pbjs stores generated structures (the option `-r, --root` specifies a name).
+ * Can also be used manually to make roots available across modules.
+ * @name roots
+ * @type {Object.<string,Root>}
+ * @example
+ * // pbjs -r myroot -o compiled.js ...
+ *
+ * // in another module:
+ * require("./compiled.js");
+ *
+ * // in any subsequent module:
+ * var root = protobuf.roots["myroot"];
+ */
diff --git a/src/rpc.js b/src/rpc.js
new file mode 100644
index 0000000..894e5c7
--- /dev/null
+++ b/src/rpc.js
@@ -0,0 +1,36 @@
+"use strict";
+
+/**
+ * Streaming RPC helpers.
+ * @namespace
+ */
+var rpc = exports;
+
+/**
+ * RPC implementation passed to {@link Service#create} performing a service request on network level, i.e. by utilizing http requests or websockets.
+ * @typedef RPCImpl
+ * @type {function}
+ * @param {Method|rpc.ServiceMethod<Message<{}>,Message<{}>>} method Reflected or static method being called
+ * @param {Uint8Array} requestData Request data
+ * @param {RPCImplCallback} callback Callback function
+ * @returns {undefined}
+ * @example
+ * function rpcImpl(method, requestData, callback) {
+ *     if (protobuf.util.lcFirst(method.name) !== "myMethod") // compatible with static code
+ *         throw Error("no such method");
+ *     asynchronouslyObtainAResponse(requestData, function(err, responseData) {
+ *         callback(err, responseData);
+ *     });
+ * }
+ */
+
+/**
+ * Node-style callback as used by {@link RPCImpl}.
+ * @typedef RPCImplCallback
+ * @type {function}
+ * @param {Error|null} error Error, if any, otherwise `null`
+ * @param {Uint8Array|null} [response] Response data or `null` to signal end of stream, if there hasn't been an error
+ * @returns {undefined}
+ */
+
+rpc.Service = require("./rpc/service");
diff --git a/src/rpc/service.js b/src/rpc/service.js
new file mode 100644
index 0000000..757f382
--- /dev/null
+++ b/src/rpc/service.js
@@ -0,0 +1,142 @@
+"use strict";
+module.exports = Service;
+
+var util = require("../util/minimal");
+
+// Extends EventEmitter
+(Service.prototype = Object.create(util.EventEmitter.prototype)).constructor = Service;
+
+/**
+ * A service method callback as used by {@link rpc.ServiceMethod|ServiceMethod}.
+ *
+ * Differs from {@link RPCImplCallback} in that it is an actual callback of a service method which may not return `response = null`.
+ * @typedef rpc.ServiceMethodCallback
+ * @template TRes extends Message<TRes>
+ * @type {function}
+ * @param {Error|null} error Error, if any
+ * @param {TRes} [response] Response message
+ * @returns {undefined}
+ */
+
+/**
+ * A service method part of a {@link rpc.Service} as created by {@link Service.create}.
+ * @typedef rpc.ServiceMethod
+ * @template TReq extends Message<TReq>
+ * @template TRes extends Message<TRes>
+ * @type {function}
+ * @param {TReq|Properties<TReq>} request Request message or plain object
+ * @param {rpc.ServiceMethodCallback<TRes>} [callback] Node-style callback called with the error, if any, and the response message
+ * @returns {Promise<Message<TRes>>} Promise if `callback` has been omitted, otherwise `undefined`
+ */
+
+/**
+ * Constructs a new RPC service instance.
+ * @classdesc An RPC service as returned by {@link Service#create}.
+ * @exports rpc.Service
+ * @extends util.EventEmitter
+ * @constructor
+ * @param {RPCImpl} rpcImpl RPC implementation
+ * @param {boolean} [requestDelimited=false] Whether requests are length-delimited
+ * @param {boolean} [responseDelimited=false] Whether responses are length-delimited
+ */
+function Service(rpcImpl, requestDelimited, responseDelimited) {
+
+    if (typeof rpcImpl !== "function")
+        throw TypeError("rpcImpl must be a function");
+
+    util.EventEmitter.call(this);
+
+    /**
+     * RPC implementation. Becomes `null` once the service is ended.
+     * @type {RPCImpl|null}
+     */
+    this.rpcImpl = rpcImpl;
+
+    /**
+     * Whether requests are length-delimited.
+     * @type {boolean}
+     */
+    this.requestDelimited = Boolean(requestDelimited);
+
+    /**
+     * Whether responses are length-delimited.
+     * @type {boolean}
+     */
+    this.responseDelimited = Boolean(responseDelimited);
+}
+
+/**
+ * Calls a service method through {@link rpc.Service#rpcImpl|rpcImpl}.
+ * @param {Method|rpc.ServiceMethod<TReq,TRes>} method Reflected or static method
+ * @param {Constructor<TReq>} requestCtor Request constructor
+ * @param {Constructor<TRes>} responseCtor Response constructor
+ * @param {TReq|Properties<TReq>} request Request message or plain object
+ * @param {rpc.ServiceMethodCallback<TRes>} callback Service callback
+ * @returns {undefined}
+ * @template TReq extends Message<TReq>
+ * @template TRes extends Message<TRes>
+ */
+Service.prototype.rpcCall = function rpcCall(method, requestCtor, responseCtor, request, callback) {
+
+    if (!request)
+        throw TypeError("request must be specified");
+
+    var self = this;
+    if (!callback)
+        return util.asPromise(rpcCall, self, method, requestCtor, responseCtor, request);
+
+    if (!self.rpcImpl) {
+        setTimeout(function() { callback(Error("already ended")); }, 0);
+        return undefined;
+    }
+
+    try {
+        return self.rpcImpl(
+            method,
+            requestCtor[self.requestDelimited ? "encodeDelimited" : "encode"](request).finish(),
+            function rpcCallback(err, response) {
+
+                if (err) {
+                    self.emit("error", err, method);
+                    return callback(err);
+                }
+
+                if (response === null) {
+                    self.end(/* endedByRPC */ true);
+                    return undefined;
+                }
+
+                if (!(response instanceof responseCtor)) {
+                    try {
+                        response = responseCtor[self.responseDelimited ? "decodeDelimited" : "decode"](response);
+                    } catch (err) {
+                        self.emit("error", err, method);
+                        return callback(err);
+                    }
+                }
+
+                self.emit("data", response, method);
+                return callback(null, response);
+            }
+        );
+    } catch (err) {
+        self.emit("error", err, method);
+        setTimeout(function() { callback(err); }, 0);
+        return undefined;
+    }
+};
+
+/**
+ * Ends this service and emits the `end` event.
+ * @param {boolean} [endedByRPC=false] Whether the service has been ended by the RPC implementation.
+ * @returns {rpc.Service} `this`
+ */
+Service.prototype.end = function end(endedByRPC) {
+    if (this.rpcImpl) {
+        if (!endedByRPC) // signal end to rpcImpl
+            this.rpcImpl(null, null, null);
+        this.rpcImpl = null;
+        this.emit("end").off();
+    }
+    return this;
+};
diff --git a/src/service.js b/src/service.js
new file mode 100644
index 0000000..bc2c308
--- /dev/null
+++ b/src/service.js
@@ -0,0 +1,167 @@
+"use strict";
+module.exports = Service;
+
+// extends Namespace
+var Namespace = require("./namespace");
+((Service.prototype = Object.create(Namespace.prototype)).constructor = Service).className = "Service";
+
+var Method = require("./method"),
+    util   = require("./util"),
+    rpc    = require("./rpc");
+
+/**
+ * Constructs a new service instance.
+ * @classdesc Reflected service.
+ * @extends NamespaceBase
+ * @constructor
+ * @param {string} name Service name
+ * @param {Object.<string,*>} [options] Service options
+ * @throws {TypeError} If arguments are invalid
+ */
+function Service(name, options) {
+    Namespace.call(this, name, options);
+
+    /**
+     * Service methods.
+     * @type {Object.<string,Method>}
+     */
+    this.methods = {}; // toJSON, marker
+
+    /**
+     * Cached methods as an array.
+     * @type {Method[]|null}
+     * @private
+     */
+    this._methodsArray = null;
+}
+
+/**
+ * Service descriptor.
+ * @interface IService
+ * @extends INamespace
+ * @property {Object.<string,IMethod>} methods Method descriptors
+ */
+
+/**
+ * Constructs a service from a service descriptor.
+ * @param {string} name Service name
+ * @param {IService} json Service descriptor
+ * @returns {Service} Created service
+ * @throws {TypeError} If arguments are invalid
+ */
+Service.fromJSON = function fromJSON(name, json) {
+    var service = new Service(name, json.options);
+    /* istanbul ignore else */
+    if (json.methods)
+        for (var names = Object.keys(json.methods), i = 0; i < names.length; ++i)
+            service.add(Method.fromJSON(names[i], json.methods[names[i]]));
+    if (json.nested)
+        service.addJSON(json.nested);
+    service.comment = json.comment;
+    return service;
+};
+
+/**
+ * Converts this service to a service descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {IService} Service descriptor
+ */
+Service.prototype.toJSON = function toJSON(toJSONOptions) {
+    var inherited = Namespace.prototype.toJSON.call(this, toJSONOptions);
+    var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
+    return util.toObject([
+        "options" , inherited && inherited.options || undefined,
+        "methods" , Namespace.arrayToJSON(this.methodsArray, toJSONOptions) || /* istanbul ignore next */ {},
+        "nested"  , inherited && inherited.nested || undefined,
+        "comment" , keepComments ? this.comment : undefined
+    ]);
+};
+
+/**
+ * Methods of this service as an array for iteration.
+ * @name Service#methodsArray
+ * @type {Method[]}
+ * @readonly
+ */
+Object.defineProperty(Service.prototype, "methodsArray", {
+    get: function() {
+        return this._methodsArray || (this._methodsArray = util.toArray(this.methods));
+    }
+});
+
+function clearCache(service) {
+    service._methodsArray = null;
+    return service;
+}
+
+/**
+ * @override
+ */
+Service.prototype.get = function get(name) {
+    return this.methods[name]
+        || Namespace.prototype.get.call(this, name);
+};
+
+/**
+ * @override
+ */
+Service.prototype.resolveAll = function resolveAll() {
+    var methods = this.methodsArray;
+    for (var i = 0; i < methods.length; ++i)
+        methods[i].resolve();
+    return Namespace.prototype.resolve.call(this);
+};
+
+/**
+ * @override
+ */
+Service.prototype.add = function add(object) {
+
+    /* istanbul ignore if */
+    if (this.get(object.name))
+        throw Error("duplicate name '" + object.name + "' in " + this);
+
+    if (object instanceof Method) {
+        this.methods[object.name] = object;
+        object.parent = this;
+        return clearCache(this);
+    }
+    return Namespace.prototype.add.call(this, object);
+};
+
+/**
+ * @override
+ */
+Service.prototype.remove = function remove(object) {
+    if (object instanceof Method) {
+
+        /* istanbul ignore if */
+        if (this.methods[object.name] !== object)
+            throw Error(object + " is not a member of " + this);
+
+        delete this.methods[object.name];
+        object.parent = null;
+        return clearCache(this);
+    }
+    return Namespace.prototype.remove.call(this, object);
+};
+
+/**
+ * Creates a runtime service using the specified rpc implementation.
+ * @param {RPCImpl} rpcImpl RPC implementation
+ * @param {boolean} [requestDelimited=false] Whether requests are length-delimited
+ * @param {boolean} [responseDelimited=false] Whether responses are length-delimited
+ * @returns {rpc.Service} RPC service. Useful where requests and/or responses are streamed.
+ */
+Service.prototype.create = function create(rpcImpl, requestDelimited, responseDelimited) {
+    var rpcService = new rpc.Service(rpcImpl, requestDelimited, responseDelimited);
+    for (var i = 0, method; i < /* initializes */ this.methodsArray.length; ++i) {
+        var methodName = util.lcFirst((method = this._methodsArray[i]).resolve().name).replace(/[^$\w_]/g, "");
+        rpcService[methodName] = util.codegen(["r","c"], util.isReserved(methodName) ? methodName + "_" : methodName)("return this.rpcCall(m,q,s,r,c)")({
+            m: method,
+            q: method.resolvedRequestType.ctor,
+            s: method.resolvedResponseType.ctor
+        });
+    }
+    return rpcService;
+};
diff --git a/src/tokenize.js b/src/tokenize.js
new file mode 100644
index 0000000..bfb784b
--- /dev/null
+++ b/src/tokenize.js
@@ -0,0 +1,418 @@
+"use strict";
+module.exports = tokenize;
+
+var delimRe        = /[\s{}=;:[\],'"()<>]/g,
+    stringDoubleRe = /(?:"([^"\\]*(?:\\.[^"\\]*)*)")/g,
+    stringSingleRe = /(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g;
+
+var setCommentRe = /^ *[*/]+ */,
+    setCommentAltRe = /^\s*\*?\/*/,
+    setCommentSplitRe = /\n/g,
+    whitespaceRe = /\s/,
+    unescapeRe = /\\(.?)/g;
+
+var unescapeMap = {
+    "0": "\0",
+    "r": "\r",
+    "n": "\n",
+    "t": "\t"
+};
+
+/**
+ * Unescapes a string.
+ * @param {string} str String to unescape
+ * @returns {string} Unescaped string
+ * @property {Object.<string,string>} map Special characters map
+ * @memberof tokenize
+ */
+function unescape(str) {
+    return str.replace(unescapeRe, function($0, $1) {
+        switch ($1) {
+            case "\\":
+            case "":
+                return $1;
+            default:
+                return unescapeMap[$1] || "";
+        }
+    });
+}
+
+tokenize.unescape = unescape;
+
+/**
+ * Gets the next token and advances.
+ * @typedef TokenizerHandleNext
+ * @type {function}
+ * @returns {string|null} Next token or `null` on eof
+ */
+
+/**
+ * Peeks for the next token.
+ * @typedef TokenizerHandlePeek
+ * @type {function}
+ * @returns {string|null} Next token or `null` on eof
+ */
+
+/**
+ * Pushes a token back to the stack.
+ * @typedef TokenizerHandlePush
+ * @type {function}
+ * @param {string} token Token
+ * @returns {undefined}
+ */
+
+/**
+ * Skips the next token.
+ * @typedef TokenizerHandleSkip
+ * @type {function}
+ * @param {string} expected Expected token
+ * @param {boolean} [optional=false] If optional
+ * @returns {boolean} Whether the token matched
+ * @throws {Error} If the token didn't match and is not optional
+ */
+
+/**
+ * Gets the comment on the previous line or, alternatively, the line comment on the specified line.
+ * @typedef TokenizerHandleCmnt
+ * @type {function}
+ * @param {number} [line] Line number
+ * @returns {string|null} Comment text or `null` if none
+ */
+
+/**
+ * Handle object returned from {@link tokenize}.
+ * @interface ITokenizerHandle
+ * @property {TokenizerHandleNext} next Gets the next token and advances (`null` on eof)
+ * @property {TokenizerHandlePeek} peek Peeks for the next token (`null` on eof)
+ * @property {TokenizerHandlePush} push Pushes a token back to the stack
+ * @property {TokenizerHandleSkip} skip Skips a token, returns its presence and advances or, if non-optional and not present, throws
+ * @property {TokenizerHandleCmnt} cmnt Gets the comment on the previous line or the line comment on the specified line, if any
+ * @property {number} line Current line number
+ */
+
+/**
+ * Tokenizes the given .proto source and returns an object with useful utility functions.
+ * @param {string} source Source contents
+ * @param {boolean} alternateCommentMode Whether we should activate alternate comment parsing mode.
+ * @returns {ITokenizerHandle} Tokenizer handle
+ */
+function tokenize(source, alternateCommentMode) {
+    /* eslint-disable callback-return */
+    source = source.toString();
+
+    var offset = 0,
+        length = source.length,
+        line = 1,
+        lastCommentLine = 0,
+        comments = {};
+
+    var stack = [];
+
+    var stringDelim = null;
+
+    /* istanbul ignore next */
+    /**
+     * Creates an error for illegal syntax.
+     * @param {string} subject Subject
+     * @returns {Error} Error created
+     * @inner
+     */
+    function illegal(subject) {
+        return Error("illegal " + subject + " (line " + line + ")");
+    }
+
+    /**
+     * Reads a string till its end.
+     * @returns {string} String read
+     * @inner
+     */
+    function readString() {
+        var re = stringDelim === "'" ? stringSingleRe : stringDoubleRe;
+        re.lastIndex = offset - 1;
+        var match = re.exec(source);
+        if (!match)
+            throw illegal("string");
+        offset = re.lastIndex;
+        push(stringDelim);
+        stringDelim = null;
+        return unescape(match[1]);
+    }
+
+    /**
+     * Gets the character at `pos` within the source.
+     * @param {number} pos Position
+     * @returns {string} Character
+     * @inner
+     */
+    function charAt(pos) {
+        return source.charAt(pos);
+    }
+
+    /**
+     * Sets the current comment text.
+     * @param {number} start Start offset
+     * @param {number} end End offset
+     * @param {boolean} isLeading set if a leading comment
+     * @returns {undefined}
+     * @inner
+     */
+    function setComment(start, end, isLeading) {
+        var comment = {
+            type: source.charAt(start++),
+            lineEmpty: false,
+            leading: isLeading,
+        };
+        var lookback;
+        if (alternateCommentMode) {
+            lookback = 2;  // alternate comment parsing: "//" or "/*"
+        } else {
+            lookback = 3;  // "///" or "/**"
+        }
+        var commentOffset = start - lookback,
+            c;
+        do {
+            if (--commentOffset < 0 ||
+                    (c = source.charAt(commentOffset)) === "\n") {
+                comment.lineEmpty = true;
+                break;
+            }
+        } while (c === " " || c === "\t");
+        var lines = source
+            .substring(start, end)
+            .split(setCommentSplitRe);
+        for (var i = 0; i < lines.length; ++i)
+            lines[i] = lines[i]
+                .replace(alternateCommentMode ? setCommentAltRe : setCommentRe, "")
+                .trim();
+        comment.text = lines
+            .join("\n")
+            .trim();
+
+        comments[line] = comment;
+        lastCommentLine = line;
+    }
+
+    function isDoubleSlashCommentLine(startOffset) {
+        var endOffset = findEndOfLine(startOffset);
+
+        // see if remaining line matches comment pattern
+        var lineText = source.substring(startOffset, endOffset);
+        // look for 1 or 2 slashes since startOffset would already point past
+        // the first slash that started the comment.
+        var isComment = /^\s*\/{1,2}/.test(lineText);
+        return isComment;
+    }
+
+    function findEndOfLine(cursor) {
+        // find end of cursor's line
+        var endOffset = cursor;
+        while (endOffset < length && charAt(endOffset) !== "\n") {
+            endOffset++;
+        }
+        return endOffset;
+    }
+
+    /**
+     * Obtains the next token.
+     * @returns {string|null} Next token or `null` on eof
+     * @inner
+     */
+    function next() {
+        if (stack.length > 0)
+            return stack.shift();
+        if (stringDelim)
+            return readString();
+        var repeat,
+            prev,
+            curr,
+            start,
+            isDoc,
+            isLeadingComment = offset === 0;
+        do {
+            if (offset === length)
+                return null;
+            repeat = false;
+            while (whitespaceRe.test(curr = charAt(offset))) {
+                if (curr === "\n") {
+                    isLeadingComment = true;
+                    ++line;
+                }
+                if (++offset === length)
+                    return null;
+            }
+
+            if (charAt(offset) === "/") {
+                if (++offset === length) {
+                    throw illegal("comment");
+                }
+                if (charAt(offset) === "/") { // Line
+                    if (!alternateCommentMode) {
+                        // check for triple-slash comment
+                        isDoc = charAt(start = offset + 1) === "/";
+
+                        while (charAt(++offset) !== "\n") {
+                            if (offset === length) {
+                                return null;
+                            }
+                        }
+                        ++offset;
+                        if (isDoc) {
+                            setComment(start, offset - 1, isLeadingComment);
+                            // Trailing comment cannot not be multi-line,
+                            // so leading comment state should be reset to handle potential next comments
+                            isLeadingComment = true;
+                        }
+                        ++line;
+                        repeat = true;
+                    } else {
+                        // check for double-slash comments, consolidating consecutive lines
+                        start = offset;
+                        isDoc = false;
+                        if (isDoubleSlashCommentLine(offset)) {
+                            isDoc = true;
+                            do {
+                                offset = findEndOfLine(offset);
+                                if (offset === length) {
+                                    break;
+                                }
+                                offset++;
+                                if (!isLeadingComment) {
+                                    // Trailing comment cannot not be multi-line
+                                    break;
+                                }
+                            } while (isDoubleSlashCommentLine(offset));
+                        } else {
+                            offset = Math.min(length, findEndOfLine(offset) + 1);
+                        }
+                        if (isDoc) {
+                            setComment(start, offset, isLeadingComment);
+                            isLeadingComment = true;
+                        }
+                        line++;
+                        repeat = true;
+                    }
+                } else if ((curr = charAt(offset)) === "*") { /* Block */
+                    // check for /** (regular comment mode) or /* (alternate comment mode)
+                    start = offset + 1;
+                    isDoc = alternateCommentMode || charAt(start) === "*";
+                    do {
+                        if (curr === "\n") {
+                            ++line;
+                        }
+                        if (++offset === length) {
+                            throw illegal("comment");
+                        }
+                        prev = curr;
+                        curr = charAt(offset);
+                    } while (prev !== "*" || curr !== "/");
+                    ++offset;
+                    if (isDoc) {
+                        setComment(start, offset - 2, isLeadingComment);
+                        isLeadingComment = true;
+                    }
+                    repeat = true;
+                } else {
+                    return "/";
+                }
+            }
+        } while (repeat);
+
+        // offset !== length if we got here
+
+        var end = offset;
+        delimRe.lastIndex = 0;
+        var delim = delimRe.test(charAt(end++));
+        if (!delim)
+            while (end < length && !delimRe.test(charAt(end)))
+                ++end;
+        var token = source.substring(offset, offset = end);
+        if (token === "\"" || token === "'")
+            stringDelim = token;
+        return token;
+    }
+
+    /**
+     * Pushes a token back to the stack.
+     * @param {string} token Token
+     * @returns {undefined}
+     * @inner
+     */
+    function push(token) {
+        stack.push(token);
+    }
+
+    /**
+     * Peeks for the next token.
+     * @returns {string|null} Token or `null` on eof
+     * @inner
+     */
+    function peek() {
+        if (!stack.length) {
+            var token = next();
+            if (token === null)
+                return null;
+            push(token);
+        }
+        return stack[0];
+    }
+
+    /**
+     * Skips a token.
+     * @param {string} expected Expected token
+     * @param {boolean} [optional=false] Whether the token is optional
+     * @returns {boolean} `true` when skipped, `false` if not
+     * @throws {Error} When a required token is not present
+     * @inner
+     */
+    function skip(expected, optional) {
+        var actual = peek(),
+            equals = actual === expected;
+        if (equals) {
+            next();
+            return true;
+        }
+        if (!optional)
+            throw illegal("token '" + actual + "', '" + expected + "' expected");
+        return false;
+    }
+
+    /**
+     * Gets a comment.
+     * @param {number} [trailingLine] Line number if looking for a trailing comment
+     * @returns {string|null} Comment text
+     * @inner
+     */
+    function cmnt(trailingLine) {
+        var ret = null;
+        var comment;
+        if (trailingLine === undefined) {
+            comment = comments[line - 1];
+            delete comments[line - 1];
+            if (comment && (alternateCommentMode || comment.type === "*" || comment.lineEmpty)) {
+                ret = comment.leading ? comment.text : null;
+            }
+        } else {
+            /* istanbul ignore else */
+            if (lastCommentLine < trailingLine) {
+                peek();
+            }
+            comment = comments[trailingLine];
+            delete comments[trailingLine];
+            if (comment && !comment.lineEmpty && (alternateCommentMode || comment.type === "/")) {
+                ret = comment.leading ? null : comment.text;
+            }
+        }
+        return ret;
+    }
+
+    return Object.defineProperty({
+        next: next,
+        peek: peek,
+        push: push,
+        skip: skip,
+        cmnt: cmnt
+    }, "line", {
+        get: function() { return line; }
+    });
+    /* eslint-enable callback-return */
+}
diff --git a/src/type.js b/src/type.js
new file mode 100644
index 0000000..2e7bda4
--- /dev/null
+++ b/src/type.js
@@ -0,0 +1,589 @@
+"use strict";
+module.exports = Type;
+
+// extends Namespace
+var Namespace = require("./namespace");
+((Type.prototype = Object.create(Namespace.prototype)).constructor = Type).className = "Type";
+
+var Enum      = require("./enum"),
+    OneOf     = require("./oneof"),
+    Field     = require("./field"),
+    MapField  = require("./mapfield"),
+    Service   = require("./service"),
+    Message   = require("./message"),
+    Reader    = require("./reader"),
+    Writer    = require("./writer"),
+    util      = require("./util"),
+    encoder   = require("./encoder"),
+    decoder   = require("./decoder"),
+    verifier  = require("./verifier"),
+    converter = require("./converter"),
+    wrappers  = require("./wrappers");
+
+/**
+ * Constructs a new reflected message type instance.
+ * @classdesc Reflected message type.
+ * @extends NamespaceBase
+ * @constructor
+ * @param {string} name Message name
+ * @param {Object.<string,*>} [options] Declared options
+ */
+function Type(name, options) {
+    Namespace.call(this, name, options);
+
+    /**
+     * Message fields.
+     * @type {Object.<string,Field>}
+     */
+    this.fields = {};  // toJSON, marker
+
+    /**
+     * Oneofs declared within this namespace, if any.
+     * @type {Object.<string,OneOf>}
+     */
+    this.oneofs = undefined; // toJSON
+
+    /**
+     * Extension ranges, if any.
+     * @type {number[][]}
+     */
+    this.extensions = undefined; // toJSON
+
+    /**
+     * Reserved ranges, if any.
+     * @type {Array.<number[]|string>}
+     */
+    this.reserved = undefined; // toJSON
+
+    /*?
+     * Whether this type is a legacy group.
+     * @type {boolean|undefined}
+     */
+    this.group = undefined; // toJSON
+
+    /**
+     * Cached fields by id.
+     * @type {Object.<number,Field>|null}
+     * @private
+     */
+    this._fieldsById = null;
+
+    /**
+     * Cached fields as an array.
+     * @type {Field[]|null}
+     * @private
+     */
+    this._fieldsArray = null;
+
+    /**
+     * Cached oneofs as an array.
+     * @type {OneOf[]|null}
+     * @private
+     */
+    this._oneofsArray = null;
+
+    /**
+     * Cached constructor.
+     * @type {Constructor<{}>}
+     * @private
+     */
+    this._ctor = null;
+}
+
+Object.defineProperties(Type.prototype, {
+
+    /**
+     * Message fields by id.
+     * @name Type#fieldsById
+     * @type {Object.<number,Field>}
+     * @readonly
+     */
+    fieldsById: {
+        get: function() {
+
+            /* istanbul ignore if */
+            if (this._fieldsById)
+                return this._fieldsById;
+
+            this._fieldsById = {};
+            for (var names = Object.keys(this.fields), i = 0; i < names.length; ++i) {
+                var field = this.fields[names[i]],
+                    id = field.id;
+
+                /* istanbul ignore if */
+                if (this._fieldsById[id])
+                    throw Error("duplicate id " + id + " in " + this);
+
+                this._fieldsById[id] = field;
+            }
+            return this._fieldsById;
+        }
+    },
+
+    /**
+     * Fields of this message as an array for iteration.
+     * @name Type#fieldsArray
+     * @type {Field[]}
+     * @readonly
+     */
+    fieldsArray: {
+        get: function() {
+            return this._fieldsArray || (this._fieldsArray = util.toArray(this.fields));
+        }
+    },
+
+    /**
+     * Oneofs of this message as an array for iteration.
+     * @name Type#oneofsArray
+     * @type {OneOf[]}
+     * @readonly
+     */
+    oneofsArray: {
+        get: function() {
+            return this._oneofsArray || (this._oneofsArray = util.toArray(this.oneofs));
+        }
+    },
+
+    /**
+     * The registered constructor, if any registered, otherwise a generic constructor.
+     * Assigning a function replaces the internal constructor. If the function does not extend {@link Message} yet, its prototype will be setup accordingly and static methods will be populated. If it already extends {@link Message}, it will just replace the internal constructor.
+     * @name Type#ctor
+     * @type {Constructor<{}>}
+     */
+    ctor: {
+        get: function() {
+            return this._ctor || (this.ctor = Type.generateConstructor(this)());
+        },
+        set: function(ctor) {
+
+            // Ensure proper prototype
+            var prototype = ctor.prototype;
+            if (!(prototype instanceof Message)) {
+                (ctor.prototype = new Message()).constructor = ctor;
+                util.merge(ctor.prototype, prototype);
+            }
+
+            // Classes and messages reference their reflected type
+            ctor.$type = ctor.prototype.$type = this;
+
+            // Mix in static methods
+            util.merge(ctor, Message, true);
+
+            this._ctor = ctor;
+
+            // Messages have non-enumerable default values on their prototype
+            var i = 0;
+            for (; i < /* initializes */ this.fieldsArray.length; ++i)
+                this._fieldsArray[i].resolve(); // ensures a proper value
+
+            // Messages have non-enumerable getters and setters for each virtual oneof field
+            var ctorProperties = {};
+            for (i = 0; i < /* initializes */ this.oneofsArray.length; ++i)
+                ctorProperties[this._oneofsArray[i].resolve().name] = {
+                    get: util.oneOfGetter(this._oneofsArray[i].oneof),
+                    set: util.oneOfSetter(this._oneofsArray[i].oneof)
+                };
+            if (i)
+                Object.defineProperties(ctor.prototype, ctorProperties);
+        }
+    }
+});
+
+/**
+ * Generates a constructor function for the specified type.
+ * @param {Type} mtype Message type
+ * @returns {Codegen} Codegen instance
+ */
+Type.generateConstructor = function generateConstructor(mtype) {
+    /* eslint-disable no-unexpected-multiline */
+    var gen = util.codegen(["p"], mtype.name);
+    // explicitly initialize mutable object/array fields so that these aren't just inherited from the prototype
+    for (var i = 0, field; i < mtype.fieldsArray.length; ++i)
+        if ((field = mtype._fieldsArray[i]).map) gen
+            ("this%s={}", util.safeProp(field.name));
+        else if (field.repeated) gen
+            ("this%s=[]", util.safeProp(field.name));
+    return gen
+    ("if(p)for(var ks=Object.keys(p),i=0;i<ks.length;++i)if(p[ks[i]]!=null)") // omit undefined or null
+        ("this[ks[i]]=p[ks[i]]");
+    /* eslint-enable no-unexpected-multiline */
+};
+
+function clearCache(type) {
+    type._fieldsById = type._fieldsArray = type._oneofsArray = null;
+    delete type.encode;
+    delete type.decode;
+    delete type.verify;
+    return type;
+}
+
+/**
+ * Message type descriptor.
+ * @interface IType
+ * @extends INamespace
+ * @property {Object.<string,IOneOf>} [oneofs] Oneof descriptors
+ * @property {Object.<string,IField>} fields Field descriptors
+ * @property {number[][]} [extensions] Extension ranges
+ * @property {number[][]} [reserved] Reserved ranges
+ * @property {boolean} [group=false] Whether a legacy group or not
+ */
+
+/**
+ * Creates a message type from a message type descriptor.
+ * @param {string} name Message name
+ * @param {IType} json Message type descriptor
+ * @returns {Type} Created message type
+ */
+Type.fromJSON = function fromJSON(name, json) {
+    var type = new Type(name, json.options);
+    type.extensions = json.extensions;
+    type.reserved = json.reserved;
+    var names = Object.keys(json.fields),
+        i = 0;
+    for (; i < names.length; ++i)
+        type.add(
+            ( typeof json.fields[names[i]].keyType !== "undefined"
+            ? MapField.fromJSON
+            : Field.fromJSON )(names[i], json.fields[names[i]])
+        );
+    if (json.oneofs)
+        for (names = Object.keys(json.oneofs), i = 0; i < names.length; ++i)
+            type.add(OneOf.fromJSON(names[i], json.oneofs[names[i]]));
+    if (json.nested)
+        for (names = Object.keys(json.nested), i = 0; i < names.length; ++i) {
+            var nested = json.nested[names[i]];
+            type.add( // most to least likely
+                ( nested.id !== undefined
+                ? Field.fromJSON
+                : nested.fields !== undefined
+                ? Type.fromJSON
+                : nested.values !== undefined
+                ? Enum.fromJSON
+                : nested.methods !== undefined
+                ? Service.fromJSON
+                : Namespace.fromJSON )(names[i], nested)
+            );
+        }
+    if (json.extensions && json.extensions.length)
+        type.extensions = json.extensions;
+    if (json.reserved && json.reserved.length)
+        type.reserved = json.reserved;
+    if (json.group)
+        type.group = true;
+    if (json.comment)
+        type.comment = json.comment;
+    return type;
+};
+
+/**
+ * Converts this message type to a message type descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {IType} Message type descriptor
+ */
+Type.prototype.toJSON = function toJSON(toJSONOptions) {
+    var inherited = Namespace.prototype.toJSON.call(this, toJSONOptions);
+    var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
+    return util.toObject([
+        "options"    , inherited && inherited.options || undefined,
+        "oneofs"     , Namespace.arrayToJSON(this.oneofsArray, toJSONOptions),
+        "fields"     , Namespace.arrayToJSON(this.fieldsArray.filter(function(obj) { return !obj.declaringField; }), toJSONOptions) || {},
+        "extensions" , this.extensions && this.extensions.length ? this.extensions : undefined,
+        "reserved"   , this.reserved && this.reserved.length ? this.reserved : undefined,
+        "group"      , this.group || undefined,
+        "nested"     , inherited && inherited.nested || undefined,
+        "comment"    , keepComments ? this.comment : undefined
+    ]);
+};
+
+/**
+ * @override
+ */
+Type.prototype.resolveAll = function resolveAll() {
+    var fields = this.fieldsArray, i = 0;
+    while (i < fields.length)
+        fields[i++].resolve();
+    var oneofs = this.oneofsArray; i = 0;
+    while (i < oneofs.length)
+        oneofs[i++].resolve();
+    return Namespace.prototype.resolveAll.call(this);
+};
+
+/**
+ * @override
+ */
+Type.prototype.get = function get(name) {
+    return this.fields[name]
+        || this.oneofs && this.oneofs[name]
+        || this.nested && this.nested[name]
+        || null;
+};
+
+/**
+ * Adds a nested object to this type.
+ * @param {ReflectionObject} object Nested object to add
+ * @returns {Type} `this`
+ * @throws {TypeError} If arguments are invalid
+ * @throws {Error} If there is already a nested object with this name or, if a field, when there is already a field with this id
+ */
+Type.prototype.add = function add(object) {
+
+    if (this.get(object.name))
+        throw Error("duplicate name '" + object.name + "' in " + this);
+
+    if (object instanceof Field && object.extend === undefined) {
+        // NOTE: Extension fields aren't actual fields on the declaring type, but nested objects.
+        // The root object takes care of adding distinct sister-fields to the respective extended
+        // type instead.
+
+        // avoids calling the getter if not absolutely necessary because it's called quite frequently
+        if (this._fieldsById ? /* istanbul ignore next */ this._fieldsById[object.id] : this.fieldsById[object.id])
+            throw Error("duplicate id " + object.id + " in " + this);
+        if (this.isReservedId(object.id))
+            throw Error("id " + object.id + " is reserved in " + this);
+        if (this.isReservedName(object.name))
+            throw Error("name '" + object.name + "' is reserved in " + this);
+
+        if (object.parent)
+            object.parent.remove(object);
+        this.fields[object.name] = object;
+        object.message = this;
+        object.onAdd(this);
+        return clearCache(this);
+    }
+    if (object instanceof OneOf) {
+        if (!this.oneofs)
+            this.oneofs = {};
+        this.oneofs[object.name] = object;
+        object.onAdd(this);
+        return clearCache(this);
+    }
+    return Namespace.prototype.add.call(this, object);
+};
+
+/**
+ * Removes a nested object from this type.
+ * @param {ReflectionObject} object Nested object to remove
+ * @returns {Type} `this`
+ * @throws {TypeError} If arguments are invalid
+ * @throws {Error} If `object` is not a member of this type
+ */
+Type.prototype.remove = function remove(object) {
+    if (object instanceof Field && object.extend === undefined) {
+        // See Type#add for the reason why extension fields are excluded here.
+
+        /* istanbul ignore if */
+        if (!this.fields || this.fields[object.name] !== object)
+            throw Error(object + " is not a member of " + this);
+
+        delete this.fields[object.name];
+        object.parent = null;
+        object.onRemove(this);
+        return clearCache(this);
+    }
+    if (object instanceof OneOf) {
+
+        /* istanbul ignore if */
+        if (!this.oneofs || this.oneofs[object.name] !== object)
+            throw Error(object + " is not a member of " + this);
+
+        delete this.oneofs[object.name];
+        object.parent = null;
+        object.onRemove(this);
+        return clearCache(this);
+    }
+    return Namespace.prototype.remove.call(this, object);
+};
+
+/**
+ * Tests if the specified id is reserved.
+ * @param {number} id Id to test
+ * @returns {boolean} `true` if reserved, otherwise `false`
+ */
+Type.prototype.isReservedId = function isReservedId(id) {
+    return Namespace.isReservedId(this.reserved, id);
+};
+
+/**
+ * Tests if the specified name is reserved.
+ * @param {string} name Name to test
+ * @returns {boolean} `true` if reserved, otherwise `false`
+ */
+Type.prototype.isReservedName = function isReservedName(name) {
+    return Namespace.isReservedName(this.reserved, name);
+};
+
+/**
+ * Creates a new message of this type using the specified properties.
+ * @param {Object.<string,*>} [properties] Properties to set
+ * @returns {Message<{}>} Message instance
+ */
+Type.prototype.create = function create(properties) {
+    return new this.ctor(properties);
+};
+
+/**
+ * Sets up {@link Type#encode|encode}, {@link Type#decode|decode} and {@link Type#verify|verify}.
+ * @returns {Type} `this`
+ */
+Type.prototype.setup = function setup() {
+    // Sets up everything at once so that the prototype chain does not have to be re-evaluated
+    // multiple times (V8, soft-deopt prototype-check).
+
+    var fullName = this.fullName,
+        types    = [];
+    for (var i = 0; i < /* initializes */ this.fieldsArray.length; ++i)
+        types.push(this._fieldsArray[i].resolve().resolvedType);
+
+    // Replace setup methods with type-specific generated functions
+    this.encode = encoder(this)({
+        Writer : Writer,
+        types  : types,
+        util   : util
+    });
+    this.decode = decoder(this)({
+        Reader : Reader,
+        types  : types,
+        util   : util
+    });
+    this.verify = verifier(this)({
+        types : types,
+        util  : util
+    });
+    this.fromObject = converter.fromObject(this)({
+        types : types,
+        util  : util
+    });
+    this.toObject = converter.toObject(this)({
+        types : types,
+        util  : util
+    });
+
+    // Inject custom wrappers for common types
+    var wrapper = wrappers[fullName];
+    if (wrapper) {
+        var originalThis = Object.create(this);
+        // if (wrapper.fromObject) {
+            originalThis.fromObject = this.fromObject;
+            this.fromObject = wrapper.fromObject.bind(originalThis);
+        // }
+        // if (wrapper.toObject) {
+            originalThis.toObject = this.toObject;
+            this.toObject = wrapper.toObject.bind(originalThis);
+        // }
+    }
+
+    return this;
+};
+
+/**
+ * Encodes a message of this type. Does not implicitly {@link Type#verify|verify} messages.
+ * @param {Message<{}>|Object.<string,*>} message Message instance or plain object
+ * @param {Writer} [writer] Writer to encode to
+ * @returns {Writer} writer
+ */
+Type.prototype.encode = function encode_setup(message, writer) {
+    return this.setup().encode(message, writer); // overrides this method
+};
+
+/**
+ * Encodes a message of this type preceeded by its byte length as a varint. Does not implicitly {@link Type#verify|verify} messages.
+ * @param {Message<{}>|Object.<string,*>} message Message instance or plain object
+ * @param {Writer} [writer] Writer to encode to
+ * @returns {Writer} writer
+ */
+Type.prototype.encodeDelimited = function encodeDelimited(message, writer) {
+    return this.encode(message, writer && writer.len ? writer.fork() : writer).ldelim();
+};
+
+/**
+ * Decodes a message of this type.
+ * @param {Reader|Uint8Array} reader Reader or buffer to decode from
+ * @param {number} [length] Length of the message, if known beforehand
+ * @returns {Message<{}>} Decoded message
+ * @throws {Error} If the payload is not a reader or valid buffer
+ * @throws {util.ProtocolError<{}>} If required fields are missing
+ */
+Type.prototype.decode = function decode_setup(reader, length) {
+    return this.setup().decode(reader, length); // overrides this method
+};
+
+/**
+ * Decodes a message of this type preceeded by its byte length as a varint.
+ * @param {Reader|Uint8Array} reader Reader or buffer to decode from
+ * @returns {Message<{}>} Decoded message
+ * @throws {Error} If the payload is not a reader or valid buffer
+ * @throws {util.ProtocolError} If required fields are missing
+ */
+Type.prototype.decodeDelimited = function decodeDelimited(reader) {
+    if (!(reader instanceof Reader))
+        reader = Reader.create(reader);
+    return this.decode(reader, reader.uint32());
+};
+
+/**
+ * Verifies that field values are valid and that required fields are present.
+ * @param {Object.<string,*>} message Plain object to verify
+ * @returns {null|string} `null` if valid, otherwise the reason why it is not
+ */
+Type.prototype.verify = function verify_setup(message) {
+    return this.setup().verify(message); // overrides this method
+};
+
+/**
+ * Creates a new message of this type from a plain object. Also converts values to their respective internal types.
+ * @param {Object.<string,*>} object Plain object to convert
+ * @returns {Message<{}>} Message instance
+ */
+Type.prototype.fromObject = function fromObject(object) {
+    return this.setup().fromObject(object);
+};
+
+/**
+ * Conversion options as used by {@link Type#toObject} and {@link Message.toObject}.
+ * @interface IConversionOptions
+ * @property {Function} [longs] Long conversion type.
+ * Valid values are `String` and `Number` (the global types).
+ * Defaults to copy the present value, which is a possibly unsafe number without and a {@link Long} with a long library.
+ * @property {Function} [enums] Enum value conversion type.
+ * Only valid value is `String` (the global type).
+ * Defaults to copy the present value, which is the numeric id.
+ * @property {Function} [bytes] Bytes value conversion type.
+ * Valid values are `Array` and (a base64 encoded) `String` (the global types).
+ * Defaults to copy the present value, which usually is a Buffer under node and an Uint8Array in the browser.
+ * @property {boolean} [defaults=false] Also sets default values on the resulting object
+ * @property {boolean} [arrays=false] Sets empty arrays for missing repeated fields even if `defaults=false`
+ * @property {boolean} [objects=false] Sets empty objects for missing map fields even if `defaults=false`
+ * @property {boolean} [oneofs=false] Includes virtual oneof properties set to the present field's name, if any
+ * @property {boolean} [json=false] Performs additional JSON compatibility conversions, i.e. NaN and Infinity to strings
+ */
+
+/**
+ * Creates a plain object from a message of this type. Also converts values to other types if specified.
+ * @param {Message<{}>} message Message instance
+ * @param {IConversionOptions} [options] Conversion options
+ * @returns {Object.<string,*>} Plain object
+ */
+Type.prototype.toObject = function toObject(message, options) {
+    return this.setup().toObject(message, options);
+};
+
+/**
+ * Decorator function as returned by {@link Type.d} (TypeScript).
+ * @typedef TypeDecorator
+ * @type {function}
+ * @param {Constructor<T>} target Target constructor
+ * @returns {undefined}
+ * @template T extends Message<T>
+ */
+
+/**
+ * Type decorator (TypeScript).
+ * @param {string} [typeName] Type name, defaults to the constructor's name
+ * @returns {TypeDecorator<T>} Decorator function
+ * @template T extends Message<T>
+ */
+Type.d = function decorateType(typeName) {
+    return function typeDecorator(target) {
+        util.decorateType(target, typeName);
+    };
+};
diff --git a/src/types.js b/src/types.js
new file mode 100644
index 0000000..5fda19a
--- /dev/null
+++ b/src/types.js
@@ -0,0 +1,196 @@
+"use strict";
+
+/**
+ * Common type constants.
+ * @namespace
+ */
+var types = exports;
+
+var util = require("./util");
+
+var s = [
+    "double",   // 0
+    "float",    // 1
+    "int32",    // 2
+    "uint32",   // 3
+    "sint32",   // 4
+    "fixed32",  // 5
+    "sfixed32", // 6
+    "int64",    // 7
+    "uint64",   // 8
+    "sint64",   // 9
+    "fixed64",  // 10
+    "sfixed64", // 11
+    "bool",     // 12
+    "string",   // 13
+    "bytes"     // 14
+];
+
+function bake(values, offset) {
+    var i = 0, o = {};
+    offset |= 0;
+    while (i < values.length) o[s[i + offset]] = values[i++];
+    return o;
+}
+
+/**
+ * Basic type wire types.
+ * @type {Object.<string,number>}
+ * @const
+ * @property {number} double=1 Fixed64 wire type
+ * @property {number} float=5 Fixed32 wire type
+ * @property {number} int32=0 Varint wire type
+ * @property {number} uint32=0 Varint wire type
+ * @property {number} sint32=0 Varint wire type
+ * @property {number} fixed32=5 Fixed32 wire type
+ * @property {number} sfixed32=5 Fixed32 wire type
+ * @property {number} int64=0 Varint wire type
+ * @property {number} uint64=0 Varint wire type
+ * @property {number} sint64=0 Varint wire type
+ * @property {number} fixed64=1 Fixed64 wire type
+ * @property {number} sfixed64=1 Fixed64 wire type
+ * @property {number} bool=0 Varint wire type
+ * @property {number} string=2 Ldelim wire type
+ * @property {number} bytes=2 Ldelim wire type
+ */
+types.basic = bake([
+    /* double   */ 1,
+    /* float    */ 5,
+    /* int32    */ 0,
+    /* uint32   */ 0,
+    /* sint32   */ 0,
+    /* fixed32  */ 5,
+    /* sfixed32 */ 5,
+    /* int64    */ 0,
+    /* uint64   */ 0,
+    /* sint64   */ 0,
+    /* fixed64  */ 1,
+    /* sfixed64 */ 1,
+    /* bool     */ 0,
+    /* string   */ 2,
+    /* bytes    */ 2
+]);
+
+/**
+ * Basic type defaults.
+ * @type {Object.<string,*>}
+ * @const
+ * @property {number} double=0 Double default
+ * @property {number} float=0 Float default
+ * @property {number} int32=0 Int32 default
+ * @property {number} uint32=0 Uint32 default
+ * @property {number} sint32=0 Sint32 default
+ * @property {number} fixed32=0 Fixed32 default
+ * @property {number} sfixed32=0 Sfixed32 default
+ * @property {number} int64=0 Int64 default
+ * @property {number} uint64=0 Uint64 default
+ * @property {number} sint64=0 Sint32 default
+ * @property {number} fixed64=0 Fixed64 default
+ * @property {number} sfixed64=0 Sfixed64 default
+ * @property {boolean} bool=false Bool default
+ * @property {string} string="" String default
+ * @property {Array.<number>} bytes=Array(0) Bytes default
+ * @property {null} message=null Message default
+ */
+types.defaults = bake([
+    /* double   */ 0,
+    /* float    */ 0,
+    /* int32    */ 0,
+    /* uint32   */ 0,
+    /* sint32   */ 0,
+    /* fixed32  */ 0,
+    /* sfixed32 */ 0,
+    /* int64    */ 0,
+    /* uint64   */ 0,
+    /* sint64   */ 0,
+    /* fixed64  */ 0,
+    /* sfixed64 */ 0,
+    /* bool     */ false,
+    /* string   */ "",
+    /* bytes    */ util.emptyArray,
+    /* message  */ null
+]);
+
+/**
+ * Basic long type wire types.
+ * @type {Object.<string,number>}
+ * @const
+ * @property {number} int64=0 Varint wire type
+ * @property {number} uint64=0 Varint wire type
+ * @property {number} sint64=0 Varint wire type
+ * @property {number} fixed64=1 Fixed64 wire type
+ * @property {number} sfixed64=1 Fixed64 wire type
+ */
+types.long = bake([
+    /* int64    */ 0,
+    /* uint64   */ 0,
+    /* sint64   */ 0,
+    /* fixed64  */ 1,
+    /* sfixed64 */ 1
+], 7);
+
+/**
+ * Allowed types for map keys with their associated wire type.
+ * @type {Object.<string,number>}
+ * @const
+ * @property {number} int32=0 Varint wire type
+ * @property {number} uint32=0 Varint wire type
+ * @property {number} sint32=0 Varint wire type
+ * @property {number} fixed32=5 Fixed32 wire type
+ * @property {number} sfixed32=5 Fixed32 wire type
+ * @property {number} int64=0 Varint wire type
+ * @property {number} uint64=0 Varint wire type
+ * @property {number} sint64=0 Varint wire type
+ * @property {number} fixed64=1 Fixed64 wire type
+ * @property {number} sfixed64=1 Fixed64 wire type
+ * @property {number} bool=0 Varint wire type
+ * @property {number} string=2 Ldelim wire type
+ */
+types.mapKey = bake([
+    /* int32    */ 0,
+    /* uint32   */ 0,
+    /* sint32   */ 0,
+    /* fixed32  */ 5,
+    /* sfixed32 */ 5,
+    /* int64    */ 0,
+    /* uint64   */ 0,
+    /* sint64   */ 0,
+    /* fixed64  */ 1,
+    /* sfixed64 */ 1,
+    /* bool     */ 0,
+    /* string   */ 2
+], 2);
+
+/**
+ * Allowed types for packed repeated fields with their associated wire type.
+ * @type {Object.<string,number>}
+ * @const
+ * @property {number} double=1 Fixed64 wire type
+ * @property {number} float=5 Fixed32 wire type
+ * @property {number} int32=0 Varint wire type
+ * @property {number} uint32=0 Varint wire type
+ * @property {number} sint32=0 Varint wire type
+ * @property {number} fixed32=5 Fixed32 wire type
+ * @property {number} sfixed32=5 Fixed32 wire type
+ * @property {number} int64=0 Varint wire type
+ * @property {number} uint64=0 Varint wire type
+ * @property {number} sint64=0 Varint wire type
+ * @property {number} fixed64=1 Fixed64 wire type
+ * @property {number} sfixed64=1 Fixed64 wire type
+ * @property {number} bool=0 Varint wire type
+ */
+types.packed = bake([
+    /* double   */ 1,
+    /* float    */ 5,
+    /* int32    */ 0,
+    /* uint32   */ 0,
+    /* sint32   */ 0,
+    /* fixed32  */ 5,
+    /* sfixed32 */ 5,
+    /* int64    */ 0,
+    /* uint64   */ 0,
+    /* sint64   */ 0,
+    /* fixed64  */ 1,
+    /* sfixed64 */ 1,
+    /* bool     */ 0
+]);
diff --git a/src/typescript.jsdoc b/src/typescript.jsdoc
new file mode 100644
index 0000000..9a67101
--- /dev/null
+++ b/src/typescript.jsdoc
@@ -0,0 +1,15 @@
+/**
+ * Constructor type.
+ * @interface Constructor
+ * @extends Function
+ * @template T
+ * @tstype new(...params: any[]): T; prototype: T;
+ */
+
+/**
+ * Properties type.
+ * @typedef Properties
+ * @template T
+ * @type {Object.<string,*>}
+ * @tstype { [P in keyof T]?: T[P] }
+ */
diff --git a/src/util.js b/src/util.js
new file mode 100644
index 0000000..c39d33a
--- /dev/null
+++ b/src/util.js
@@ -0,0 +1,212 @@
+"use strict";
+
+/**
+ * Various utility functions.
+ * @namespace
+ */
+var util = module.exports = require("./util/minimal");
+
+var roots = require("./roots");
+
+var Type, // cyclic
+    Enum;
+
+util.codegen = require("@protobufjs/codegen");
+util.fetch   = require("@protobufjs/fetch");
+util.path    = require("@protobufjs/path");
+
+/**
+ * Node's fs module if available.
+ * @type {Object.<string,*>}
+ */
+util.fs = util.inquire("fs");
+
+/**
+ * Converts an object's values to an array.
+ * @param {Object.<string,*>} object Object to convert
+ * @returns {Array.<*>} Converted array
+ */
+util.toArray = function toArray(object) {
+    if (object) {
+        var keys  = Object.keys(object),
+            array = new Array(keys.length),
+            index = 0;
+        while (index < keys.length)
+            array[index] = object[keys[index++]];
+        return array;
+    }
+    return [];
+};
+
+/**
+ * Converts an array of keys immediately followed by their respective value to an object, omitting undefined values.
+ * @param {Array.<*>} array Array to convert
+ * @returns {Object.<string,*>} Converted object
+ */
+util.toObject = function toObject(array) {
+    var object = {},
+        index  = 0;
+    while (index < array.length) {
+        var key = array[index++],
+            val = array[index++];
+        if (val !== undefined)
+            object[key] = val;
+    }
+    return object;
+};
+
+var safePropBackslashRe = /\\/g,
+    safePropQuoteRe     = /"/g;
+
+/**
+ * Tests whether the specified name is a reserved word in JS.
+ * @param {string} name Name to test
+ * @returns {boolean} `true` if reserved, otherwise `false`
+ */
+util.isReserved = function isReserved(name) {
+    return /^(?:do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$/.test(name);
+};
+
+/**
+ * Returns a safe property accessor for the specified property name.
+ * @param {string} prop Property name
+ * @returns {string} Safe accessor
+ */
+util.safeProp = function safeProp(prop) {
+    if (!/^[$\w_]+$/.test(prop) || util.isReserved(prop))
+        return "[\"" + prop.replace(safePropBackslashRe, "\\\\").replace(safePropQuoteRe, "\\\"") + "\"]";
+    return "." + prop;
+};
+
+/**
+ * Converts the first character of a string to upper case.
+ * @param {string} str String to convert
+ * @returns {string} Converted string
+ */
+util.ucFirst = function ucFirst(str) {
+    return str.charAt(0).toUpperCase() + str.substring(1);
+};
+
+var camelCaseRe = /_([a-z])/g;
+
+/**
+ * Converts a string to camel case.
+ * @param {string} str String to convert
+ * @returns {string} Converted string
+ */
+util.camelCase = function camelCase(str) {
+    return str.substring(0, 1)
+         + str.substring(1)
+               .replace(camelCaseRe, function($0, $1) { return $1.toUpperCase(); });
+};
+
+/**
+ * Compares reflected fields by id.
+ * @param {Field} a First field
+ * @param {Field} b Second field
+ * @returns {number} Comparison value
+ */
+util.compareFieldsById = function compareFieldsById(a, b) {
+    return a.id - b.id;
+};
+
+/**
+ * Decorator helper for types (TypeScript).
+ * @param {Constructor<T>} ctor Constructor function
+ * @param {string} [typeName] Type name, defaults to the constructor's name
+ * @returns {Type} Reflected type
+ * @template T extends Message<T>
+ * @property {Root} root Decorators root
+ */
+util.decorateType = function decorateType(ctor, typeName) {
+
+    /* istanbul ignore if */
+    if (ctor.$type) {
+        if (typeName && ctor.$type.name !== typeName) {
+            util.decorateRoot.remove(ctor.$type);
+            ctor.$type.name = typeName;
+            util.decorateRoot.add(ctor.$type);
+        }
+        return ctor.$type;
+    }
+
+    /* istanbul ignore next */
+    if (!Type)
+        Type = require("./type");
+
+    var type = new Type(typeName || ctor.name);
+    util.decorateRoot.add(type);
+    type.ctor = ctor; // sets up .encode, .decode etc.
+    Object.defineProperty(ctor, "$type", { value: type, enumerable: false });
+    Object.defineProperty(ctor.prototype, "$type", { value: type, enumerable: false });
+    return type;
+};
+
+var decorateEnumIndex = 0;
+
+/**
+ * Decorator helper for enums (TypeScript).
+ * @param {Object} object Enum object
+ * @returns {Enum} Reflected enum
+ */
+util.decorateEnum = function decorateEnum(object) {
+
+    /* istanbul ignore if */
+    if (object.$type)
+        return object.$type;
+
+    /* istanbul ignore next */
+    if (!Enum)
+        Enum = require("./enum");
+
+    var enm = new Enum("Enum" + decorateEnumIndex++, object);
+    util.decorateRoot.add(enm);
+    Object.defineProperty(object, "$type", { value: enm, enumerable: false });
+    return enm;
+};
+
+
+/**
+ * Sets the value of a property by property path. If a value already exists, it is turned to an array
+ * @param {Object.<string,*>} dst Destination object
+ * @param {string} path dot '.' delimited path of the property to set
+ * @param {Object} value the value to set
+ * @returns {Object.<string,*>} Destination object
+ */
+util.setProperty = function setProperty(dst, path, value) {
+    function setProp(dst, path, value) {
+        var part = path.shift();
+        if (part === "__proto__") {
+          return dst;
+        }
+        if (path.length > 0) {
+            dst[part] = setProp(dst[part] || {}, path, value);
+        } else {
+            var prevValue = dst[part];
+            if (prevValue)
+                value = [].concat(prevValue).concat(value);
+            dst[part] = value;
+        }
+        return dst;
+    }
+
+    if (typeof dst !== "object")
+        throw TypeError("dst must be an object");
+    if (!path)
+        throw TypeError("path must be specified");
+
+    path = path.split(".");
+    return setProp(dst, path, value);
+};
+
+/**
+ * Decorator root (TypeScript).
+ * @name util.decorateRoot
+ * @type {Root}
+ * @readonly
+ */
+Object.defineProperty(util, "decorateRoot", {
+    get: function() {
+        return roots["decorated"] || (roots["decorated"] = new (require("./root"))());
+    }
+});
diff --git a/src/util/longbits.js b/src/util/longbits.js
new file mode 100644
index 0000000..11bfb1c
--- /dev/null
+++ b/src/util/longbits.js
@@ -0,0 +1,200 @@
+"use strict";
+module.exports = LongBits;
+
+var util = require("../util/minimal");
+
+/**
+ * Constructs new long bits.
+ * @classdesc Helper class for working with the low and high bits of a 64 bit value.
+ * @memberof util
+ * @constructor
+ * @param {number} lo Low 32 bits, unsigned
+ * @param {number} hi High 32 bits, unsigned
+ */
+function LongBits(lo, hi) {
+
+    // note that the casts below are theoretically unnecessary as of today, but older statically
+    // generated converter code might still call the ctor with signed 32bits. kept for compat.
+
+    /**
+     * Low bits.
+     * @type {number}
+     */
+    this.lo = lo >>> 0;
+
+    /**
+     * High bits.
+     * @type {number}
+     */
+    this.hi = hi >>> 0;
+}
+
+/**
+ * Zero bits.
+ * @memberof util.LongBits
+ * @type {util.LongBits}
+ */
+var zero = LongBits.zero = new LongBits(0, 0);
+
+zero.toNumber = function() { return 0; };
+zero.zzEncode = zero.zzDecode = function() { return this; };
+zero.length = function() { return 1; };
+
+/**
+ * Zero hash.
+ * @memberof util.LongBits
+ * @type {string}
+ */
+var zeroHash = LongBits.zeroHash = "\0\0\0\0\0\0\0\0";
+
+/**
+ * Constructs new long bits from the specified number.
+ * @param {number} value Value
+ * @returns {util.LongBits} Instance
+ */
+LongBits.fromNumber = function fromNumber(value) {
+    if (value === 0)
+        return zero;
+    var sign = value < 0;
+    if (sign)
+        value = -value;
+    var lo = value >>> 0,
+        hi = (value - lo) / 4294967296 >>> 0;
+    if (sign) {
+        hi = ~hi >>> 0;
+        lo = ~lo >>> 0;
+        if (++lo > 4294967295) {
+            lo = 0;
+            if (++hi > 4294967295)
+                hi = 0;
+        }
+    }
+    return new LongBits(lo, hi);
+};
+
+/**
+ * Constructs new long bits from a number, long or string.
+ * @param {Long|number|string} value Value
+ * @returns {util.LongBits} Instance
+ */
+LongBits.from = function from(value) {
+    if (typeof value === "number")
+        return LongBits.fromNumber(value);
+    if (util.isString(value)) {
+        /* istanbul ignore else */
+        if (util.Long)
+            value = util.Long.fromString(value);
+        else
+            return LongBits.fromNumber(parseInt(value, 10));
+    }
+    return value.low || value.high ? new LongBits(value.low >>> 0, value.high >>> 0) : zero;
+};
+
+/**
+ * Converts this long bits to a possibly unsafe JavaScript number.
+ * @param {boolean} [unsigned=false] Whether unsigned or not
+ * @returns {number} Possibly unsafe number
+ */
+LongBits.prototype.toNumber = function toNumber(unsigned) {
+    if (!unsigned && this.hi >>> 31) {
+        var lo = ~this.lo + 1 >>> 0,
+            hi = ~this.hi     >>> 0;
+        if (!lo)
+            hi = hi + 1 >>> 0;
+        return -(lo + hi * 4294967296);
+    }
+    return this.lo + this.hi * 4294967296;
+};
+
+/**
+ * Converts this long bits to a long.
+ * @param {boolean} [unsigned=false] Whether unsigned or not
+ * @returns {Long} Long
+ */
+LongBits.prototype.toLong = function toLong(unsigned) {
+    return util.Long
+        ? new util.Long(this.lo | 0, this.hi | 0, Boolean(unsigned))
+        /* istanbul ignore next */
+        : { low: this.lo | 0, high: this.hi | 0, unsigned: Boolean(unsigned) };
+};
+
+var charCodeAt = String.prototype.charCodeAt;
+
+/**
+ * Constructs new long bits from the specified 8 characters long hash.
+ * @param {string} hash Hash
+ * @returns {util.LongBits} Bits
+ */
+LongBits.fromHash = function fromHash(hash) {
+    if (hash === zeroHash)
+        return zero;
+    return new LongBits(
+        ( charCodeAt.call(hash, 0)
+        | charCodeAt.call(hash, 1) << 8
+        | charCodeAt.call(hash, 2) << 16
+        | charCodeAt.call(hash, 3) << 24) >>> 0
+    ,
+        ( charCodeAt.call(hash, 4)
+        | charCodeAt.call(hash, 5) << 8
+        | charCodeAt.call(hash, 6) << 16
+        | charCodeAt.call(hash, 7) << 24) >>> 0
+    );
+};
+
+/**
+ * Converts this long bits to a 8 characters long hash.
+ * @returns {string} Hash
+ */
+LongBits.prototype.toHash = function toHash() {
+    return String.fromCharCode(
+        this.lo        & 255,
+        this.lo >>> 8  & 255,
+        this.lo >>> 16 & 255,
+        this.lo >>> 24      ,
+        this.hi        & 255,
+        this.hi >>> 8  & 255,
+        this.hi >>> 16 & 255,
+        this.hi >>> 24
+    );
+};
+
+/**
+ * Zig-zag encodes this long bits.
+ * @returns {util.LongBits} `this`
+ */
+LongBits.prototype.zzEncode = function zzEncode() {
+    var mask =   this.hi >> 31;
+    this.hi  = ((this.hi << 1 | this.lo >>> 31) ^ mask) >>> 0;
+    this.lo  = ( this.lo << 1                   ^ mask) >>> 0;
+    return this;
+};
+
+/**
+ * Zig-zag decodes this long bits.
+ * @returns {util.LongBits} `this`
+ */
+LongBits.prototype.zzDecode = function zzDecode() {
+    var mask = -(this.lo & 1);
+    this.lo  = ((this.lo >>> 1 | this.hi << 31) ^ mask) >>> 0;
+    this.hi  = ( this.hi >>> 1                  ^ mask) >>> 0;
+    return this;
+};
+
+/**
+ * Calculates the length of this longbits when encoded as a varint.
+ * @returns {number} Length
+ */
+LongBits.prototype.length = function length() {
+    var part0 =  this.lo,
+        part1 = (this.lo >>> 28 | this.hi << 4) >>> 0,
+        part2 =  this.hi >>> 24;
+    return part2 === 0
+         ? part1 === 0
+           ? part0 < 16384
+             ? part0 < 128 ? 1 : 2
+             : part0 < 2097152 ? 3 : 4
+           : part1 < 16384
+             ? part1 < 128 ? 5 : 6
+             : part1 < 2097152 ? 7 : 8
+         : part2 < 128 ? 9 : 10;
+};
diff --git a/src/util/minimal.js b/src/util/minimal.js
new file mode 100644
index 0000000..62d6833
--- /dev/null
+++ b/src/util/minimal.js
@@ -0,0 +1,438 @@
+"use strict";
+var util = exports;
+
+// used to return a Promise where callback is omitted
+util.asPromise = require("@protobufjs/aspromise");
+
+// converts to / from base64 encoded strings
+util.base64 = require("@protobufjs/base64");
+
+// base class of rpc.Service
+util.EventEmitter = require("@protobufjs/eventemitter");
+
+// float handling accross browsers
+util.float = require("@protobufjs/float");
+
+// requires modules optionally and hides the call from bundlers
+util.inquire = require("@protobufjs/inquire");
+
+// converts to / from utf8 encoded strings
+util.utf8 = require("@protobufjs/utf8");
+
+// provides a node-like buffer pool in the browser
+util.pool = require("@protobufjs/pool");
+
+// utility to work with the low and high bits of a 64 bit value
+util.LongBits = require("./longbits");
+
+/**
+ * Whether running within node or not.
+ * @memberof util
+ * @type {boolean}
+ */
+util.isNode = Boolean(typeof global !== "undefined"
+                   && global
+                   && global.process
+                   && global.process.versions
+                   && global.process.versions.node);
+
+/**
+ * Global object reference.
+ * @memberof util
+ * @type {Object}
+ */
+util.global = util.isNode && global
+           || typeof window !== "undefined" && window
+           || typeof self   !== "undefined" && self
+           || this; // eslint-disable-line no-invalid-this
+
+/**
+ * An immuable empty array.
+ * @memberof util
+ * @type {Array.<*>}
+ * @const
+ */
+util.emptyArray = Object.freeze ? Object.freeze([]) : /* istanbul ignore next */ []; // used on prototypes
+
+/**
+ * An immutable empty object.
+ * @type {Object}
+ * @const
+ */
+util.emptyObject = Object.freeze ? Object.freeze({}) : /* istanbul ignore next */ {}; // used on prototypes
+
+/**
+ * Tests if the specified value is an integer.
+ * @function
+ * @param {*} value Value to test
+ * @returns {boolean} `true` if the value is an integer
+ */
+util.isInteger = Number.isInteger || /* istanbul ignore next */ function isInteger(value) {
+    return typeof value === "number" && isFinite(value) && Math.floor(value) === value;
+};
+
+/**
+ * Tests if the specified value is a string.
+ * @param {*} value Value to test
+ * @returns {boolean} `true` if the value is a string
+ */
+util.isString = function isString(value) {
+    return typeof value === "string" || value instanceof String;
+};
+
+/**
+ * Tests if the specified value is a non-null object.
+ * @param {*} value Value to test
+ * @returns {boolean} `true` if the value is a non-null object
+ */
+util.isObject = function isObject(value) {
+    return value && typeof value === "object";
+};
+
+/**
+ * Checks if a property on a message is considered to be present.
+ * This is an alias of {@link util.isSet}.
+ * @function
+ * @param {Object} obj Plain object or message instance
+ * @param {string} prop Property name
+ * @returns {boolean} `true` if considered to be present, otherwise `false`
+ */
+util.isset =
+
+/**
+ * Checks if a property on a message is considered to be present.
+ * @param {Object} obj Plain object or message instance
+ * @param {string} prop Property name
+ * @returns {boolean} `true` if considered to be present, otherwise `false`
+ */
+util.isSet = function isSet(obj, prop) {
+    var value = obj[prop];
+    if (value != null && obj.hasOwnProperty(prop)) // eslint-disable-line eqeqeq, no-prototype-builtins
+        return typeof value !== "object" || (Array.isArray(value) ? value.length : Object.keys(value).length) > 0;
+    return false;
+};
+
+/**
+ * Any compatible Buffer instance.
+ * This is a minimal stand-alone definition of a Buffer instance. The actual type is that exported by node's typings.
+ * @interface Buffer
+ * @extends Uint8Array
+ */
+
+/**
+ * Node's Buffer class if available.
+ * @type {Constructor<Buffer>}
+ */
+util.Buffer = (function() {
+    try {
+        var Buffer = util.inquire("buffer").Buffer;
+        // refuse to use non-node buffers if not explicitly assigned (perf reasons):
+        return Buffer.prototype.utf8Write ? Buffer : /* istanbul ignore next */ null;
+    } catch (e) {
+        /* istanbul ignore next */
+        return null;
+    }
+})();
+
+// Internal alias of or polyfull for Buffer.from.
+util._Buffer_from = null;
+
+// Internal alias of or polyfill for Buffer.allocUnsafe.
+util._Buffer_allocUnsafe = null;
+
+/**
+ * Creates a new buffer of whatever type supported by the environment.
+ * @param {number|number[]} [sizeOrArray=0] Buffer size or number array
+ * @returns {Uint8Array|Buffer} Buffer
+ */
+util.newBuffer = function newBuffer(sizeOrArray) {
+    /* istanbul ignore next */
+    return typeof sizeOrArray === "number"
+        ? util.Buffer
+            ? util._Buffer_allocUnsafe(sizeOrArray)
+            : new util.Array(sizeOrArray)
+        : util.Buffer
+            ? util._Buffer_from(sizeOrArray)
+            : typeof Uint8Array === "undefined"
+                ? sizeOrArray
+                : new Uint8Array(sizeOrArray);
+};
+
+/**
+ * Array implementation used in the browser. `Uint8Array` if supported, otherwise `Array`.
+ * @type {Constructor<Uint8Array>}
+ */
+util.Array = typeof Uint8Array !== "undefined" ? Uint8Array /* istanbul ignore next */ : Array;
+
+/**
+ * Any compatible Long instance.
+ * This is a minimal stand-alone definition of a Long instance. The actual type is that exported by long.js.
+ * @interface Long
+ * @property {number} low Low bits
+ * @property {number} high High bits
+ * @property {boolean} unsigned Whether unsigned or not
+ */
+
+/**
+ * Long.js's Long class if available.
+ * @type {Constructor<Long>}
+ */
+util.Long = /* istanbul ignore next */ util.global.dcodeIO && /* istanbul ignore next */ util.global.dcodeIO.Long
+         || /* istanbul ignore next */ util.global.Long
+         || util.inquire("long");
+
+/**
+ * Regular expression used to verify 2 bit (`bool`) map keys.
+ * @type {RegExp}
+ * @const
+ */
+util.key2Re = /^true|false|0|1$/;
+
+/**
+ * Regular expression used to verify 32 bit (`int32` etc.) map keys.
+ * @type {RegExp}
+ * @const
+ */
+util.key32Re = /^-?(?:0|[1-9][0-9]*)$/;
+
+/**
+ * Regular expression used to verify 64 bit (`int64` etc.) map keys.
+ * @type {RegExp}
+ * @const
+ */
+util.key64Re = /^(?:[\\x00-\\xff]{8}|-?(?:0|[1-9][0-9]*))$/;
+
+/**
+ * Converts a number or long to an 8 characters long hash string.
+ * @param {Long|number} value Value to convert
+ * @returns {string} Hash
+ */
+util.longToHash = function longToHash(value) {
+    return value
+        ? util.LongBits.from(value).toHash()
+        : util.LongBits.zeroHash;
+};
+
+/**
+ * Converts an 8 characters long hash string to a long or number.
+ * @param {string} hash Hash
+ * @param {boolean} [unsigned=false] Whether unsigned or not
+ * @returns {Long|number} Original value
+ */
+util.longFromHash = function longFromHash(hash, unsigned) {
+    var bits = util.LongBits.fromHash(hash);
+    if (util.Long)
+        return util.Long.fromBits(bits.lo, bits.hi, unsigned);
+    return bits.toNumber(Boolean(unsigned));
+};
+
+/**
+ * Merges the properties of the source object into the destination object.
+ * @memberof util
+ * @param {Object.<string,*>} dst Destination object
+ * @param {Object.<string,*>} src Source object
+ * @param {boolean} [ifNotSet=false] Merges only if the key is not already set
+ * @returns {Object.<string,*>} Destination object
+ */
+function merge(dst, src, ifNotSet) { // used by converters
+    for (var keys = Object.keys(src), i = 0; i < keys.length; ++i)
+        if (dst[keys[i]] === undefined || !ifNotSet)
+            dst[keys[i]] = src[keys[i]];
+    return dst;
+}
+
+util.merge = merge;
+
+/**
+ * Converts the first character of a string to lower case.
+ * @param {string} str String to convert
+ * @returns {string} Converted string
+ */
+util.lcFirst = function lcFirst(str) {
+    return str.charAt(0).toLowerCase() + str.substring(1);
+};
+
+/**
+ * Creates a custom error constructor.
+ * @memberof util
+ * @param {string} name Error name
+ * @returns {Constructor<Error>} Custom error constructor
+ */
+function newError(name) {
+
+    function CustomError(message, properties) {
+
+        if (!(this instanceof CustomError))
+            return new CustomError(message, properties);
+
+        // Error.call(this, message);
+        // ^ just returns a new error instance because the ctor can be called as a function
+
+        Object.defineProperty(this, "message", { get: function() { return message; } });
+
+        /* istanbul ignore next */
+        if (Error.captureStackTrace) // node
+            Error.captureStackTrace(this, CustomError);
+        else
+            Object.defineProperty(this, "stack", { value: new Error().stack || "" });
+
+        if (properties)
+            merge(this, properties);
+    }
+
+    CustomError.prototype = Object.create(Error.prototype, {
+        constructor: {
+            value: CustomError,
+            writable: true,
+            enumerable: false,
+            configurable: true,
+        },
+        name: {
+            get: function get() { return name; },
+            set: undefined,
+            enumerable: false,
+            // configurable: false would accurately preserve the behavior of
+            // the original, but I'm guessing that was not intentional.
+            // For an actual error subclass, this property would
+            // be configurable.
+            configurable: true,
+        },
+        toString: {
+            value: function value() { return this.name + ": " + this.message; },
+            writable: true,
+            enumerable: false,
+            configurable: true,
+        },
+    });
+
+    return CustomError;
+}
+
+util.newError = newError;
+
+/**
+ * Constructs a new protocol error.
+ * @classdesc Error subclass indicating a protocol specifc error.
+ * @memberof util
+ * @extends Error
+ * @template T extends Message<T>
+ * @constructor
+ * @param {string} message Error message
+ * @param {Object.<string,*>} [properties] Additional properties
+ * @example
+ * try {
+ *     MyMessage.decode(someBuffer); // throws if required fields are missing
+ * } catch (e) {
+ *     if (e instanceof ProtocolError && e.instance)
+ *         console.log("decoded so far: " + JSON.stringify(e.instance));
+ * }
+ */
+util.ProtocolError = newError("ProtocolError");
+
+/**
+ * So far decoded message instance.
+ * @name util.ProtocolError#instance
+ * @type {Message<T>}
+ */
+
+/**
+ * A OneOf getter as returned by {@link util.oneOfGetter}.
+ * @typedef OneOfGetter
+ * @type {function}
+ * @returns {string|undefined} Set field name, if any
+ */
+
+/**
+ * Builds a getter for a oneof's present field name.
+ * @param {string[]} fieldNames Field names
+ * @returns {OneOfGetter} Unbound getter
+ */
+util.oneOfGetter = function getOneOf(fieldNames) {
+    var fieldMap = {};
+    for (var i = 0; i < fieldNames.length; ++i)
+        fieldMap[fieldNames[i]] = 1;
+
+    /**
+     * @returns {string|undefined} Set field name, if any
+     * @this Object
+     * @ignore
+     */
+    return function() { // eslint-disable-line consistent-return
+        for (var keys = Object.keys(this), i = keys.length - 1; i > -1; --i)
+            if (fieldMap[keys[i]] === 1 && this[keys[i]] !== undefined && this[keys[i]] !== null)
+                return keys[i];
+    };
+};
+
+/**
+ * A OneOf setter as returned by {@link util.oneOfSetter}.
+ * @typedef OneOfSetter
+ * @type {function}
+ * @param {string|undefined} value Field name
+ * @returns {undefined}
+ */
+
+/**
+ * Builds a setter for a oneof's present field name.
+ * @param {string[]} fieldNames Field names
+ * @returns {OneOfSetter} Unbound setter
+ */
+util.oneOfSetter = function setOneOf(fieldNames) {
+
+    /**
+     * @param {string} name Field name
+     * @returns {undefined}
+     * @this Object
+     * @ignore
+     */
+    return function(name) {
+        for (var i = 0; i < fieldNames.length; ++i)
+            if (fieldNames[i] !== name)
+                delete this[fieldNames[i]];
+    };
+};
+
+/**
+ * Default conversion options used for {@link Message#toJSON} implementations.
+ *
+ * These options are close to proto3's JSON mapping with the exception that internal types like Any are handled just like messages. More precisely:
+ *
+ * - Longs become strings
+ * - Enums become string keys
+ * - Bytes become base64 encoded strings
+ * - (Sub-)Messages become plain objects
+ * - Maps become plain objects with all string keys
+ * - Repeated fields become arrays
+ * - NaN and Infinity for float and double fields become strings
+ *
+ * @type {IConversionOptions}
+ * @see https://developers.google.com/protocol-buffers/docs/proto3?hl=en#json
+ */
+util.toJSONOptions = {
+    longs: String,
+    enums: String,
+    bytes: String,
+    json: true
+};
+
+// Sets up buffer utility according to the environment (called in index-minimal)
+util._configure = function() {
+    var Buffer = util.Buffer;
+    /* istanbul ignore if */
+    if (!Buffer) {
+        util._Buffer_from = util._Buffer_allocUnsafe = null;
+        return;
+    }
+    // because node 4.x buffers are incompatible & immutable
+    // see: https://github.com/dcodeIO/protobuf.js/pull/665
+    util._Buffer_from = Buffer.from !== Uint8Array.from && Buffer.from ||
+        /* istanbul ignore next */
+        function Buffer_from(value, encoding) {
+            return new Buffer(value, encoding);
+        };
+    util._Buffer_allocUnsafe = Buffer.allocUnsafe ||
+        /* istanbul ignore next */
+        function Buffer_allocUnsafe(size) {
+            return new Buffer(size);
+        };
+};
diff --git a/src/verifier.js b/src/verifier.js
new file mode 100644
index 0000000..d58e27a
--- /dev/null
+++ b/src/verifier.js
@@ -0,0 +1,177 @@
+"use strict";
+module.exports = verifier;
+
+var Enum      = require("./enum"),
+    util      = require("./util");
+
+function invalid(field, expected) {
+    return field.name + ": " + expected + (field.repeated && expected !== "array" ? "[]" : field.map && expected !== "object" ? "{k:"+field.keyType+"}" : "") + " expected";
+}
+
+/**
+ * Generates a partial value verifier.
+ * @param {Codegen} gen Codegen instance
+ * @param {Field} field Reflected field
+ * @param {number} fieldIndex Field index
+ * @param {string} ref Variable reference
+ * @returns {Codegen} Codegen instance
+ * @ignore
+ */
+function genVerifyValue(gen, field, fieldIndex, ref) {
+    /* eslint-disable no-unexpected-multiline */
+    if (field.resolvedType) {
+        if (field.resolvedType instanceof Enum) { gen
+            ("switch(%s){", ref)
+                ("default:")
+                    ("return%j", invalid(field, "enum value"));
+            for (var keys = Object.keys(field.resolvedType.values), j = 0; j < keys.length; ++j) gen
+                ("case %i:", field.resolvedType.values[keys[j]]);
+            gen
+                    ("break")
+            ("}");
+        } else {
+            gen
+            ("{")
+                ("var e=types[%i].verify(%s);", fieldIndex, ref)
+                ("if(e)")
+                    ("return%j+e", field.name + ".")
+            ("}");
+        }
+    } else {
+        switch (field.type) {
+            case "int32":
+            case "uint32":
+            case "sint32":
+            case "fixed32":
+            case "sfixed32": gen
+                ("if(!util.isInteger(%s))", ref)
+                    ("return%j", invalid(field, "integer"));
+                break;
+            case "int64":
+            case "uint64":
+            case "sint64":
+            case "fixed64":
+            case "sfixed64": gen
+                ("if(!util.isInteger(%s)&&!(%s&&util.isInteger(%s.low)&&util.isInteger(%s.high)))", ref, ref, ref, ref)
+                    ("return%j", invalid(field, "integer|Long"));
+                break;
+            case "float":
+            case "double": gen
+                ("if(typeof %s!==\"number\")", ref)
+                    ("return%j", invalid(field, "number"));
+                break;
+            case "bool": gen
+                ("if(typeof %s!==\"boolean\")", ref)
+                    ("return%j", invalid(field, "boolean"));
+                break;
+            case "string": gen
+                ("if(!util.isString(%s))", ref)
+                    ("return%j", invalid(field, "string"));
+                break;
+            case "bytes": gen
+                ("if(!(%s&&typeof %s.length===\"number\"||util.isString(%s)))", ref, ref, ref)
+                    ("return%j", invalid(field, "buffer"));
+                break;
+        }
+    }
+    return gen;
+    /* eslint-enable no-unexpected-multiline */
+}
+
+/**
+ * Generates a partial key verifier.
+ * @param {Codegen} gen Codegen instance
+ * @param {Field} field Reflected field
+ * @param {string} ref Variable reference
+ * @returns {Codegen} Codegen instance
+ * @ignore
+ */
+function genVerifyKey(gen, field, ref) {
+    /* eslint-disable no-unexpected-multiline */
+    switch (field.keyType) {
+        case "int32":
+        case "uint32":
+        case "sint32":
+        case "fixed32":
+        case "sfixed32": gen
+            ("if(!util.key32Re.test(%s))", ref)
+                ("return%j", invalid(field, "integer key"));
+            break;
+        case "int64":
+        case "uint64":
+        case "sint64":
+        case "fixed64":
+        case "sfixed64": gen
+            ("if(!util.key64Re.test(%s))", ref) // see comment above: x is ok, d is not
+                ("return%j", invalid(field, "integer|Long key"));
+            break;
+        case "bool": gen
+            ("if(!util.key2Re.test(%s))", ref)
+                ("return%j", invalid(field, "boolean key"));
+            break;
+    }
+    return gen;
+    /* eslint-enable no-unexpected-multiline */
+}
+
+/**
+ * Generates a verifier specific to the specified message type.
+ * @param {Type} mtype Message type
+ * @returns {Codegen} Codegen instance
+ */
+function verifier(mtype) {
+    /* eslint-disable no-unexpected-multiline */
+
+    var gen = util.codegen(["m"], mtype.name + "$verify")
+    ("if(typeof m!==\"object\"||m===null)")
+        ("return%j", "object expected");
+    var oneofs = mtype.oneofsArray,
+        seenFirstField = {};
+    if (oneofs.length) gen
+    ("var p={}");
+
+    for (var i = 0; i < /* initializes */ mtype.fieldsArray.length; ++i) {
+        var field = mtype._fieldsArray[i].resolve(),
+            ref   = "m" + util.safeProp(field.name);
+
+        if (field.optional) gen
+        ("if(%s!=null&&m.hasOwnProperty(%j)){", ref, field.name); // !== undefined && !== null
+
+        // map fields
+        if (field.map) { gen
+            ("if(!util.isObject(%s))", ref)
+                ("return%j", invalid(field, "object"))
+            ("var k=Object.keys(%s)", ref)
+            ("for(var i=0;i<k.length;++i){");
+                genVerifyKey(gen, field, "k[i]");
+                genVerifyValue(gen, field, i, ref + "[k[i]]")
+            ("}");
+
+        // repeated fields
+        } else if (field.repeated) { gen
+            ("if(!Array.isArray(%s))", ref)
+                ("return%j", invalid(field, "array"))
+            ("for(var i=0;i<%s.length;++i){", ref);
+                genVerifyValue(gen, field, i, ref + "[i]")
+            ("}");
+
+        // required or present fields
+        } else {
+            if (field.partOf) {
+                var oneofProp = util.safeProp(field.partOf.name);
+                if (seenFirstField[field.partOf.name] === 1) gen
+            ("if(p%s===1)", oneofProp)
+                ("return%j", field.partOf.name + ": multiple values");
+                seenFirstField[field.partOf.name] = 1;
+                gen
+            ("p%s=1", oneofProp);
+            }
+            genVerifyValue(gen, field, i, ref);
+        }
+        if (field.optional) gen
+        ("}");
+    }
+    return gen
+    ("return null");
+    /* eslint-enable no-unexpected-multiline */
+}
\ No newline at end of file
diff --git a/src/wrappers.js b/src/wrappers.js
new file mode 100644
index 0000000..131e21c
--- /dev/null
+++ b/src/wrappers.js
@@ -0,0 +1,102 @@
+"use strict";
+
+/**
+ * Wrappers for common types.
+ * @type {Object.<string,IWrapper>}
+ * @const
+ */
+var wrappers = exports;
+
+var Message = require("./message");
+
+/**
+ * From object converter part of an {@link IWrapper}.
+ * @typedef WrapperFromObjectConverter
+ * @type {function}
+ * @param {Object.<string,*>} object Plain object
+ * @returns {Message<{}>} Message instance
+ * @this Type
+ */
+
+/**
+ * To object converter part of an {@link IWrapper}.
+ * @typedef WrapperToObjectConverter
+ * @type {function}
+ * @param {Message<{}>} message Message instance
+ * @param {IConversionOptions} [options] Conversion options
+ * @returns {Object.<string,*>} Plain object
+ * @this Type
+ */
+
+/**
+ * Common type wrapper part of {@link wrappers}.
+ * @interface IWrapper
+ * @property {WrapperFromObjectConverter} [fromObject] From object converter
+ * @property {WrapperToObjectConverter} [toObject] To object converter
+ */
+
+// Custom wrapper for Any
+wrappers[".google.protobuf.Any"] = {
+
+    fromObject: function(object) {
+
+        // unwrap value type if mapped
+        if (object && object["@type"]) {
+             // Only use fully qualified type name after the last '/'
+            var name = object["@type"].substring(object["@type"].lastIndexOf("/") + 1);
+            var type = this.lookup(name);
+            /* istanbul ignore else */
+            if (type) {
+                // type_url does not accept leading "."
+                var type_url = object["@type"].charAt(0) === "." ?
+                    object["@type"].slice(1) : object["@type"];
+                // type_url prefix is optional, but path seperator is required
+                if (type_url.indexOf("/") === -1) {
+                    type_url = "/" + type_url;
+                }
+                return this.create({
+                    type_url: type_url,
+                    value: type.encode(type.fromObject(object)).finish()
+                });
+            }
+        }
+
+        return this.fromObject(object);
+    },
+
+    toObject: function(message, options) {
+
+        // Default prefix
+        var googleApi = "type.googleapis.com/";
+        var prefix = "";
+        var name = "";
+
+        // decode value if requested and unmapped
+        if (options && options.json && message.type_url && message.value) {
+            // Only use fully qualified type name after the last '/'
+            name = message.type_url.substring(message.type_url.lastIndexOf("/") + 1);
+            // Separate the prefix used
+            prefix = message.type_url.substring(0, message.type_url.lastIndexOf("/") + 1);
+            var type = this.lookup(name);
+            /* istanbul ignore else */
+            if (type)
+                message = type.decode(message.value);
+        }
+
+        // wrap value if unmapped
+        if (!(message instanceof this.ctor) && message instanceof Message) {
+            var object = message.$type.toObject(message, options);
+            var messageName = message.$type.fullName[0] === "." ?
+                message.$type.fullName.slice(1) : message.$type.fullName;
+            // Default to type.googleapis.com prefix if no prefix is used
+            if (prefix === "") {
+                prefix = googleApi;
+            }
+            name = prefix + messageName;
+            object["@type"] = name;
+            return object;
+        }
+
+        return this.toObject(message, options);
+    }
+};
diff --git a/src/writer.js b/src/writer.js
new file mode 100644
index 0000000..cc84a00
--- /dev/null
+++ b/src/writer.js
@@ -0,0 +1,465 @@
+"use strict";
+module.exports = Writer;
+
+var util      = require("./util/minimal");
+
+var BufferWriter; // cyclic
+
+var LongBits  = util.LongBits,
+    base64    = util.base64,
+    utf8      = util.utf8;
+
+/**
+ * Constructs a new writer operation instance.
+ * @classdesc Scheduled writer operation.
+ * @constructor
+ * @param {function(*, Uint8Array, number)} fn Function to call
+ * @param {number} len Value byte length
+ * @param {*} val Value to write
+ * @ignore
+ */
+function Op(fn, len, val) {
+
+    /**
+     * Function to call.
+     * @type {function(Uint8Array, number, *)}
+     */
+    this.fn = fn;
+
+    /**
+     * Value byte length.
+     * @type {number}
+     */
+    this.len = len;
+
+    /**
+     * Next operation.
+     * @type {Writer.Op|undefined}
+     */
+    this.next = undefined;
+
+    /**
+     * Value to write.
+     * @type {*}
+     */
+    this.val = val; // type varies
+}
+
+/* istanbul ignore next */
+function noop() {} // eslint-disable-line no-empty-function
+
+/**
+ * Constructs a new writer state instance.
+ * @classdesc Copied writer state.
+ * @memberof Writer
+ * @constructor
+ * @param {Writer} writer Writer to copy state from
+ * @ignore
+ */
+function State(writer) {
+
+    /**
+     * Current head.
+     * @type {Writer.Op}
+     */
+    this.head = writer.head;
+
+    /**
+     * Current tail.
+     * @type {Writer.Op}
+     */
+    this.tail = writer.tail;
+
+    /**
+     * Current buffer length.
+     * @type {number}
+     */
+    this.len = writer.len;
+
+    /**
+     * Next state.
+     * @type {State|null}
+     */
+    this.next = writer.states;
+}
+
+/**
+ * Constructs a new writer instance.
+ * @classdesc Wire format writer using `Uint8Array` if available, otherwise `Array`.
+ * @constructor
+ */
+function Writer() {
+
+    /**
+     * Current length.
+     * @type {number}
+     */
+    this.len = 0;
+
+    /**
+     * Operations head.
+     * @type {Object}
+     */
+    this.head = new Op(noop, 0, 0);
+
+    /**
+     * Operations tail
+     * @type {Object}
+     */
+    this.tail = this.head;
+
+    /**
+     * Linked forked states.
+     * @type {Object|null}
+     */
+    this.states = null;
+
+    // When a value is written, the writer calculates its byte length and puts it into a linked
+    // list of operations to perform when finish() is called. This both allows us to allocate
+    // buffers of the exact required size and reduces the amount of work we have to do compared
+    // to first calculating over objects and then encoding over objects. In our case, the encoding
+    // part is just a linked list walk calling operations with already prepared values.
+}
+
+var create = function create() {
+    return util.Buffer
+        ? function create_buffer_setup() {
+            return (Writer.create = function create_buffer() {
+                return new BufferWriter();
+            })();
+        }
+        /* istanbul ignore next */
+        : function create_array() {
+            return new Writer();
+        };
+};
+
+/**
+ * Creates a new writer.
+ * @function
+ * @returns {BufferWriter|Writer} A {@link BufferWriter} when Buffers are supported, otherwise a {@link Writer}
+ */
+Writer.create = create();
+
+/**
+ * Allocates a buffer of the specified size.
+ * @param {number} size Buffer size
+ * @returns {Uint8Array} Buffer
+ */
+Writer.alloc = function alloc(size) {
+    return new util.Array(size);
+};
+
+// Use Uint8Array buffer pool in the browser, just like node does with buffers
+/* istanbul ignore else */
+if (util.Array !== Array)
+    Writer.alloc = util.pool(Writer.alloc, util.Array.prototype.subarray);
+
+/**
+ * Pushes a new operation to the queue.
+ * @param {function(Uint8Array, number, *)} fn Function to call
+ * @param {number} len Value byte length
+ * @param {number} val Value to write
+ * @returns {Writer} `this`
+ * @private
+ */
+Writer.prototype._push = function push(fn, len, val) {
+    this.tail = this.tail.next = new Op(fn, len, val);
+    this.len += len;
+    return this;
+};
+
+function writeByte(val, buf, pos) {
+    buf[pos] = val & 255;
+}
+
+function writeVarint32(val, buf, pos) {
+    while (val > 127) {
+        buf[pos++] = val & 127 | 128;
+        val >>>= 7;
+    }
+    buf[pos] = val;
+}
+
+/**
+ * Constructs a new varint writer operation instance.
+ * @classdesc Scheduled varint writer operation.
+ * @extends Op
+ * @constructor
+ * @param {number} len Value byte length
+ * @param {number} val Value to write
+ * @ignore
+ */
+function VarintOp(len, val) {
+    this.len = len;
+    this.next = undefined;
+    this.val = val;
+}
+
+VarintOp.prototype = Object.create(Op.prototype);
+VarintOp.prototype.fn = writeVarint32;
+
+/**
+ * Writes an unsigned 32 bit value as a varint.
+ * @param {number} value Value to write
+ * @returns {Writer} `this`
+ */
+Writer.prototype.uint32 = function write_uint32(value) {
+    // here, the call to this.push has been inlined and a varint specific Op subclass is used.
+    // uint32 is by far the most frequently used operation and benefits significantly from this.
+    this.len += (this.tail = this.tail.next = new VarintOp(
+        (value = value >>> 0)
+                < 128       ? 1
+        : value < 16384     ? 2
+        : value < 2097152   ? 3
+        : value < 268435456 ? 4
+        :                     5,
+    value)).len;
+    return this;
+};
+
+/**
+ * Writes a signed 32 bit value as a varint.
+ * @function
+ * @param {number} value Value to write
+ * @returns {Writer} `this`
+ */
+Writer.prototype.int32 = function write_int32(value) {
+    return value < 0
+        ? this._push(writeVarint64, 10, LongBits.fromNumber(value)) // 10 bytes per spec
+        : this.uint32(value);
+};
+
+/**
+ * Writes a 32 bit value as a varint, zig-zag encoded.
+ * @param {number} value Value to write
+ * @returns {Writer} `this`
+ */
+Writer.prototype.sint32 = function write_sint32(value) {
+    return this.uint32((value << 1 ^ value >> 31) >>> 0);
+};
+
+function writeVarint64(val, buf, pos) {
+    while (val.hi) {
+        buf[pos++] = val.lo & 127 | 128;
+        val.lo = (val.lo >>> 7 | val.hi << 25) >>> 0;
+        val.hi >>>= 7;
+    }
+    while (val.lo > 127) {
+        buf[pos++] = val.lo & 127 | 128;
+        val.lo = val.lo >>> 7;
+    }
+    buf[pos++] = val.lo;
+}
+
+/**
+ * Writes an unsigned 64 bit value as a varint.
+ * @param {Long|number|string} value Value to write
+ * @returns {Writer} `this`
+ * @throws {TypeError} If `value` is a string and no long library is present.
+ */
+Writer.prototype.uint64 = function write_uint64(value) {
+    var bits = LongBits.from(value);
+    return this._push(writeVarint64, bits.length(), bits);
+};
+
+/**
+ * Writes a signed 64 bit value as a varint.
+ * @function
+ * @param {Long|number|string} value Value to write
+ * @returns {Writer} `this`
+ * @throws {TypeError} If `value` is a string and no long library is present.
+ */
+Writer.prototype.int64 = Writer.prototype.uint64;
+
+/**
+ * Writes a signed 64 bit value as a varint, zig-zag encoded.
+ * @param {Long|number|string} value Value to write
+ * @returns {Writer} `this`
+ * @throws {TypeError} If `value` is a string and no long library is present.
+ */
+Writer.prototype.sint64 = function write_sint64(value) {
+    var bits = LongBits.from(value).zzEncode();
+    return this._push(writeVarint64, bits.length(), bits);
+};
+
+/**
+ * Writes a boolish value as a varint.
+ * @param {boolean} value Value to write
+ * @returns {Writer} `this`
+ */
+Writer.prototype.bool = function write_bool(value) {
+    return this._push(writeByte, 1, value ? 1 : 0);
+};
+
+function writeFixed32(val, buf, pos) {
+    buf[pos    ] =  val         & 255;
+    buf[pos + 1] =  val >>> 8   & 255;
+    buf[pos + 2] =  val >>> 16  & 255;
+    buf[pos + 3] =  val >>> 24;
+}
+
+/**
+ * Writes an unsigned 32 bit value as fixed 32 bits.
+ * @param {number} value Value to write
+ * @returns {Writer} `this`
+ */
+Writer.prototype.fixed32 = function write_fixed32(value) {
+    return this._push(writeFixed32, 4, value >>> 0);
+};
+
+/**
+ * Writes a signed 32 bit value as fixed 32 bits.
+ * @function
+ * @param {number} value Value to write
+ * @returns {Writer} `this`
+ */
+Writer.prototype.sfixed32 = Writer.prototype.fixed32;
+
+/**
+ * Writes an unsigned 64 bit value as fixed 64 bits.
+ * @param {Long|number|string} value Value to write
+ * @returns {Writer} `this`
+ * @throws {TypeError} If `value` is a string and no long library is present.
+ */
+Writer.prototype.fixed64 = function write_fixed64(value) {
+    var bits = LongBits.from(value);
+    return this._push(writeFixed32, 4, bits.lo)._push(writeFixed32, 4, bits.hi);
+};
+
+/**
+ * Writes a signed 64 bit value as fixed 64 bits.
+ * @function
+ * @param {Long|number|string} value Value to write
+ * @returns {Writer} `this`
+ * @throws {TypeError} If `value` is a string and no long library is present.
+ */
+Writer.prototype.sfixed64 = Writer.prototype.fixed64;
+
+/**
+ * Writes a float (32 bit).
+ * @function
+ * @param {number} value Value to write
+ * @returns {Writer} `this`
+ */
+Writer.prototype.float = function write_float(value) {
+    return this._push(util.float.writeFloatLE, 4, value);
+};
+
+/**
+ * Writes a double (64 bit float).
+ * @function
+ * @param {number} value Value to write
+ * @returns {Writer} `this`
+ */
+Writer.prototype.double = function write_double(value) {
+    return this._push(util.float.writeDoubleLE, 8, value);
+};
+
+var writeBytes = util.Array.prototype.set
+    ? function writeBytes_set(val, buf, pos) {
+        buf.set(val, pos); // also works for plain array values
+    }
+    /* istanbul ignore next */
+    : function writeBytes_for(val, buf, pos) {
+        for (var i = 0; i < val.length; ++i)
+            buf[pos + i] = val[i];
+    };
+
+/**
+ * Writes a sequence of bytes.
+ * @param {Uint8Array|string} value Buffer or base64 encoded string to write
+ * @returns {Writer} `this`
+ */
+Writer.prototype.bytes = function write_bytes(value) {
+    var len = value.length >>> 0;
+    if (!len)
+        return this._push(writeByte, 1, 0);
+    if (util.isString(value)) {
+        var buf = Writer.alloc(len = base64.length(value));
+        base64.decode(value, buf, 0);
+        value = buf;
+    }
+    return this.uint32(len)._push(writeBytes, len, value);
+};
+
+/**
+ * Writes a string.
+ * @param {string} value Value to write
+ * @returns {Writer} `this`
+ */
+Writer.prototype.string = function write_string(value) {
+    var len = utf8.length(value);
+    return len
+        ? this.uint32(len)._push(utf8.write, len, value)
+        : this._push(writeByte, 1, 0);
+};
+
+/**
+ * Forks this writer's state by pushing it to a stack.
+ * Calling {@link Writer#reset|reset} or {@link Writer#ldelim|ldelim} resets the writer to the previous state.
+ * @returns {Writer} `this`
+ */
+Writer.prototype.fork = function fork() {
+    this.states = new State(this);
+    this.head = this.tail = new Op(noop, 0, 0);
+    this.len = 0;
+    return this;
+};
+
+/**
+ * Resets this instance to the last state.
+ * @returns {Writer} `this`
+ */
+Writer.prototype.reset = function reset() {
+    if (this.states) {
+        this.head   = this.states.head;
+        this.tail   = this.states.tail;
+        this.len    = this.states.len;
+        this.states = this.states.next;
+    } else {
+        this.head = this.tail = new Op(noop, 0, 0);
+        this.len  = 0;
+    }
+    return this;
+};
+
+/**
+ * Resets to the last state and appends the fork state's current write length as a varint followed by its operations.
+ * @returns {Writer} `this`
+ */
+Writer.prototype.ldelim = function ldelim() {
+    var head = this.head,
+        tail = this.tail,
+        len  = this.len;
+    this.reset().uint32(len);
+    if (len) {
+        this.tail.next = head.next; // skip noop
+        this.tail = tail;
+        this.len += len;
+    }
+    return this;
+};
+
+/**
+ * Finishes the write operation.
+ * @returns {Uint8Array} Finished buffer
+ */
+Writer.prototype.finish = function finish() {
+    var head = this.head.next, // skip noop
+        buf  = this.constructor.alloc(this.len),
+        pos  = 0;
+    while (head) {
+        head.fn(head.val, buf, pos);
+        pos += head.len;
+        head = head.next;
+    }
+    // this.head = this.tail = null;
+    return buf;
+};
+
+Writer._configure = function(BufferWriter_) {
+    BufferWriter = BufferWriter_;
+    Writer.create = create();
+    BufferWriter._configure();
+};
diff --git a/src/writer_buffer.js b/src/writer_buffer.js
new file mode 100644
index 0000000..09a4a91
--- /dev/null
+++ b/src/writer_buffer.js
@@ -0,0 +1,85 @@
+"use strict";
+module.exports = BufferWriter;
+
+// extends Writer
+var Writer = require("./writer");
+(BufferWriter.prototype = Object.create(Writer.prototype)).constructor = BufferWriter;
+
+var util = require("./util/minimal");
+
+/**
+ * Constructs a new buffer writer instance.
+ * @classdesc Wire format writer using node buffers.
+ * @extends Writer
+ * @constructor
+ */
+function BufferWriter() {
+    Writer.call(this);
+}
+
+BufferWriter._configure = function () {
+    /**
+     * Allocates a buffer of the specified size.
+     * @function
+     * @param {number} size Buffer size
+     * @returns {Buffer} Buffer
+     */
+    BufferWriter.alloc = util._Buffer_allocUnsafe;
+
+    BufferWriter.writeBytesBuffer = util.Buffer && util.Buffer.prototype instanceof Uint8Array && util.Buffer.prototype.set.name === "set"
+        ? function writeBytesBuffer_set(val, buf, pos) {
+          buf.set(val, pos); // faster than copy (requires node >= 4 where Buffers extend Uint8Array and set is properly inherited)
+          // also works for plain array values
+        }
+        /* istanbul ignore next */
+        : function writeBytesBuffer_copy(val, buf, pos) {
+          if (val.copy) // Buffer values
+            val.copy(buf, pos, 0, val.length);
+          else for (var i = 0; i < val.length;) // plain array values
+            buf[pos++] = val[i++];
+        };
+};
+
+
+/**
+ * @override
+ */
+BufferWriter.prototype.bytes = function write_bytes_buffer(value) {
+    if (util.isString(value))
+        value = util._Buffer_from(value, "base64");
+    var len = value.length >>> 0;
+    this.uint32(len);
+    if (len)
+        this._push(BufferWriter.writeBytesBuffer, len, value);
+    return this;
+};
+
+function writeStringBuffer(val, buf, pos) {
+    if (val.length < 40) // plain js is faster for short strings (probably due to redundant assertions)
+        util.utf8.write(val, buf, pos);
+    else if (buf.utf8Write)
+        buf.utf8Write(val, pos);
+    else
+        buf.write(val, pos);
+}
+
+/**
+ * @override
+ */
+BufferWriter.prototype.string = function write_string_buffer(value) {
+    var len = util.Buffer.byteLength(value);
+    this.uint32(len);
+    if (len)
+        this._push(writeStringBuffer, len, value);
+    return this;
+};
+
+
+/**
+ * Finishes the write operation.
+ * @name BufferWriter#finish
+ * @function
+ * @returns {Buffer} Finished buffer
+ */
+
+BufferWriter._configure();
diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 0000000..b9e2eff
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,18 @@
+This folder contains all the tests, one per file.
+
+It is essential that tests only use the cross-platform API that is also available in browsers:
+
+* Use `load`, not `loadSync`
+* Use `Reader.create`, not `BufferReader`
+* Use `Writer.create`, not `BufferWriter`
+* It is safe to use `Long`, but TypeScript tests must import the type from `"long"`
+
+If it's absolutely inevitable for your test case to use node-specific features, you can still use this pattern:
+
+```js
+if (protobuf.util.isNode) {
+    // node-specific tests
+}
+```
+
+**Why?** Tests are run both under node.js and within all kinds of modern to ancient browsers automatically.
diff --git a/tests/api_Class.js b/tests/api_Class.js
new file mode 100644
index 0000000..9b91eee
--- /dev/null
+++ b/tests/api_Class.js
@@ -0,0 +1,21 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var proto = "message Something {}";
+
+tape.test("reflected classes", function(test) {
+
+    var root = protobuf.parse(proto).root,
+        Something = root.lookup("Something");
+
+    test.throws(function() {
+        protobuf.Class("a");
+    }, TypeError, "Class should throw if first argument is not a Type");
+
+    test.throws(function() {
+        protobuf.Class(Something, "a");
+    }, TypeError, "Class should throw if second argument is not a function");
+
+    test.end();
+});
\ No newline at end of file
diff --git a/tests/api_common.js b/tests/api_common.js
new file mode 100644
index 0000000..fba6813
--- /dev/null
+++ b/tests/api_common.js
@@ -0,0 +1,27 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("common types", function(test) {
+
+    protobuf.common("google/protobuf/foo.proto", {
+        nested: {
+            google: {
+                nested: {
+                    protobuf: {
+                        nested: {
+                            Foo: {
+                                fields: {}
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    });
+
+    test.ok(protobuf.common["google/protobuf/foo.proto"], "should expose custom definitions");
+    test.same(protobuf.common.get("google/protobuf/any.proto"), protobuf.common["google/protobuf/any.proto"], "should also get() any definition");
+    test.equal(protobuf.common.get("google/protobuf/doesntexist.proto"), null, "should return null from get() if there is no such definition");
+    test.end();
+});
\ No newline at end of file
diff --git a/tests/api_converters.js b/tests/api_converters.js
new file mode 100644
index 0000000..0ad9010
--- /dev/null
+++ b/tests/api_converters.js
@@ -0,0 +1,200 @@
+var tape = require("tape");
+
+var protobuf  = require("..");
+
+tape.test("converters", function(test) {
+
+    protobuf.load("tests/data/convert.proto", function(err, root) {
+        if (err)
+            return test.fail(err.message);
+
+        var Message = root.lookup("Message");
+
+        test.test(test.name + " - Message#toObject", function(test) {
+
+            test.plan(6);
+
+            test.test(test.name + " - called with defaults = true", function(test) {
+                var obj = Message.toObject(Message.create(), { defaults: true });
+
+                test.equal(obj.stringVal, "", "should set stringVal");
+                test.same(obj.stringRepeated, [], "should set stringRepeated");
+
+                test.same(obj.uint64Val, { low: 0, high: 0, unsigned: true }, "should set uint64Val");
+                test.same(obj.uint64Repeated, [], "should set uint64Repeated");
+
+                test.same(obj.bytesVal, protobuf.util.newBuffer(0), "should set bytesVal");
+                test.same(obj.bytesRepeated, [], "should set bytesRepeated");
+
+                test.equal(obj.enumVal, 1, "should set enumVal to the first defined value");
+                test.same(obj.enumRepeated, [], "should set enumRepeated");
+
+                test.same(obj.int64Map, {}, "should set int64Map");
+
+                test.end();
+            });
+
+            test.test(test.name + " - called with defaults = undefined", function(test) {
+                var obj = Message.toObject(Message.create());
+
+                test.equal(obj.stringVal, undefined, "should not set stringVal");
+                test.equal(obj.stringRepeated, undefined, "should not set stringRepeated");
+
+                test.equal(obj.uint64Val, undefined, "should not set uint64Val");
+                test.equal(obj.uint64Repeated, undefined, "should not set uint64Repeated");
+
+                test.equal(obj.bytesVal, undefined, "should not set bytesVal");
+                test.equal(obj.bytesRepeated, undefined, "should not set bytesRepeated");
+
+                test.equal(obj.enumVal, undefined, "should not set enumVal");
+                test.equal(obj.enumRepeated, undefined, "should not set enumRepeated");
+
+                test.equal(obj.int64Map, undefined, "should not set int64 map");
+
+                test.end();
+            });
+
+            test.test(test.name + " - called with arrays = true", function(test) {
+                var obj = Message.toObject(Message.create(), { arrays: true });
+
+                test.equal(obj.stringVal, undefined, "should not set stringVal");
+                test.same(obj.stringRepeated, [], "should set stringRepeated");
+
+                test.equal(obj.uint64Val, undefined, "should not set uint64Val");
+                test.same(obj.uint64Repeated, [], "should set uint64Repeated");
+
+                test.equal(obj.bytesVal, undefined, "should not set bytesVal");
+                test.same(obj.bytesRepeated, [], "should set bytesRepeated");
+
+                test.equal(obj.enumVal, undefined, "should not set enumVal");
+                test.same(obj.enumRepeated, [], "should set enumRepeated");
+
+                test.equal(obj.int64Map, undefined, "should not set int64Map");
+
+                test.end();
+            });
+
+            test.test(test.name + " - called with objects = true", function(test) {
+                var obj = Message.toObject(Message.create(), { objects: true });
+
+                test.equal(obj.stringVal, undefined, "should not set stringVal");
+                test.equal(obj.stringRepeated, undefined, "should not set stringRepeated");
+
+                test.equal(obj.uint64Val, undefined, "should not set uint64Val");
+                test.same(obj.uint64Repeated, undefined, "should not set uint64Repeated");
+
+                test.equal(obj.bytesVal, undefined, "should not set bytesVal");
+                test.same(obj.bytesRepeated, undefined, "should not set bytesRepeated");
+
+                test.equal(obj.enumVal, undefined, "should not set enumVal");
+                test.same(obj.enumRepeated, undefined, "should not set enumRepeated");
+
+                test.same(obj.int64Map, {}, "should set int64Map");
+
+                test.end();
+            });
+
+            test.test(test.name + " - should convert", function(test) {
+                var buf = protobuf.util.newBuffer(3);
+                buf[0] = buf[1] = buf[2] = 49; // "111"
+                var msg = Message.create({
+                    uint64Val: protobuf.util.Long.fromNumber(1),
+                    uint64Repeated: [2, 3],
+                    bytesVal: buf,
+                    bytesRepeated: [buf, buf],
+                    enumVal: 2,
+                    enumRepeated: [1, 100, 2],
+                    int64Map: {
+                        a: protobuf.util.Long.fromNumber(2),
+                        b: protobuf.util.Long.fromNumber(3)
+                    }
+                });
+
+                var msgLongsToNumber = Message.toObject(msg, { longs: Number }),
+                    msgLongsToString = Message.toObject(msg, { longs: String });
+
+                test.same(Message.ctor.toObject(msg, { longs: Number}), msgLongsToNumber, "should convert the same using the static and the instance method");
+                test.same(Message.ctor.toObject(msg, { longs: String}), msgLongsToString, "should convert the same using the static and the instance method");
+
+                test.equal(msgLongsToNumber.uint64Val, 1, "longs to numbers");
+                test.equal(msgLongsToString.uint64Val, "1", "longs to strings");
+                test.same(msgLongsToNumber.int64Map, { a: 2, b: 3}, "long map values to numbers");
+                test.same(msgLongsToString.int64Map, { a: "2", b: "3"}, "long map values to strings");
+
+                test.equal(Object.prototype.toString.call(Message.toObject(msg, { bytes: Array }).bytesVal), "[object Array]", "bytes to arrays");
+                test.equal(Message.toObject(msg, { bytes: String }).bytesVal, "MTEx", "bytes to base64 strings");
+                if (protobuf.util.isNode)
+                    test.ok(Buffer.isBuffer(Message.toObject(msg, { bytes: Buffer }).bytesVal), "bytes to buffers");
+
+                test.equal(Message.toObject(msg, { enums: String }).enumVal, "TWO", "enums to strings");
+                test.equal(Message.toObject(msg, { enums: String }).enumRepeated[1], 100, "enums to strings does not change unknown values");
+
+                test.end();
+            });
+
+            test.test(test.name + " - Message.toObject with empty buffers", function(test) {
+                var msg = Message.create({
+                    bytesVal: protobuf.util.newBuffer(0),
+                });
+
+                test.equal(Message.toObject(msg, { bytes: String }).bytesVal, "", "bytes to base64 strings");
+
+                if (protobuf.util.isNode) {
+                    const bytesVal = Message.toObject(msg, { bytes: Buffer }).bytesVal; 
+                    test.ok(Buffer.isBuffer(bytesVal), "bytes to buffers");
+                    test.equal(bytesVal.length, 0, "empty buffer");
+                }
+
+                test.end();
+            });            
+
+        });
+
+        test.test(test.name + " - Message.fromObject", function(test) {
+
+            var obj = {
+                uint64Val: 1,
+                uint64Repeated: [1, "2"],
+                bytesVal: "MTEx",
+                bytesRepeated: ["MTEx", [49, 49, 49]],
+                enumVal: "ONE",
+                enumRepeated: [2, "TWO", 100],
+                int64Map: {
+                    a: 2,
+                    b: "3"
+                }
+            };
+            var msg = Message.fromObject(obj);
+
+            test.same(Message.ctor.fromObject(obj), msg, "should convert the same using the static and the instance method");
+            test.equal(Message.fromObject(msg), msg, "should just return the object if already a runtime message");
+
+            var buf = protobuf.util.newBuffer(3);
+            buf[0] = buf[1] = buf[2] = 49; // "111"
+
+            test.same(msg.uint64Val, { low: 1, high: 0, unsigned: true }, "should set uint64Val from a number");
+            test.same(msg.uint64Repeated, [ { low: 1, high: 0, unsigned: true}, { low: 2, high: 0, unsigned: true } ], "should set uint64Repeated from a number and a string");
+            test.same(msg.bytesVal, buf, "should set bytesVal from a base64 string");
+            test.same(msg.bytesRepeated, [ buf, buf ], "should set bytesRepeated from a base64 string and a plain array");
+            test.equal(msg.enumVal, 1, "should set enumVal from a string");
+            test.same(msg.enumRepeated, [ 2, 2, 100 ], "should set enumRepeated from a number and a string and preserve unknown value");
+            test.same(msg.int64Map, { a: { low: 2, high: 0, unsigned: false }, b: { low: 3, high: 0, unsigned: false } }, "should set int64Map from a number and a string");
+
+            test.end();
+        });
+
+        test.test(test.name + " - Message#toJSON", function(test) {
+            var msg = Message.create();
+            msg.$type = {
+                toObject: function(obj, opt) {
+                    test.same(opt, protobuf.util.toJSONOptions, "should use toJSONOptions with toJSON");
+                    test.end();
+                }
+            };
+            msg.toJSON();
+        });
+
+        test.end();
+    });
+
+});
diff --git a/tests/api_enum.js b/tests/api_enum.js
new file mode 100644
index 0000000..051bc51
--- /dev/null
+++ b/tests/api_enum.js
@@ -0,0 +1,91 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("reflected enums", function(test) {
+
+    var enm = new protobuf.Enum("Test", {
+        a: 1,
+        b: 2
+    });
+
+    var enm_allow_alias = new protobuf.Enum( 'AliasTest',
+    { a: 0 }, { allow_alias: true } );
+
+    test.throws(function() {
+        new protobuf.Enum("Test", true);
+    }, TypeError, "should throw if values is specified but not an object");
+
+    test.same(enm.valuesById, {
+        1: "a",
+        2: "b"
+    }, "should also expose their values by id");
+
+    test.throws(function() {
+        enm.add(2, 2);
+    }, TypeError, "should throw if name is not a string");
+
+    test.throws(function() {
+        enm.add("c", 1.5);
+    }, TypeError, "should throw if id is not an integer");
+
+    test.throws(function() {
+        enm.add("b", 2);
+    }, Error, "should throw if name is a duplicate");
+
+    test.throws(function() {
+        enm.add("c", 2);
+    }, Error, "should throw if id is a duplicate, without allow_alias option");
+
+    enm.add("c", 3);
+    test.same(enm.values, {
+        a: 1,
+        b: 2,
+        c: 3
+    }, "should allow adding new values");
+    test.same(enm.valuesById, {
+        1: "a",
+        2: "b",
+        3: "c"
+    }, "should also expose any new values by id");
+
+    test.throws(function() {
+        enm.remove(1);
+    }, TypeError, "should throw if name is not a string");
+
+    test.throws(function() {
+        enm.remove("d");
+    }, Error, "should throw if name is not present");
+
+    enm.remove("b");
+    test.same(enm.values, {
+        a: 1,
+        c: 3
+    }, "should allow removing existing values");
+    test.same(enm.valuesById, {
+        1: "a",
+        3: "c"
+    }, "should no longer expose any removed values by id");
+
+    test.same(enm.toJSON(), {
+        values: {
+            a: 1,
+            c: 3
+        }
+    }, "should export values to JSON");
+
+    enm_allow_alias.add( 'b', 0 );
+    test.same( enm_allow_alias.values, {
+      a: 0,
+      b: 0
+    });
+
+    enm.add('e', 4, undefined, {'(test_option)': 'test_value'});
+    test.same( enm.valuesOptions, {
+        'e': {
+            '(test_option)': 'test_value'
+        }
+    });
+
+    test.end();
+});
diff --git a/tests/api_field.js b/tests/api_field.js
new file mode 100644
index 0000000..23fa61f
--- /dev/null
+++ b/tests/api_field.js
@@ -0,0 +1,85 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("reflected fields", function(test) {
+
+    test.throws(function() {
+        new protobuf.Field(1);
+    }, TypeError, "should throw if name is not a string");
+
+    test.throws(function() {
+        new protobuf.Field("a", 1.5);
+    }, TypeError, "should throw if id is not an integer");
+
+    test.throws(function() {
+        new protobuf.Field("a", -5);
+    }, TypeError, "should throw if id is negative");
+
+    test.throws(function() {
+        new protobuf.Field("a", 1, 5);
+    }, TypeError, "should throw if type is not a string");
+
+    test.throws(function() {
+        new protobuf.Field("a", 1, "uint32", "optiona");
+    }, TypeError, "should throw if rule is specified but not a rule string");
+
+    test.throws(function() {
+        new protobuf.Field("a", 1, "uint32", "optional", 1);
+    }, TypeError, "should throw if extend is specified but not a string");
+
+    test.throws(function() {
+        new protobuf.Field("a", 1, "uint32", "optional", "B", true);
+    }, TypeError, "should throw if options is specified but not an object");
+
+    test.throws(function() {
+        var field = new protobuf.Field("a", 1, "UnDeFiNeD");
+        new protobuf.Root().add(new protobuf.Type("A").add(field));
+        field.resolve();
+    }, Error, "should throw if type cannot be resolved");
+
+    var root = new protobuf.Root(),
+        type,
+        field = new protobuf.Field("a", 1, "uint32", /* rule */ undefined, /* skipped extend, */ /* options */ {});
+
+    test.same(field.toJSON(), {
+        type: "uint32",
+        id: 1,
+        options: {}
+    }, "should export to JSON");
+
+    root.add(
+        type = new protobuf.Type("Test").add(
+            field = new protobuf.Field("a", 1, "Enm", /* skipped rule and extend, */ { "default": "ONE" })
+        )
+    ).add(
+        new protobuf.Enum("Enm", { "ONE": 1, "TWO": 2 })
+    ).resolveAll();
+
+    test.ok(field.resolvedType instanceof protobuf.Enum, "should resolve to an enum");
+
+    test.equal(field.typeDefault, 1, "should recognize enum default values as strings");
+
+    field.resolved = false;
+    field.options["default"] = 2;
+    field.resolve();
+
+    test.equal(field.typeDefault, 2, "should recognize enum default values as numbers");
+
+    type.add(field = new protobuf.Field("b", 2, "bytes", { default: "dGVzdA=="}));
+    field.resolve();
+
+    test.same(Array.prototype.slice.call(field.typeDefault), "test".split("").map(function(c) { return c.charCodeAt(0); }), "should recognize bytes default values as base64 encoded strings");
+
+    field.resolved = false;
+    field.options["default"] = "teststr"; // quirk: length not a multiple of 4 if using a subset of base64 chars
+    field.resolve();
+
+    test.same(Array.prototype.slice.call(field.typeDefault), "teststr".split("").map(function(c) { return c.charCodeAt(0); }), "should recognize bytes default values as strings");
+
+    field.resolved = 2;
+    field.resolve();
+    test.equal(field.resolved, 2, "should not resolve again if already resolved");
+
+    test.end();
+});
\ No newline at end of file
diff --git a/tests/api_inheritance.js b/tests/api_inheritance.js
new file mode 100644
index 0000000..f854827
--- /dev/null
+++ b/tests/api_inheritance.js
@@ -0,0 +1,42 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var objects = [
+    protobuf.Enum,
+    protobuf.Field,
+    protobuf.MapField,
+    protobuf.Method,
+    protobuf.Namespace,
+    protobuf.Root,
+    protobuf.Service,
+    protobuf.Type
+];
+
+var namespaces = [
+    protobuf.Root,
+    protobuf.Service,
+    protobuf.Type
+];
+
+var fields = [
+    protobuf.MapField
+];
+
+tape.test("inheritance", function(test) {
+
+    objects.forEach(function(object) {
+        test.ok(object.prototype instanceof protobuf.ReflectionObject, object.className + " should extend ReflectionObject");
+    });
+
+    namespaces.forEach(function(ns) {
+        test.ok(ns.prototype instanceof protobuf.Namespace, ns.className + " should extend Namespace");
+    });
+
+    fields.forEach(function(field) {
+        test.ok(field.prototype instanceof protobuf.Field, field.className + " should extend Field");
+    });
+
+    test.end();
+
+});
\ No newline at end of file
diff --git a/tests/api_longbits.js b/tests/api_longbits.js
new file mode 100644
index 0000000..388244b
--- /dev/null
+++ b/tests/api_longbits.js
@@ -0,0 +1,82 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+var LongBits = protobuf.util.LongBits;
+var Long = protobuf.util.Long;
+
+tape.test("longbits", function(test) {
+
+    test.test(test.name + " - zero", function(test) {
+        var zero = LongBits.zero;
+        test.equal(zero.lo, 0, "should have low bits of 0");
+        test.equal(zero.hi, 0, "should have high bits of 0");
+        test.equal(zero.toNumber(), 0, "should convert to number 0 (signed)");
+        test.equal(zero.toNumber(true), 0, "should convert to number 0 (unsigned)");
+        test.equal(zero.zzEncode(), zero, "should return itself when zig-zag encoded");
+        test.equal(zero.length(), 1, "should return a byte length of 1");
+        test.equal(LongBits.fromNumber(0), zero, "should be returned by fromNumber(0)");
+        test.equal(LongBits.from(0), zero, "should be returned by from(0)");
+        test.equal(LongBits.from(Long.ZERO), zero, "should be returned by from(Long.ZERO)");
+        test.same(zero.toLong(), Long.ZERO, "should equal Long.ZERO (signed)");
+        test.same(zero.toLong(true), Long.UZERO, "should equal Long.UZERO (unsigned)");
+        test.equal(zero.toHash(), "\0\0\0\0\0\0\0\0", "should convert to a binary hash of 8x0");
+        test.equal(protobuf.util.longToHash(0), "\0\0\0\0\0\0\0\0", "should convert to a binary hash of 8x0 (number 0 through util.longToHash)");
+        test.equal(LongBits.fromHash("\0\0\0\0\0\0\0\0"), zero, "should be returned for a binary hash of 8x0");
+        protobuf.util.Long = null;
+        test.equal(protobuf.util.longFromHash("\0\0\0\0\0\0\0\0"), 0, "should be returned for a binary hash of 8x0 (number 0 through util.longFromHash)");
+        protobuf.util.Long = Long;
+        test.end();
+    });
+
+    [
+        { low: 0, high: 0, unsigned: false, length: 1 },
+        { low: 0, high: 0, unsigned: true, length: 1 },
+        { low: (1 << 7) - 1, high: 0, unsigned: false, length: 1 },
+        { low: (1 << 7) - 1, high: 0, unsigned: true, length: 1 },
+        { low: (1 << 14) - 1, high: 0, unsigned: false, length: 2 },
+        { low: (1 << 14) - 1, high: 0, unsigned: true, length: 2 },
+        { low: (1 << 21) - 1, high: 0, unsigned: false, length: 3 },
+        { low: (1 << 21) - 1, high: 0, unsigned: true, length: 3 },
+        { low: (1 << 28) - 1, high: 0, unsigned: false, length: 4 },
+        { low: (1 << 28) - 1, high: 0, unsigned: true, length: 4 },
+        { low: -1, high: (1 << 3) - 1, unsigned: false, length: 5 },
+        { low: -1, high: (1 << 3) - 1, unsigned: true, length: 5 },
+        { low: -1, high: (1 << 10) - 1, unsigned: false, length: 6 },
+        { low: -1, high: (1 << 10) - 1, unsigned: true, length: 6 },
+        { low: -1, high: (1 << 17) - 1, unsigned: false, length: 7 },
+        { low: -1, high: (1 << 17) - 1, unsigned: true, length: 7 },
+        { low: -1, high: (1 << 24) - 1, unsigned: false, length: 8 },
+        { low: -1, high: (1 << 24) - 1, unsigned: true, length: 8 },
+        { low: -1, high: (1 << 31) - 1 | 0, unsigned: false, length: 9 },
+        { low: -1, high: (1 << 31) - 1 | 0, unsigned: true, length: 9 },
+        { low: -1, high: -1, unsigned: false, length: 10 },
+        { low: -1, high: -1, unsigned: true, length: 10 },
+        { low: 0, high: 1 << 31, unsigned: false, length: 10 },
+        { low: 0, high: 1 << 31, unsigned: true, length: 10 },
+        { low: 0, high: -1, unsigned: false, length: 10 }
+    ]
+    .forEach(function(value) {
+        var long = Long.fromValue(value);
+        test.equal(long.unsigned, value.unsigned, long + " should be signed/unsigned");
+        var bits = LongBits.from(value);
+        test.equal(bits.lo, long.low >>> 0, long + " should have equal low bits");
+        test.equal(bits.hi, long.high >>> 0, long + " should have equal high bits");
+        test.equal(bits.length(), value.length, long + " should return an equal length");
+        test.equal(bits.toNumber(value.unsigned), long.toNumber(), long + " should convert to an equal number");
+        var number = long.toNumber(value.unsigned);
+        if (number <= 9007199254740991 && number >= -9007199254740991)
+            test.same(LongBits.fromNumber(number), bits, long + " should convert hence and forth equally (where safe)");
+        test.same(bits.toLong(value.unsigned), long, long + " should convert to an equal Long");
+        var comp = String.fromCharCode.apply(String, long.toBytesLE());
+        test.equal(bits.toHash(), comp, long + " should convert to an equal hash");
+        test.equal(protobuf.util.longToHash(long), comp, long + " should convert to an equal hash through util.longToHash");
+        test.same(LongBits.fromHash(comp), bits, long + " should convert back to an equal value");
+        test.same(protobuf.util.longFromHash(comp, long.unsigned), long, long + " should convert back to an equal value through util.longFromHash");
+    });
+
+    var num = -4294967296 * 4294967296;
+    var bits = LongBits.fromNumber(num);
+    test.same(bits, { lo: 0, hi: 0 }, "lo and hi should properly overflow when converting " + num);
+
+    test.end();
+});
\ No newline at end of file
diff --git a/tests/api_mapfield.js b/tests/api_mapfield.js
new file mode 100644
index 0000000..917b528
--- /dev/null
+++ b/tests/api_mapfield.js
@@ -0,0 +1,21 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var def = {
+    keyType: "bytes",
+    type: "string",
+    id: 1
+};
+
+tape.test("reflected map fields", function(test) {
+
+    var field = protobuf.MapField.fromJSON("a", def);
+    test.same(field.toJSON(), def, "should construct from and convert back to JSON");
+
+    test.throws(function() {
+        field.resolve();
+    }, Error, "should throw for invalid key types");
+
+    test.end();
+});
diff --git a/tests/api_namespace.js b/tests/api_namespace.js
new file mode 100644
index 0000000..b7203da
--- /dev/null
+++ b/tests/api_namespace.js
@@ -0,0 +1,133 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var def = {};
+
+var proto = "package ns;\
+enum Enm {\
+    ONE = 1;\
+    TWO = 2;\
+}\
+message Msg {\
+    message Enm {}\
+}\
+service Svc {}";
+
+tape.test("reflected namespaces", function(test) {
+
+    var ns = protobuf.Namespace.fromJSON("ns", def);
+    test.same(ns.toJSON(), def, "should construct from and convert back to JSON");
+
+    var root = protobuf.parse(proto).root;
+    ns = root.lookup("ns").resolveAll();
+    test.same(ns.getEnum("Enm"), { ONE: 1, TWO: 2 }, "should get enums");
+
+    test.throws(function() {
+        ns.getEnum("Msg");
+    }, Error, "should throw when getting a message as an enum");
+
+    test.throws(function() {
+        ns.getEnum("NOTFOUND");
+    }, Error, "should throw when getting null as an enum");
+
+    test.ok(ns.lookupType("Msg"), "should lookup types");
+
+    test.equal(ns.get("Msg").lookupTypeOrEnum("Enm"), ns.lookup(".ns.Msg.Enm"), "should lookup the nearest type or enum");
+
+    test.throws(function() {
+        ns.lookupType("Enm");
+    }, Error, "should throw when looking up an enum as a type");
+
+    test.throws(function() {
+        ns.lookupType("NOTFOUND");
+    }, Error, "should throw when looking up null as a type");
+
+    test.ok(ns.lookupEnum("Enm"), "should lookup enums");
+
+    test.throws(function() {
+        ns.lookupEnum("Msg");
+    }, Error, "should throw when looking up a type as an enum");
+
+    test.throws(function() {
+        ns.lookupEnum("NOTFOUND");
+    }, Error, "should throw when looking up null as an enum");
+
+    test.ok(ns.lookupService("Svc"), "should lookup services");
+
+    test.throws(function() {
+        ns.lookupService("Msg");
+    }, Error, "should throw when looking up a type as a service");
+
+    test.throws(function() {
+        ns.lookupService("NOTFOUND");
+    }, Error, "should throw when looking up null as a service");
+
+    test.equal(ns.lookup(""), ns, "should lookup itself for an empty path");
+
+    test.equal(ns.lookup([]), ns, "should lookup itself for []");
+
+    test.ok(ns.lookup(".") instanceof protobuf.Root, "should lookup root for .");
+
+    test.ok(ns.lookup([""]) instanceof protobuf.Root, "should lookup root for [\"\"]");
+
+    test.throws(function() {
+        ns.define(null);
+    }, "should throw when path is not a string or array");
+
+    test.throws(function() {
+        ns.define(".sub", {});
+    }, "should throw when defining absolute .sub");
+
+    test.throws(function() {
+        ns.define(["", "sub"], {});
+    }, "should throw when defining absolute [\"\", \"sub\"]");
+
+    var sub = ns.define("sub", {});
+    test.equal(ns.lookup("sub"), sub, "should define sub namespaces");
+
+    test.throws(function() {
+        ns.add(new protobuf.ReflectionObject("invalid"));
+    }, TypeError, "should throw when adding invalid nested objects");
+
+    test.throws(function() {
+        ns.add(new protobuf.Enum("sub"));
+    }, Error, "should throw on duplicate names");
+
+    sub = ns.define("sub.sub");
+    test.equal(ns.lookup("sub.sub"), sub, "should define sub sub namespaces");
+
+    test.throws(function() {
+        ns.remove(true);
+    }, TypeError, "should throw when trying to remove non-reflection objects");
+
+    test.throws(function() {
+        ns.remove(new protobuf.Enum("Enm"));
+    }, Error, "should throw when trying to remove non-children");
+
+    test.throws(function() {
+        ns.add(new protobuf.Enum("MyEnum", {}));
+        ns.define("MyEnum");
+    }, Error, "should throw when trying to define a path conflicting with non-namespace objects");
+
+    ns = protobuf.Namespace.fromJSON("My", {
+        nested: {
+            Message: { fields: {} },
+            Enum: { values: {} },
+            Service: { methods: {} },
+            extensionField: { type: "string", id: 1000, extend: "Message" },
+            Other: { nested: {} }
+        }
+    });
+    test.same(ns.toJSON(), {
+        nested: {
+            Message: { fields: {} },
+            Enum: { values: {} },
+            Service: { methods: {} },
+            extensionField: { extend: "Message", id: 1000, type: "string" },
+            Other: { }
+        }
+    }, "should create from Type, Enum, Service, extension Field and Namespace JSON");
+
+    test.end();
+});
diff --git a/tests/api_object.js b/tests/api_object.js
new file mode 100644
index 0000000..9dda733
--- /dev/null
+++ b/tests/api_object.js
@@ -0,0 +1,44 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("reflection objects", function(test) {
+
+    test.throws(function() { new protobuf.ReflectionObject(null); }, TypeError, "should throw on construction if name is not a string");
+    test.throws(function() { new protobuf.ReflectionObject("name", true); }, TypeError, "should throw on construction if options is not an object if not omitted");
+
+    var obj = new protobuf.ReflectionObject("Test");
+
+    obj.resolve();
+    test.equal(obj.resolved, false, "should not resolve when not part of a root");
+
+    obj.resolved = 2;
+    obj.resolve();
+    test.equal(obj.resolved, 2, "should not resolve again when already resolved");
+    obj.resolved = false;
+
+    obj.setOptions({ a: 1, b: 2 });
+    test.same(obj.options, { a: 1, b: 2 }, "should set multiple options");
+    obj.setOptions(undefined);
+    test.same(obj.options, { a: 1, b: 2 }, "should accept undefined as options");    
+    obj.setOption("c", 3);
+    test.same(obj.options, { a: 1, b: 2, c: 3 }, "should set single options");
+
+    obj.setParsedOption("opt1", {a: 1, b: 2});
+    test.same(obj.parsedOptions, [{"opt1": {a: 1, b: 2}}], "should set single parsed option");
+    obj.setParsedOption("opt1", {a: 3, b: 4});
+    test.same(obj.parsedOptions, [{"opt1": {a: 1, b: 2}}, {"opt1": {a: 3, b: 4}}], "should allow same option twice");
+    obj.setParsedOption("opt2", 1, "x");
+    test.same(obj.parsedOptions, [{"opt1": {a: 1, b: 2}}, {"opt1": {a: 3, b: 4}}, {"opt2": {x: 1}}], "should create new option using property path");
+    obj.setParsedOption("opt2", 5, "a.b");
+    test.same(obj.parsedOptions, [{"opt1": {a: 1, b: 2}}, {"opt1": {a: 3, b: 4}}, {"opt2": {x: 1, a: {b :5}}}], "should merge new property path in existing option");
+    obj.setParsedOption("opt2", 6, "x");
+    test.same(obj.parsedOptions, [{"opt1": {a: 1, b: 2}}, {"opt1": {a: 3, b: 4}}, {"opt2": {x: [1,6], a: {b :5}}}], "should convert property to array when set more than once");
+
+
+    test.equal(obj.toString(), "ReflectionObject Test", "should convert to a string (even if not part of a root)");
+    obj.name = "";
+    test.equal(obj.toString(), "ReflectionObject", "should convert to a string even with no full name");
+
+    test.end();
+});
\ No newline at end of file
diff --git a/tests/api_oneof.js b/tests/api_oneof.js
new file mode 100644
index 0000000..507efc7
--- /dev/null
+++ b/tests/api_oneof.js
@@ -0,0 +1,61 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var def = {
+    oneof: ["a", "b"],
+    options: {}
+};
+
+var proto = "syntax = \"proto3\";\
+import \"google/protobuf/descriptor.proto\";\
+extend google.protobuf.FileOptions { optional int32 ecs_component_id = 50000;}\
+option (ecs_component_id) = 1020;\
+message Test {\
+    oneof kind {\
+        uint32 a = 1;\
+        string b = 2;\
+    }\
+    bool c = 3;\
+}";
+
+tape.test("reflected oneofs", function(test) {
+
+    var oneof = protobuf.OneOf.fromJSON("kind", {
+        oneof: ["a", "b"],
+        options: {}
+    });
+    test.same(oneof.toJSON(), def, "should construct from and convert back to JSON");
+
+    var root = protobuf.parse(proto).root;
+    var Test = root.lookup("Test");
+    var kind = Test.get("kind");
+    var field = Test.get("c");
+
+    kind.add(field);
+    test.same(kind.toJSON(), {
+        oneof: ["a", "b", "c"]
+    }, "should allow adding fields");
+    test.ok(Test.get("c"), "should still have the field on the parent");
+
+    kind.remove(field);
+    test.same(kind.toJSON(), {
+        oneof: ["a", "b"]
+    }, "should allow removing fields");
+    test.ok(Test.get("c"), "should still have the field on the parent");
+
+    var Test2 = new protobuf.Type("Test2");
+    root.add(Test2);
+    Test2.add(field);
+    kind.add(field);
+    test.notOk(Test2.get("c"), "should remove the field from the previous parent");
+
+    var looseField = new protobuf.Field("d", 4, "float");
+    kind.add(looseField); // no parent
+    Test.remove(looseField);
+    Test.remove(kind);
+    test.same(Test.fields, {}, "should remove all fields from the parent");
+    test.same(kind.oneof, ["a","b","c","d"], "should still have the fields on the oneof");
+
+    test.end();
+});
diff --git a/tests/api_reader-writer-reuse.js b/tests/api_reader-writer-reuse.js
new file mode 100644
index 0000000..5820918
--- /dev/null
+++ b/tests/api_reader-writer-reuse.js
@@ -0,0 +1,59 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var proto = "message A {\
+    required uint32 a = 1;\
+}\
+message B {\
+    required string b = 1;\
+}";
+
+tape.test("reusing", function(test) {
+    var root = protobuf.parse(proto).root;
+
+    var A = root.lookup("A"),
+        B = root.lookup("B");
+
+    test.test(test.name + " - a writer should write", function(test) {
+
+        var writer = protobuf.Writer.create();
+
+        A.encodeDelimited({
+            a: 1
+        }, writer);
+
+        B.encodeDelimited({
+            b: "a"
+        }, writer);
+
+        var buffer = writer.finish();
+
+        test.equal(buffer[0], 2, "length 2");
+        test.equal(buffer[1], 8, "id 1, wireType 0");
+        test.equal(buffer[2], 1, "number 1");
+        test.equal(buffer[3], 3, "length 3");
+        test.equal(buffer[4], 10, "id 1, wireType 2");
+        test.equal(buffer[5], 1, "length 1");
+        test.equal(buffer[6], 97, "string 'a'");
+
+        var reader = protobuf.Reader.create(buffer);
+
+        test.test(test.name + " - and a reader should", function(test) {
+
+            var a = A.decodeDelimited(reader);
+            test.deepEqual(a, { a: 1 }, "read back the first message");
+
+            var b = B.decodeDelimited(reader);
+            test.deepEqual(b, { b: "a" }, "read back the second message");
+
+            test.equal(reader.pos, reader.len, "consume the reader");
+
+            test.end();
+        });
+
+        test.end();
+    });
+
+    test.end();
+});
diff --git a/tests/api_root-deferred.js b/tests/api_root-deferred.js
new file mode 100644
index 0000000..577e7b5
--- /dev/null
+++ b/tests/api_root-deferred.js
@@ -0,0 +1,40 @@
+var tape = require("tape");
+
+var protobuf  = require(".."),
+    Namespace = protobuf.Namespace,
+    Type      = protobuf.Type,
+    Field     = protobuf.Field;
+
+tape.test("extension fields", function(test) {
+
+    var root = new protobuf.Root({ noGoogleTypes: true }),
+        ns = new Namespace("my"),
+        type = new Type("DeclaringType"),
+        declaringField = new Field("declaringField", 1, "string", "optional", "ExtendedType");
+    root.add(ns.add(type.add(declaringField)));
+
+    test.deepEqual(root.deferred[0], declaringField, "should be deferred until their extended type can be resolved");
+
+    var extendedType = new Type("ExtendedType");
+    ns.add(extendedType);
+    var extensionField = extendedType.get(declaringField.fullName);
+    test.equal(extensionField, declaringField.extensionField, "should become available once their extended type is known");
+
+    type.remove(declaringField);
+    extensionField = extendedType.get(declaringField.fullName);
+    test.equal(extensionField, null, "should become unavailable when their declaring field is removed");
+
+    type.add(declaringField);
+    extensionField = extendedType.get(declaringField.fullName);
+    test.equal(extensionField, declaringField.extensionField, "should become instantly available if their extended type is knwon");
+
+    ns.remove(extendedType);
+    type.remove(declaringField);
+    type.add(declaringField);
+    test.throws(function() {
+        root.resolveAll();
+    }, Error, "should throw on resolveAll if there are unresolvable extensions");
+    type.remove(declaringField);
+
+    test.end();
+});
diff --git a/tests/api_root-expose.js b/tests/api_root-expose.js
new file mode 100644
index 0000000..a143bae
--- /dev/null
+++ b/tests/api_root-expose.js
@@ -0,0 +1,38 @@
+var tape = require("tape");
+
+var protobuf  = require("..");
+
+tape.test("exposure handlers", function(test) {
+    var root = new protobuf.Root();
+
+    var ns = new protobuf.Namespace("MyNamespace");
+    root.add(ns);
+    test.ok(root.MyNamespace, "should expose namespaces on roots");
+
+    var type = new protobuf.Type("MyType");
+    ns.add(type);
+    test.ok(root.MyNamespace.MyType, "should expose types on namespaces");
+
+    var lcType = new protobuf.Type("myType");
+    ns.add(lcType);
+    test.notOk(root.MyNamespace.myType, "should not expose lower-cased types on namespaces");
+
+    var enm = new protobuf.Enum("MyEnum", {});
+    type.add(enm);
+    test.ok(root.MyNamespace.MyType.MyEnum, "should expose enums on types");
+
+    var lcEnm = new protobuf.Enum("myEnum", {});
+    type.add(lcEnm);
+    test.notOk(root.MyNamespace.MyType.myEnum, "should not expose lower-cased enums on types");
+
+    ns.remove(type);
+    test.notOk(root.MyNamespace.MyType, "should unexpose types on namespaces");
+
+    type.remove(enm);
+    test.notOk(type.MyEnum, "should unexpose enums on types, even if no longer part of a root");
+
+    root.remove(ns);
+    test.notOk(root.MyNamespace, "should unexpose namespaces on roots");
+
+    test.end();
+});
\ No newline at end of file
diff --git a/tests/api_root.js b/tests/api_root.js
new file mode 100644
index 0000000..6e9814d
--- /dev/null
+++ b/tests/api_root.js
@@ -0,0 +1,95 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var Root = protobuf.Root;
+
+var def = {
+    nested: {},
+    options: { javaPackage: "com.something" }
+};
+
+tape.test("reflected roots", function(test) {
+
+    test.test(test.name + " - construct", function(test) {
+        var root = Root.fromJSON(def);
+        test.ok(root instanceof Root, "should construct from JSON");
+        var root2 = Root.fromJSON(def, root);
+        test.equal(root2, root, "should construct from JSON and reuse specified Root");
+        test.end();
+    });
+
+    if (typeof Promise !== "undefined")
+    test.test(test.name + " - promise", function(test) {
+        var root = new Root();
+        var promise = root.load("tests/data/common.proto");
+        test.ok(promise instanceof Promise, "should return a Promise when loading without a callback");
+        promise
+        .then(function() {
+            test.pass("should resolve");
+            test.end();
+        })
+        .catch(function() {
+            test.fail("should not reject");
+        });
+    });
+
+    test.test(test.name + " - json", function(test) {
+        var root = new Root();
+        test.plan(3);
+        root.load("tests/data/common.json", function(err) {
+            if (err)
+                return test.fail("should not return an error when loading JSON files: " + err.message);
+            test.ok(root.lookupType("google.protobuf.Any"), "should load JSON files");
+            root.load("tests/data/common.json", function(err) {
+                test.same(root.files, [ "tests/data/common.json" ], "should not attempt to load the same file twice");
+                test.notOk(err, "should not return an error when loading files twice");
+                test.end();
+            });
+        });
+    });
+
+    test.test(test.name + " - weak", function(test) {
+        var root = new Root();
+        test.plan(1);        
+        root.load(["tests/data/weak.proto"], function (err) {
+            test.notOk(err, "should ignore missing weak imports");
+            test.end();
+        });
+    });
+
+    test.test(test.name + " - missing", function(test) {
+        var root = new Root();
+        test.plan(1);
+        root.load("tests/data/NOTFOUND", function(err) {
+            test.ok(err, "should return an error when trying to load missing protos");
+            test.end();
+        });
+    });
+
+    test.test(test.name + " - skipped", function(test) {
+        var root = new Root();
+        root.resolvePath = function() {
+            return null;
+        };
+        test.plan(1);
+        root.load("tests/data/NOTFOUND2", function(err) {
+            test.notOk(err, "should skip files without error when resolvePath returns null");
+            test.end();
+        });
+    });
+
+    test.test(test.name + " - skipped import", function(test) {
+        var root = new Root();
+        root.resolvePath = function(origin, target) {
+            if (/weak\.proto$/.test(target))
+                return protobuf.util.path.resolve(origin, target);
+            return null;
+        };
+        test.plan(1);
+        root.load("tests/data/weak.proto", function(err) {
+            test.notOk(err, "should skip files without error when resolvePath returns null");
+            test.end();
+        });
+    });
+});
diff --git a/tests/api_service-rpc-streaming.js b/tests/api_service-rpc-streaming.js
new file mode 100644
index 0000000..94618a5
--- /dev/null
+++ b/tests/api_service-rpc-streaming.js
@@ -0,0 +1,165 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("runtime services", function(test) {
+
+    // FIXME
+
+    protobuf.load("tests/data/rpc.proto", function(err, root) {
+        if (err)
+            return test.fail(err.message);
+
+        var MyService  = root.lookup("MyService"),
+            MyMethod   = MyService.get("MyMethod").resolve(),
+            MyRequest  = MyMethod.resolvedRequestType,
+            MyResponse = MyMethod.resolvedResponseType;
+
+        var statusCodes = [200, 400];
+        var timesCalled = 0;
+       
+        MyService = root.lookup("MyService");
+
+        test.plan(2);
+
+        test.test(test.name + " - closed server-side", function(test) {
+
+            function rpc(method, requestData, callback) {
+                if (++timesCalled < 3) {
+                    test.test(test.name + " - should call the rpc impl with", function(test) {
+                        test.equal(method, MyMethod, "the reflected method");
+                        test.ok(requestData.length, "a buffer");
+                        test.ok(typeof callback === "function", "a callback function");
+                        test.end();
+                    });
+                    test.test(test.name + " - should call with a buffer that contains", function(test) {
+                        test.equal(requestData[0], 3, "ldelim 3");
+                        test.equal(requestData[1], 10, "id 1, wireType 2");
+                        test.equal(requestData[2], 1, "length 1");
+                        test.equal(requestData[3], 0x2f, "the original string");
+                        test.end();
+                    });
+                    setTimeout(function() {
+                        var status = statusCodes.shift();
+                        callback(null, MyResponse.encode({
+                            status: status
+                        }).finish());
+                        if (status === 200)
+                            callback(null, null); // ended server-side
+                    });
+                } else {
+                    test.equal(requestData, null, "should signal ended client-side");
+                }
+            }
+
+            var service = MyService.create(rpc, true, false);
+            service.myMethod(MyRequest.create({
+                path: "/"
+            }), function(err, response) {
+                if (err)
+                    return test.fail(err.message);
+                test.ok(response instanceof MyResponse.ctor, "should return an instance of MyResponse");
+                test.deepEqual(response, {
+                    status: 200
+                }, "should return status 200");
+
+                test.end();
+            });
+        });
+
+        test.test(test.name + " - closed client-side", function(test) {
+
+            function rpc(method, requestData, callback) {
+                if (++timesCalled < 3) {
+                    test.test(test.name + " - should call the rpc impl with", function(test) {
+                        test.equal(method, MyMethod, "the reflected method");
+                        test.ok(requestData.length, "a buffer");
+                        test.ok(typeof callback === "function", "a callback function");
+                        test.end();
+                    });
+                    test.test(test.name + " - should call with a buffer that contains", function(test) {
+                        test.equal(requestData[0], 3, "ldelim 3");
+                        test.equal(requestData[1], 10, "id 1, wireType 2");
+                        test.equal(requestData[2], 1, "length 1");
+                        test.equal(requestData[3], 0x2f, "the original string");
+                        test.end();
+                    });
+                    setTimeout(function() {
+                        var status = statusCodes.shift();
+                        callback(null, MyResponse.encode({
+                            status: status
+                        }).finish());
+                        if (status === 200)
+                            callback(null, null); // ended server-side
+                    });
+                } else {
+                    test.equal(requestData, null, "should signal ended client-side");
+                }
+            }
+
+            var service = MyService.create(rpc, true, false);
+            service.myMethod(MyRequest.create({
+                path: "/"
+            }), function(err, response) {
+                if (err)
+                    return test.fail(err.message);
+                test.ok(response instanceof MyResponse.ctor, "should return an instance of MyResponse");
+                test.deepEqual(response, {
+                    status: 400
+                }, "should return status 400");
+                service.end(); // ended client-side
+
+                var count = 0,
+                    total = 1;
+
+                if (typeof Promise !== "undefined") {
+                    ++total;
+                    var promise = service.myMethod(MyRequest.create({ path: "/" }));
+                    promise.catch(function(err) {
+                        test.ok(err, "should return an error if already ended (Promise)");
+                        if (++count === total)
+                            test.end();
+                    });
+                    test.ok(promise instanceof Promise, "should return a promise if callback has been omitted (even if already ended)");
+                }
+
+                service.myMethod(MyRequest.create({ path: "/" }), function(err) {
+                    test.ok(err, "should return an error if already ended");
+                    if (++count === total)
+                        test.end();
+                });
+            });
+        });
+    });
+});
+
+function fakeRPC(test) {
+    function rpc(method, requestData, callback) {
+        if (++timesCalled < 3) {
+            test.test(test.name + " - should call the rpc impl with", function(test) {
+                test.equal(method, MyMethod, "the reflected method");
+                test.ok(requestData.length, "a buffer");
+                test.ok(typeof callback === "function", "a callback function");
+                test.end();
+            });
+            test.test(test.name + " - should call with a buffer that contains", function(test) {
+                test.equal(requestData[0], 3, "ldelim 3");
+                test.equal(requestData[1], 10, "id 1, wireType 2");
+                test.equal(requestData[2], 1, "length 1");
+                test.equal(requestData[3], 0x2f, "the original string");
+                test.end();
+            });
+            setTimeout(function() {
+                var status = statusCodes.shift();
+                callback(null, MyResponse.encode({
+                    status: status
+                }).finish());
+                if (status === 200)
+                    callback(null, null); // ended server-side
+            });
+        } else {
+            test.equal(requestData, null, "should signal ended client-side");
+        }
+    }
+    return rpc;
+}
\ No newline at end of file
diff --git a/tests/api_service-rpc.js b/tests/api_service-rpc.js
new file mode 100644
index 0000000..53d67ac
--- /dev/null
+++ b/tests/api_service-rpc.js
@@ -0,0 +1,118 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var proto = "syntax = \"proto3\";\
+package myservice;\
+message DoSomethingRequest {\
+}\
+message DoSomethingResponse {\
+}\
+service MyService {\
+  rpc DoSomething(DoSomethingRequest) returns (DoSomethingResponse) {\
+    option (google.api.http) = {\
+      get: \"/v1/dosomething\"\
+    };\
+  };\
+}";
+
+tape.test("reflected services", function(test) {
+    var root = protobuf.parse(proto).root;
+
+    var myservice = root.lookup("myservice").resolveAll(),
+        MyService = myservice.MyService,
+        DoSomethingRequest = myservice.DoSomethingRequest,
+        DoSomethingResponse = myservice.DoSomethingResponse,
+        DoSomething = MyService.get("DoSomething");
+
+    test.throws(function() {
+        MyService.create();
+    }, TypeError, "should throw if rpcImpl is not specified");
+
+    function rpcImpl(method, requestData, callback) {
+        if (requestData) {
+            test.equal(method, DoSomething, "rpcImpl should reference the correct method");
+            test.ok(callback, "rpcImpl should provide a callback");
+            setTimeout(function() {
+                callback(null, DoSomethingResponse.create());
+            });
+        } else {
+            test.equal(method, null, "rpcImpl should not reference a method when closed");
+            test.equal(callback, null, "rpcImpl should not provide a callback when closed");
+        }
+    }
+
+    var service = MyService.create(rpcImpl);
+
+    test.throws(function() {
+        service.doSomething();
+    }, TypeError, "should throw if request is not specified");
+
+    test.test(test.name + " - should propagate errors from rpcImpl", function(test) {
+        var err = Error();
+        var service2 = MyService.create(function(method, requestData, callback) { callback(err); });
+        var count = 0;
+        service2.on("error", function(err2) {
+            test.equal(err2, err, "should emit the exact error");
+            if (++count === 2)
+                test.end();
+        });
+        service2.doSomething({}, function(err2) {
+            test.equal(err2, err, "should return the exact error");
+            if (++count === 2)
+                test.end();
+        });
+    });
+
+    test.test(test.name + " - should catch errors within rpcImpl", function(test) {
+        var err = Error();
+        var service2 = MyService.create(function(method, requestData, callback) { throw err; });
+        var count = 0;
+        service2.on("error", function(err2) {
+            test.equal(err2, err, "should emit the exact error");
+            if (++count === 2)
+                test.end();
+        });
+        service2.doSomething({}, function(err2) {
+            test.equal(err2, err, "should return the exact error");
+            if (++count === 2)
+                test.end();
+        });
+    });
+
+    test.test(test.name + " - should return errors from decoding", function(test) {
+        var service2 = MyService.create(function(method, requestData, callback) { callback(null, protobuf.util.newBuffer(0) ); }, true, true);
+        var count = 0;
+        service2.on("error", function(err2) {
+            test.ok(err2, "should emit the error");
+            if (++count === 2)
+                test.end();
+        });
+        service2.doSomething({}, function(err2) {
+            test.ok(err2, "should return the error");
+            if (++count === 2)
+                test.end();
+        });
+    });
+
+    var dataEmitted = false;
+    service.on("data", function(responseData) {
+        dataEmitted = true;
+        test.ok(responseData, "should emit the data event");
+    });
+    var endCalled = false;
+    service.on("end", function() {
+        test.notOk(endCalled, "should not emit the end event twice");
+        endCalled = true;
+        test.pass("should call the end event");
+        service.end();
+        test.end();
+    });
+    service.doSomething(DoSomethingRequest.create(), function(err, res) {
+        test.notOk(err, "should not raise an error");
+        test.ok(res instanceof DoSomethingResponse.ctor, "should return a properly typed response");
+        test.ok(dataEmitted, "should have emitted the data event");
+        service.end();
+    });
+    
+});
\ No newline at end of file
diff --git a/tests/api_service.js b/tests/api_service.js
new file mode 100644
index 0000000..805caf7
--- /dev/null
+++ b/tests/api_service.js
@@ -0,0 +1,47 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var def = {
+    methods: {},
+    nested: {
+        SomeEnum: {
+            values: {}
+        }
+    }
+};
+
+var methodDef = {
+    requestType: "MyRequest",
+    requestStream: true,
+    responseType: "MyResponse",
+    responseStream: true,
+    options: {}
+};
+
+tape.test("reflected services", function(test) {
+
+    var MyService = protobuf.Service.fromJSON("MyService", def);
+    test.same(MyService.toJSON(), def, "should construct without methods from and convert back to JSON");
+
+    var MyMethod = protobuf.Method.fromJSON("MyMethod", methodDef);
+    test.same(MyMethod.toJSON(), methodDef, "should constructos methods from and convert back to JSON");
+
+    MyService.add(MyMethod);
+    test.ok(MyService.get("MyMethod"), "should allow adding methods");
+    var other = new protobuf.Enum("Other", {});
+    MyService.add(other);
+    test.ok(MyService.get("Other"), "should allow adding other nested objects");
+    MyService.remove(other);
+    test.notOk(MyService.get("Other"), "should allow removing other nested objects");
+    MyService.remove(MyMethod);
+    test.notOk(MyService.get("Other"), "should allow removing methods");
+    test.same(MyService.toJSON(), def, "should convert to initial JSON afterwards");
+
+    def.methods.MyMethod = methodDef;
+    MyService = protobuf.Service.fromJSON("MyService", def);
+    test.same(MyService.toJSON(), def, "should construct with methods from and convert back to JSON");
+    MyMethod = MyService.get("MyMethod");
+
+    test.end();
+});
diff --git a/tests/api_tokenize.js b/tests/api_tokenize.js
new file mode 100644
index 0000000..7f408fb
--- /dev/null
+++ b/tests/api_tokenize.js
@@ -0,0 +1,86 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var tokenize = protobuf.tokenize;
+
+tape.test("tokenize", function(test) {
+
+    test.test(test.name + " - unescape", function(test) {
+        test.equal(tokenize.unescape("\\\\0 \\\0 \\0 \0"), "\\0  \0 \0", "should propery unescape zero-sequences");
+        test.equal(tokenize.unescape("\\\t\\t\\r\\n"), "\t\r\n", "should propery unescape tabs and line feeds");
+        test.end();
+    });
+
+    test.ok(expect("", [null]), "should instantly finish for an empty source");
+    test.ok(expect("'hello\\nworld'", ["'", "hello\nworld", "'", null]), "should parse single quoted strings");
+    test.ok(expect("\"hello\\nworld\"", ["\"", "hello\nworld", "\"", null]), "should parse double quoted strings");
+    test.ok(expectError("\"as\"d\""), "should throw for invalid strings");
+
+    var tn = tokenize("message Test {}");
+    test.throws(function() {
+        tn.skip("somethingelse", false);
+    }, Error, "should throw when skipping non-optional tokens");
+    test.doesNotThrow(function() {
+        tn.skip("somethingelse", true);
+    }, Error, "should not throw when skipping optional tokens");
+
+    tn = tokenize("// line comment");
+    test.equal(tn.next(), null, "should skip line comments on a single line");
+    tn = tokenize("a /// line comment\n");
+    tn.next();
+    test.equal(tn.cmnt(1), "line comment", "should peek for trailing line comments");
+    tn = tokenize("/* block comment */");
+    test.equal(tn.next(), null, "should skip block comments on a single line");
+    tn = tokenize("/// line comment\na\n");
+    tn.next();
+    test.equal(tn.cmnt(), "line comment", "should keep leading comments around while on the next line");
+    tn = tokenize("/// leading comment A\na /// trailing comment A\nb /// trailing comment B\n");
+    tn.next();
+    test.equal(tn.cmnt(), "leading comment A", "should parse leading comment");
+    test.equal(tn.cmnt(tn.line), "trailing comment A", "should parse trailing comment");
+    tn.next();
+    test.equal(tn.cmnt(), null, "trailing comment should not be recognized as leading comment for next line");
+    test.equal(tn.cmnt(tn.line), "trailing comment B", "should parse trailing comment");
+    tn = tokenize("/// leading comment A\na /// trailing comment A\n/// leading comment B\nb /// trailing comment B\n");
+    tn.next();
+    test.equal(tn.cmnt(tn.line), "trailing comment A", "trailing comment should not contain leading comment from next line");
+    tn.next();
+    test.equal(tn.cmnt(), 'leading comment B', "leading comment should be present after trailing comment");
+
+    test.ok(expectError("something; /"), "should throw for unterminated line comments");
+    test.ok(expectError("something; /* comment"), "should throw for unterminated block comments");
+    test.ok(expectError("something; /* comment *"), "should throw for unterminated block comments");
+    test.ok(expect("a / / b", ["a", "/", "/", "b", null]), "should not misinterpret single slashes as a comment");
+
+    test.end();
+});
+
+function expect(proto, expected) {
+    var tn = tokenize(proto);
+    var token;
+    var actual = [];
+    do {
+        actual.push(token = tn.next());
+    } while (token !== null);
+    if (actual.length !== expected.length) {
+        // console.error("actual", actual, " != expected" , expected);
+        return false;
+    }
+    for (var i = 0; i < expected.length; ++i)
+        if (actual[i] !== expected[i]) {
+            // console.error("actual", actual, " != expected" , expected);
+            return false;
+        }
+    return true;
+}
+
+function expectError(proto) {
+    var tn = tokenize(proto);
+    try {
+        while (tn.next());
+        return null;
+    } catch (e) {
+        return e;
+    }
+}
diff --git a/tests/api_type.js b/tests/api_type.js
new file mode 100644
index 0000000..5930661
--- /dev/null
+++ b/tests/api_type.js
@@ -0,0 +1,102 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var def = {
+    fields: {}
+};
+
+var def2 = {
+    fields: {
+        a: {
+            type: "uint32",
+            id: 1
+        }
+    },
+    oneofs: {
+        kind: {
+            oneof: ["a"]
+        }
+    },
+    extensions: [[1000, 2000]],
+    reserved: [[900, 999], "b"],
+    nested: {
+        Type: {
+            values: { ONE: 1, TWO: 2 }
+        },
+        Service: {
+            methods: {}
+        }
+    },
+    options: {
+        custom: true
+    }
+};
+
+tape.test("reflected types", function(test) {
+
+    var type = protobuf.Type.fromJSON("Test", def);
+    test.same(type.toJSON(), def, "should construct from and convert back to JSON");
+    type = protobuf.Type.fromJSON("Test", def2);
+    test.same(JSON.parse(JSON.stringify(type)), JSON.parse(JSON.stringify(def2)), "should construct from and convert back to JSON (complex parsed)");
+
+    function MyMessageAuto() {}
+    type.ctor = MyMessageAuto;
+    test.ok(MyMessageAuto.prototype instanceof protobuf.Message, "should properly register a constructor through assignment");
+    test.ok(typeof MyMessageAuto.encode === "function", "should populate static methods on assigned constructors");
+
+    function MyMessageManual() {}
+    MyMessageManual.prototype = Object.create(protobuf.Message.prototype);
+    type.ctor = MyMessageManual;
+    test.ok(MyMessageManual.prototype instanceof protobuf.Message, "should properly register a constructor through assignment if already extending message");
+    test.ok(typeof MyMessageManual.encode === "function", "should populate static methods on assigned constructors");
+
+    type = protobuf.Type.fromJSON("My", {
+        fields: {
+            a: {
+                type: "string",
+                id: 1
+            }
+        },
+        reserved: [[900, 999], "b"],
+        nested: {
+            Type: { fields: {} },
+            Enum: { values: {} },
+            Service: { methods: {} },
+            extensionField: { type: "string", id: 1000, extend: "Message" },
+            Other: { nested: {} }
+        }
+    });
+    test.same(type.toJSON(), {
+        fields: {
+            a: { id: 1, type: "string" }
+        },
+        reserved: [[900, 999], "b"],
+        nested: {
+            Type: { fields: {} },
+            Enum: { values: {} },
+            Service: { methods: {} },
+            extensionField: { extend: "Message", id: 1000, type: "string" },
+            Other: { }
+        }
+    }, "should create from Field, Type, Enum, Service, extension Field and Namespace JSON");
+
+    test.throws(function() {
+        type.add(new protobuf.Enum("Enum"));
+    }, Error, "should throw when trying to add duplicate names");
+
+    test.throws(function() {
+        type.add(new protobuf.Field("c", 1, "uint32"));
+    }, Error, "should throw when trying to add duplicate ids");
+
+    test.throws(function() {
+        type.add(new protobuf.Field("c", 900, "uint32"));
+    }, Error, "should throw when trying to add reserved ids");
+
+    test.throws(function() {
+        type.add(new protobuf.Field("b", 2, "uint32"));
+    }, Error, "should throw when trying to add reserved names");
+
+
+    test.end();
+});
diff --git a/tests/api_util.js b/tests/api_util.js
new file mode 100644
index 0000000..7b6f50f
--- /dev/null
+++ b/tests/api_util.js
@@ -0,0 +1,103 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var util = protobuf.util;
+
+tape.test("util", function(test) {
+
+    test.test(test.name + " - merge", function(test) {
+        var o = {};
+        util.merge(o, {});
+        test.same(o, {}, "should do nothing if both objects are empty");
+        util.merge(o, { a: 1 });
+        test.same(o, { a: 1 }, "should merge non-existing keys");
+        util.merge(o, { a: 2 });
+        test.same(o, { a: 2 }, "should merge existing keys");
+        util.merge(o, { a: 3 }, true);
+        test.same(o, { a: 2 }, "should not merge existing keys");
+        test.end();
+    });
+
+    test.test(test.name + " - lcFirst", function(test) {
+        test.equal(util.lcFirst("ABC"), "aBC", "should convert the first character to lower case");
+        test.end();
+    });
+
+    test.test(test.name + " - ucFirst", function(test) {
+        test.equal(util.ucFirst("abc"), "Abc", "should convert the first character to upper case");
+        test.end();
+    });
+
+    test.test(test.name + " - isSet", function(test) {
+        // note that encoders don't check for default values either
+        var neverPresent = [
+            [],
+            {},
+            undefined,
+            null
+        ];
+        neverPresent.forEach(function(value) {
+            var proto = {};
+            var instance = Object.create(proto);
+            proto.p = value;
+            instance.i = value;
+            test.notOk(util.isSet(proto, "p"), "should return that " + JSON.stringify(value) + " on the prototype is not present");
+            test.notOk(util.isSet(instance, "i"), "should return that " + JSON.stringify(value) + " on the instance is not present");
+        });
+        var cases = {
+            "arrays": [ [], [0] ],
+            "objects": [ {}, {a:1} ],
+            "strings": [ undefined, "" ],
+            "numbers": [ undefined, 0 ],
+            "booleans": [ undefined, false ]
+        };
+        Object.keys(cases).forEach(function(name) {
+            var empty = cases[name][0],
+                value = cases[name][1];
+            var proto = {};
+            var instance = Object.create(proto);
+            proto.pe = instance.ie = empty;
+            proto.p = instance.i = value;
+            if (empty !== undefined) { // not present anyway
+                test.notOk(util.isSet(instance, "pe"), "should return that empty " + name + " on the prototype are not present");
+                test.notOk(util.isSet(instance, "ie"), "should return that empty " + name + " on the instance are not present");
+            }
+            test.notOk(util.isSet(instance, "p"), "should return that " + name + " on the prototype are not present");
+            test.ok(util.isSet(instance, "i"), "should return that " + name + " on the instance ARE present");
+        });
+
+         test.end();
+    });
+
+    test.test(test.name + " - setProperty", function(test) {
+        var o = {};
+
+        test.throws(function() {
+            util.setProperty(5, 'prop1', 5);
+        }, TypeError, "dst must be an object");
+
+        test.throws(function () {
+            util.setProperty(o, '', 5);
+        }, TypeError, "path must be specified");
+
+        util.setProperty(o, 'prop1', 5);
+        test.same(o, {prop1: 5}, "should set single property value");
+
+        util.setProperty(o, 'prop1', 6);
+        test.same(o, {prop1: [5, 6]}, "should convert to array if same property is set");
+
+        util.setProperty(o, 'prop.subprop', { subsub: 5});
+        test.same(o, {prop1: [5, 6], prop: {subprop: {subsub: 5}}}, "should handle nested properties properly");
+
+        util.setProperty(o, 'prop.subprop.subsub', 6);
+        test.same(o, {prop1: [5, 6], prop: {subprop: {subsub: [5, 6]}}}, "should convert to array nested property");
+
+        util.setProperty(o, 'prop.subprop', { subsub2: 7});
+        test.same(o, {prop1: [5, 6], prop: {subprop: [{subsub: [5,6]}, {subsub2: 7}]}}, "should convert nested properties to array");
+
+        test.end();
+    });
+
+    test.end();
+});
\ No newline at end of file
diff --git a/tests/api_writer-reader.js b/tests/api_writer-reader.js
new file mode 100644
index 0000000..5914914
--- /dev/null
+++ b/tests/api_writer-reader.js
@@ -0,0 +1,181 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var Writer = protobuf.Writer,
+    Reader = protobuf.Reader;
+
+tape.test("writer & reader", function(test) {
+
+    test.throws(function() {
+        Reader.create(1);
+    }, "should throw when creating a Reader from something else than a buffer");
+
+    test.doesNotThrow(function() {
+        Reader.create([]);
+    }, "should not throw when creating a Reader from an array (comp)");
+
+    // uint32, int32, sint32
+
+    var values = [
+        [ 0, [ 0 ] ],
+        [ 127, [ 127 ] ],
+        [ 128, [ 128, 1] ],
+        [ 16383, [ 255, 127 ] ],
+        [ 16384, [ 128, 128, 1] ],
+        [ 2097151, [ 255, 255, 127 ] ],
+        [ 2097152, [ 128, 128, 128, 1 ] ],
+        [ 268435455, [ 255, 255, 255, 127 ] ],
+        [ 268435456, [ 128, 128, 128, 128, 1 ] ],
+        [ 2147483647, [ 255, 255, 255, 255, 7 ] ]
+    ];
+    values.forEach(function(val) {
+         test.ok(expect("uint32", val[0] >>> 0, val[1]), "should write " + val[0] + " as an unsigned varint of length " + val[1].length + " and read it back equally");
+         test.ok(expect("int32", val[0] | 0, val[1]), "should write " + val[0] + " as a signed varint of length " + val[1].length + " and read it back equally");
+         var zzBaseVal = val[0] >>> 1 ^ -(val[0] & 1) | 0;
+         test.ok(expect("sint32", zzBaseVal, val[1]), "should write " + zzBaseVal + " as a signed zig-zag encoded varint of length " + val[1].length + " and read it back equally");
+    });
+
+    test.ok(expect("uint32", -1 >>> 0, [ 255, 255, 255, 255, 15 ]), "should write -1 as an unsigned varint of length 5");
+    test.ok(expect("int32", -1, [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 1 ]), "should write -1 as a signed varint of length 10");
+    test.ok(expect("sint32", -1, [ 1 ]), "should write -1 as a signed zig-zag encoded varint of length 1");
+
+    // fixed32, sfixed32
+
+    if (typeof Uint32Array !== "undefined")
+        values.forEach(function(val) {
+            // the same for all sorts of writers anyway
+
+            var buffer = Writer.create().fixed32(val[0]).finish();
+            var comp = new Uint8Array(new Uint32Array([ val[0] ]).buffer);
+            test.same(Array.prototype.slice.call(buffer), Array.prototype.slice.call(comp), "should write " + val[0] + " as fixed 32 bits");
+            test.equal(Reader.create(buffer).fixed32(), val[0], "should read back "+ val[0] + " equally");
+
+            var signedVal = val[0] | 0;
+            buffer = Writer.create().sfixed32(signedVal).finish();
+            comp = new Uint8Array(new Uint32Array([ val[0] ]).buffer);
+            test.same(Array.prototype.slice.call(buffer), Array.prototype.slice.call(comp), "should write " + signedVal + " as fixed 32 bits (signed)");
+            test.equal(Reader.create(buffer).sfixed32(), signedVal, "should read back "+ signedVal + " equally");
+        });
+
+    test.ok(expect("fixed32", 4294967295, [ 255, 255, 255, 255 ]), "should write 4294967295 as fixed 32 bits");
+    test.ok(expect("fixed32", 4294967294, [ 254, 255, 255, 255 ]), "should write 4294967294 as fixed 32 bits");
+    test.ok(expect("sfixed32", -1, [ 255, 255, 255, 255 ]), "should write -1 as fixed 32 bits (signed)");
+    test.ok(expect("sfixed32", -2, [ 254, 255, 255, 255 ]), "should write -2 as fixed 32 bits (signed)");
+
+    // uint64, int64, sint64
+
+    protobuf.util.merge(values, [
+        [ 549755813887, [ 255, 255, 255, 255, 255, 15 ] ],
+        [ 140737488355327, [ 255, 255, 255, 255, 255, 255, 31 ] ]
+    ]);
+
+    test.ok(protobuf.util.Long, "should use long.js");
+    values.forEach(function(val) {
+        var longVal = protobuf.util.Long.fromNumber(val[0], false);
+        
+        test.ok(expect("uint64", longVal, val[1]), "should write " + longVal + " as an unsigned varint of length " + val[1].length + " and read it back equally");
+        test.ok(expect("int64", longVal, val[1]), "should write " + longVal + " as a signed varint of length " + val[1].length + " and read it back equally");
+        var zzBaseVal = longVal.shru(1).xor(longVal.and(1).negate());
+        test.ok(expect("sint64", zzBaseVal, val[1]), "should write " + zzBaseVal + " as a signed zig-zag encoded varint of length " + val[1].length + " and read it back equally");
+    });
+
+    // fixed64, sfixed64 -> see also see comp_fixed/sfixed64 (grpc)
+
+    // TODO
+
+    // float, double -> see comp_float
+
+    // bool
+
+    test.ok(expect("bool", true, [1]), "should write true as a varint of length 1 and read it back equally");
+    test.ok(expect("bool", false, [0]), "should write false as a varint of length 1 and read it back equally");
+
+    // string, see also lib_utf8
+
+    test.ok(expect("string", "123", [3,49,50,51]), "should write \"123\" as a string prefixed with its length as a varint and read it back equally");
+    test.ok(expect("string", "", [0]), "should write \"\" as a string prefixed with its length as a varint and read it back equally");
+
+    // bytes
+
+    test.ok(expect("bytes", [1,2,3], [3,1,2,3]), "should write [1,2,3] as bytes prefixed with its length as a varint and read it back equally");
+    test.ok(expect("bytes", [], [0]), "should write [] as bytes prefixed with its length as a varint and read it back equally");
+    test.ok(expect("bytes", "MTIz", [3,49,50,51]), "should write MTIz as bytes prefixed with its length as a varint and read it back equally");
+
+    // skipType
+
+    test.test(test.name + " - should allow to skip", function(test) {
+        var reader = Reader.create(Writer.create()
+            .uint32(1)
+            .double(0.1)
+            .string("123")
+            .uint32(1 << 3 | 1).double(0.1).uint32(4)
+            .uint32(4)
+            .float(0.125)
+            .finish()
+        );
+        reader.skipType(0);
+        test.equal(reader.pos, 1, "varints");
+        reader.skipType(1);
+        test.equal(reader.pos, 9, "fixed 64 bits");
+        reader.skipType(2);
+        test.equal(reader.pos, 13, "length delimited values");
+        reader.skipType(3);
+        test.equal(reader.pos, 23, "legacy groups");
+        reader.skipType(3);
+        test.equal(reader.pos, 24, "empty legacy groups");
+        reader.skipType(5);
+        test.equal(reader.pos, 28, "fixed 32 bits");
+        test.end();
+    });
+
+    test.end();
+});
+
+function expect(type, value, expected, WriterToTest) {
+    if (!WriterToTest)
+        WriterToTest = Writer.create().constructor;
+    var writer = new WriterToTest();
+    var actual = writer[type](value).finish();
+    if (actual.length !== expected.length) {
+        console.error("actual", Array.prototype.slice.call(actual), "!= expected", expected);
+        return false;
+    }
+    for (var i = 0; i < expected.length; ++i)
+        if (actual[i] !== expected[i]) {
+            console.error("actual", Array.prototype.slice.call(actual), "!= expected", expected);
+            return false;
+        }
+    var longActual = protobuf.util.newBuffer(20);
+    for (var l = 0; l < actual.length; ++l)
+        longActual[l] = actual[l];
+    [ actual, longActual ] // also test readLongVarint fast route
+    .forEach(function(actual) {
+        var reader = Reader.create(actual);
+        var actualValue = reader[type]();
+        if (typeof actualValue === "object") { // buffer
+            var buf;
+            if (typeof value === "string") { // initial value is a base64 encoded string
+                buf = protobuf.util.newBuffer(protobuf.util.base64.length(value));
+                protobuf.util.base64.decode(value, buf, 0);
+            } else
+                buf = value;
+            if (buf.length !== actualValue.length)
+                return false;
+            for (var j = 0; j < buf.length; ++j)
+                if (actualValue[j] !== buf[j])
+                    return false;
+        } else if (actualValue !== value) {
+            console.error("actual value", actualValue, "!= expected", value);
+            return false;
+        }
+    });
+    // also test browser writer if running under node
+    if (WriterToTest !== protobuf.Writer) {
+        if (!expect(type, value, expected, Writer)) {
+            console.error("in browser writer");
+            return false;
+        }
+    }
+    return true;
+}
\ No newline at end of file
diff --git a/tests/cli.js b/tests/cli.js
new file mode 100644
index 0000000..11f32a0
--- /dev/null
+++ b/tests/cli.js
@@ -0,0 +1,216 @@
+// A minimal test for pbjs tool targets.
+
+var tape = require("tape");
+var path = require("path");
+var Module = require("module");
+var protobuf = require("..");
+var fs = require("fs");
+
+function cliTest(test, testFunc) {
+    // pbjs does not seem to work with Node v4, so skip this test if we're running on it
+    if (process.versions.node.match(/^4\./)) {
+        test.end();
+        return;
+    }
+
+    // Alter the require cache to make the cli/targets/static work since it requires "protobufjs"
+    // and we don't want to mess with "npm link"
+    var savedResolveFilename = Module._resolveFilename;
+    Module._resolveFilename = function(request, parent) { 
+      if (request.startsWith("protobufjs")) {
+        return request;
+      }
+      return savedResolveFilename(request, parent);
+    };
+    require.cache.protobufjs = require.cache[path.resolve("index.js")];
+
+    try {
+        testFunc();
+    } finally {
+        // Rollback all the require() related mess we made
+        delete require.cache.protobufjs;
+        Module._resolveFilename = savedResolveFilename;
+    }
+}
+
+tape.test("pbjs generates static code", function(test) {
+    cliTest(test, function() {
+        var root = protobuf.loadSync("tests/data/cli/test.proto");
+        root.resolveAll();
+
+        var staticTarget = require("../cli/targets/static");
+
+        staticTarget(root, {
+            create: true,
+            decode: true,
+            encode: true,
+            convert: true,
+            typeurl: true,
+        }, function(err, jsCode) {
+            test.error(err, 'static code generation worked');
+
+            // jsCode is the generated code; we'll eval it
+            // (since this is what we normally do with the code, right?)
+            // This is a test code. Do not use this in production.
+            var $protobuf = protobuf;
+            eval(jsCode);
+
+            var OneofContainer = protobuf.roots.default.OneofContainer;
+            var Message = protobuf.roots.default.Message;
+            test.ok(OneofContainer, "type is loaded");
+            test.ok(Message, "type is loaded");
+
+            // Check that fromObject and toObject work for plain object
+            var obj = {
+                messageInOneof: {
+                    value: 42,
+                },
+                regularField: "abc",
+                enumField: 0,
+            };
+            var obj1 = OneofContainer.toObject(OneofContainer.fromObject(obj));
+            test.deepEqual(obj, obj1, "fromObject and toObject work for plain object");
+
+            // Check that dynamic fromObject and toObject work for static instance
+            var root = protobuf.loadSync("tests/data/cli/test.proto");
+            var OneofContainerDynamic = root.lookup("OneofContainer");
+            var instance = new OneofContainer();
+            instance.messageInOneof = new Message();
+            instance.messageInOneof.value = 42;
+            instance.regularField = "abc";
+            instance.enumField = 0;
+            var instance1 = OneofContainerDynamic.toObject(OneofContainerDynamic.fromObject(instance));
+            test.deepEqual(instance, instance1, "fromObject and toObject work for instance of the static type");
+
+            // Check that getTypeUrl works
+            var defaultTypeUrl = Message.getTypeUrl();
+            var customTypeUrl = Message.getTypeUrl("example.com");
+            test.equal(defaultTypeUrl, "type.googleapis.com/Message", "getTypeUrl returns expected url");
+            test.equal(customTypeUrl, "example.com/Message", "getTypeUrl returns custom url");
+
+            test.end();
+        });
+    });
+});
+
+tape.test("without null-defaults, absent optional fields have zero values", function(test) {
+    cliTest(test, function() {
+        var root = protobuf.loadSync("tests/data/cli/null-defaults.proto");
+        root.resolveAll();
+
+        var staticTarget = require("../cli/targets/static");
+
+        staticTarget(root, {
+            create: true,
+            decode: true,
+            encode: true,
+            convert: true,
+        }, function(err, jsCode) {
+            test.error(err, 'static code generation worked');
+
+            // jsCode is the generated code; we'll eval it
+            // (since this is what we normally does with the code, right?)
+            // This is a test code. Do not use this in production.
+            var $protobuf = protobuf;
+            eval(jsCode);
+
+            var OptionalFields = protobuf.roots.default.OptionalFields;
+            test.ok(OptionalFields, "type is loaded");
+
+            // Check default values
+            var msg = OptionalFields.fromObject({});
+            test.equal(msg.a, null, "default submessage is null");
+            test.equal(msg.b, "", "default string is empty");
+            test.equal(msg.c, 0, "default integer is 0");
+
+            test.end();
+        });
+    });
+});
+
+tape.test("with null-defaults, absent optional fields have null values", function(test) {
+    cliTest(test, function() {
+        var root = protobuf.loadSync("tests/data/cli/null-defaults.proto");
+        root.resolveAll();
+
+        var staticTarget = require("../cli/targets/static");
+
+        staticTarget(root, {
+            create: true,
+            decode: true,
+            encode: true,
+            convert: true,
+            "null-defaults": true,
+        }, function(err, jsCode) {
+            test.error(err, 'static code generation worked');
+
+            // jsCode is the generated code; we'll eval it
+            // (since this is what we normally does with the code, right?)
+            // This is a test code. Do not use this in production.
+            var $protobuf = protobuf;
+            eval(jsCode);
+
+            var OptionalFields = protobuf.roots.default.OptionalFields;
+            test.ok(OptionalFields, "type is loaded");
+
+            // Check default values
+            var msg = OptionalFields.fromObject({});
+            test.equal(msg.a, null, "default submessage is null");
+            test.equal(msg.b, null, "default string is null");
+            test.equal(msg.c, null, "default integer is null");
+
+            test.end();
+        });
+    });
+});
+
+
+tape.test("pbjs generates static code with message filter", function (test) {
+    cliTest(test, function () {
+        var root = protobuf.loadSync("tests/data/cli/test-filter.proto");
+        root.resolveAll();
+
+        var staticTarget = require("../cli/targets/static");
+        var util = require("../cli/util");
+
+        const needMessageConfig = JSON.parse(fs.readFileSync("tests/data/cli/filter.json"));
+
+        util.filterMessage(root, needMessageConfig);
+
+        staticTarget(root, {
+            create: true,
+            decode: true,
+            encode: true,
+            convert: true,
+            "null-defaults": true,
+        }, function (err, jsCode) {
+            test.error(err, 'static code generation worked');
+
+            // jsCode is the generated code; we'll eval it
+            // (since this is what we normally does with the code, right?)
+            // This is a test code. Do not use this in production.
+            var $protobuf = protobuf;
+            eval(jsCode);
+
+            console.log(protobuf.roots);
+
+            var NeedMessage1 = protobuf.roots.default.filtertest.NeedMessage1;
+            var NeedMessage2 = protobuf.roots.default.filtertest.NeedMessage2;
+            var DependentMessage1 = protobuf.roots.default.filtertest.DependentMessage1;
+            var DependentMessageFromImport = protobuf.roots.default.DependentMessageFromImport;
+
+            var NotNeedMessageInRootFile = protobuf.roots.default.filtertest.NotNeedMessageInRootFile;
+            var NotNeedMessageInImportFile = protobuf.roots.default.NotNeedMessageInImportFile;
+            
+            test.ok(NeedMessage1, "NeedMessage1 is loaded");
+            test.ok(NeedMessage2, "NeedMessage2 is loaded");
+            test.ok(DependentMessage1, "DependentMessage1 is loaded");
+            test.ok(DependentMessageFromImport, "DependentMessageFromImport is loaded");
+
+            test.notOk(NotNeedMessageInImportFile, "NotNeedMessageInImportFile is not loaded");
+            test.notOk(NotNeedMessageInRootFile, "NotNeedMessageInRootFile is not loaded");
+
+            test.end();
+        });
+    });
+});
diff --git a/tests/comment_serialization.js b/tests/comment_serialization.js
new file mode 100644
index 0000000..f696d24
--- /dev/null
+++ b/tests/comment_serialization.js
@@ -0,0 +1,66 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("by default, drop comments through de/serialization", function(test) {
+    test.plan(16);
+    protobuf.load("tests/data/comment_serialization.proto", function(err, root) {
+        if (err) {
+            throw test.fail(err.message);
+        }
+
+        var copy = protobuf.Root.fromJSON(root.toJSON());
+        test.ok(root.lookup("TestMessage").comment);
+        test.notOk(copy.lookup("TestMessage").comment);
+        test.ok(root.lookup("TestMessage.testField").comment);
+        test.notOk(copy.lookup("TestMessage.testField").comment);
+        test.ok(root.lookup("TestMessage.testMap").comment);
+        test.notOk(copy.lookup("TestMessage.testMap").comment);
+        test.ok(root.lookup("TestMessage.testOneof").comment);
+        test.notOk(copy.lookup("TestMessage.testOneof").comment);
+
+        var rootService = root.lookupService("TestService");
+        var copyService = copy.lookupService("TestService");
+        test.ok(rootService.comment);
+        test.notOk(copyService.comment);
+        test.ok(rootService.methods["testMethod"].comment);
+        test.notOk(copyService.methods["testMethod"].comment);
+
+        var rootEnum = root.lookup("TestEnum");
+        var copyEnum = copy.lookup("TestEnum");
+        test.ok(rootEnum.comment);
+        test.notOk(copyEnum.comment);
+        test.ok(rootEnum.comments.VALUE);
+        test.notOk(copyEnum.comments.VALUE);
+
+        test.end();
+    });
+});
+
+tape.test("preserve comments through de/serialization if option set", function(test) {
+    test.plan(8);
+    protobuf.load("tests/data/comment_serialization.proto", function(err, root) {
+        if (err) {
+            throw test.fail(err.message);
+        }
+
+        var toJSONOptions = {keepComments: true};
+        var copy = protobuf.Root.fromJSON(root.toJSON(toJSONOptions));
+        test.equal(root.lookup("TestMessage").comment, copy.lookup("TestMessage").comment);
+        test.equal(root.lookup("TestMessage.testField").comment, copy.lookup("TestMessage.testField").comment);
+        test.equal(root.lookup("TestMessage.testMap").comment, copy.lookup("TestMessage.testMap").comment);
+        test.equal(root.lookup("TestMessage.testOneof").comment, copy.lookup("TestMessage.testOneof").comment);
+
+        var rootService = root.lookupService("TestService");
+        var copyService = copy.lookupService("TestService");
+        test.equal(rootService.comment, copyService.comment);
+        test.equal(rootService.methods["testMethod"].comment, copyService.methods["testMethod"].comment);
+
+        var rootEnum = root.lookup("TestEnum");
+        var copyEnum = copy.lookup("TestEnum");
+        test.equal(rootEnum.comment, copyEnum.comment);
+        test.equal(rootEnum.comments.VALUE, copyEnum.comments.VALUE);
+
+        test.end();
+    });
+});
diff --git a/tests/comp_ambiguous-names.js b/tests/comp_ambiguous-names.js
new file mode 100644
index 0000000..3a86e1b
--- /dev/null
+++ b/tests/comp_ambiguous-names.js
@@ -0,0 +1,17 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var proto = "syntax = \"proto3\";\
+message A {\
+  string whatever = 1;\
+}\
+message B {\
+  A A = 1;\
+}";
+
+tape.test("ambiguous names", function(test) {
+    protobuf.parse(proto);
+    test.pass("should parse without errors");
+    test.end();
+});
diff --git a/tests/comp_bytes.js b/tests/comp_bytes.js
new file mode 100644
index 0000000..39c58fd
--- /dev/null
+++ b/tests/comp_bytes.js
@@ -0,0 +1,89 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var oldBufferImpl = Buffer.alloc === undefined;
+
+// extends Buffer
+(CustomBuffer.prototype = Object.create(Buffer.prototype)).constructor = CustomBuffer;
+
+function CustomBuffer(arg, encodingOrOffset, length) {
+    Buffer.call(this, arg, encodingOrOffset, length);
+    CustomBuffer.toCustom(this);
+}
+
+CustomBuffer.isBuffer = Buffer.isBuffer.bind(Buffer);
+
+CustomBuffer.toCustom = function (b) {
+    b._isCustom = true;
+    return b;
+}
+
+CustomBuffer.isCustom = function (b) {
+    return !!b._isCustom;
+}
+
+CustomBuffer.from = function (valueOf, encodingOrOffset, length) {
+    return CustomBuffer.toCustom(oldBufferImpl
+        ?  new Buffer(valueOf, encodingOrOffset, length)
+        : Buffer.from(valueOf, encodingOrOffset, length)
+    );
+}
+
+CustomBuffer.alloc = function (size, fill, encoding) {
+    return CustomBuffer.toCustom(oldBufferImpl
+        ?  new Buffer(size, fill, encoding)
+        : Buffer.alloc(size, fill, encoding)
+    );
+}
+
+CustomBuffer.allocUnsafe = function (size) {
+    return CustomBuffer.toCustom(oldBufferImpl
+        ?  new Buffer(size)
+        : Buffer.allocUnsafe(size)
+    );
+}
+
+CustomBuffer.prototype.slice = function (start, end) {
+    return CustomBuffer.toCustom(this.slice(start, end));
+}
+
+tape.test("configure a custom encoder/decoder for bytes", function(test) {
+    var oldBuffer = protobuf.util.Buffer;
+
+    protobuf.util.Buffer = CustomBuffer;
+    protobuf.configure();
+
+    var root = protobuf.Root.fromJSON({
+        nested: {
+            test: {
+                nested: {
+                    Test: {
+                        fields: {
+                            data: {
+                                type: "bytes",
+                                id: 1
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    });
+
+    var Test = root.lookup("test.Test");
+
+    var buffer = Test.encode({
+        data: CustomBuffer.from('some-data')
+    }).finish();
+    test.ok(CustomBuffer.isCustom(buffer), "should encode the message with a custom buffer");
+
+    var decoded = Test.decode(buffer);
+    test.ok(CustomBuffer.isCustom(decoded.data), "should decode `data` into a custom buffer");
+
+    protobuf.util.Buffer = oldBuffer;
+    protobuf.configure();
+
+    test.end();
+
+});
diff --git a/tests/comp_empty-encode.js b/tests/comp_empty-encode.js
new file mode 100644
index 0000000..5a8fc9f
--- /dev/null
+++ b/tests/comp_empty-encode.js
@@ -0,0 +1,20 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("empty messages", function(test) {
+    var root = new protobuf.Root().addJSON({
+        "Test": {
+            fields: {}
+        }
+    });
+
+    var Test = root.lookup("Test");
+
+    var buf = Test.encodeDelimited({}).finish();
+
+    test.equal(buf.length, 1, "should encodeDelimited to a buffer of length 1");
+    test.equal(buf[0], 0, "should encodeDelimited a length of 0");
+    
+    test.end();
+});
diff --git a/tests/comp_empty-inner-fields.js b/tests/comp_empty-inner-fields.js
new file mode 100644
index 0000000..7150e95
--- /dev/null
+++ b/tests/comp_empty-inner-fields.js
@@ -0,0 +1,36 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("empty inner fields", function(test) {
+    var root = protobuf.Root.fromJSON({
+        nested: {
+            Inner: {
+                fields: {
+                }
+            },
+            Outer: {
+                oneofs: {
+                    child: {
+                        oneof: ["inner"]
+                    }
+                },
+                fields: {
+                    inner: {
+                        id: 1,
+                        type: "Inner"
+                    }
+                }
+            }
+        }
+    });
+    var Outer = root.lookup("Outer");
+    var msg = Outer.fromObject({
+        inner: {}
+    });
+    var buf = Outer.encode(msg).finish();
+    test.equal(buf.length, 2, "should always be present on the wire");
+    test.equal(buf[0], 1 << 3 | 2, "should write id 1, wireType 2");
+    test.equal(buf[1], 0, "should write a length of 0");
+    test.end();
+});
\ No newline at end of file
diff --git a/tests/comp_extend.js b/tests/comp_extend.js
new file mode 100644
index 0000000..4d9d195
--- /dev/null
+++ b/tests/comp_extend.js
@@ -0,0 +1,27 @@
+var tape = require("tape");
+
+var protobuf  = require("..");
+
+var proto = "syntax = \"proto3\";\
+message A {\
+    message B {\
+        message One {\
+            extensions 1000 to max;\
+            reserved 900 to 999, 899, \"a\", 'b';\
+        }\
+    }\
+    message C {\
+        message Two {\
+            extend B.One {\
+                C.Two two = 1000;\
+            }\
+        }\
+    }\
+}";
+
+tape.test("extensions", function(test) {
+    var root = protobuf.parse(proto).root;
+    root.resolveAll();
+    test.pass("should parse and resolve without errors");
+    test.end();
+});
diff --git a/tests/comp_fixed64-grpc.js b/tests/comp_fixed64-grpc.js
new file mode 100644
index 0000000..e2e9d62
--- /dev/null
+++ b/tests/comp_fixed64-grpc.js
@@ -0,0 +1,39 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("fixed64 (grpc)", function(test) {
+
+    var root = protobuf.Root.fromJSON({
+        nested: {
+            test: {
+                nested: {
+                    Test: {
+                        fields: {
+                            int_64: {
+                                type: 'fixed64',
+                                id: 1
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    });
+
+    var Test = root.lookup("test.Test");
+
+    var buffer = Test.encode({
+        int_64: '314159265358979'
+    }).finish();
+
+    test.equal(buffer.length, 9, "should encode a total of 9 bytes");
+    test.equal(buffer[0], 9, "should encode id 1, wireType 1");
+
+    var decoded = Test.decode(buffer);
+    // decoded.int_64 is a Long here, so this implicitly calls Long#toString:
+    test.ok(decoded.int_64 == '314159265358979', "should decode back the original value");
+
+    test.end();
+
+});
diff --git a/tests/comp_google_protobuf_any.js b/tests/comp_google_protobuf_any.js
new file mode 100644
index 0000000..342dcfb
--- /dev/null
+++ b/tests/comp_google_protobuf_any.js
@@ -0,0 +1,66 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var root = protobuf.Root.fromJSON({
+    nested: {
+        Foo: {
+            fields: {
+                foo: {
+                    id: 1,
+                    type: "google.protobuf.Any"
+                }
+            }
+        },
+        Bar: {
+            fields: {
+                bar: {
+                    id: 1,
+                    type: "string"
+                }
+            }
+        }
+    }
+}).addJSON(protobuf.common["google/protobuf/any.proto"].nested).resolveAll();
+
+var Any = root.lookupType("protobuf.Any"),
+    Foo = root.lookupType(".Foo"),
+    Bar = root.lookupType(".Bar");
+
+tape.test("google.protobuf.Any", function(test) {
+
+    var foo = Foo.fromObject({
+        foo: {
+            type_url: "Bar",
+            value: [1 << 3 | 2, 1, 97] // value = "a"
+        }
+    });
+    test.ok(foo.foo instanceof Any.ctor, "should keep explicit Any in fromObject");
+    test.same(foo.foo, { type_url: "Bar", value: [10, 1, 97] }, "should keep explicit Any in fromObject properly");
+
+    var obj = Foo.toObject(foo);
+    test.same(obj.foo, { type_url: "Bar", value: [10, 1, 97] }, "should keep explicit Any in toObject properly");
+
+    obj = Foo.toObject(foo, { json: true });
+    test.same(obj.foo, { "@type": "type.googleapis.com/Bar", bar: "a" }, "should decode explicitly Any in toObject if requested");
+
+    foo = Foo.fromObject({
+        foo: {
+            "@type": ".Bar",
+            bar: "a"
+        }
+    });
+    test.ok(foo.foo instanceof Any.ctor, "should convert to Any in fromObject");
+    test.same(foo.foo, { type_url: "/Bar", value: protobuf.util.newBuffer([10, 1, 97]) }, "should have correct Any object when converted with fromObject");
+
+    var baz = Foo.fromObject({
+        foo: {
+            type_url: "type.someurl.com/Bar",
+            value: [1 << 3 | 2, 1, 97] // value = "a"
+        }
+    });
+    obj = Foo.toObject(baz, { json: true });
+    test.same(obj.foo, { "@type": "type.someurl.com/Bar", bar: "a" }, "should keep prefix in type url");
+
+    test.end();
+});
diff --git a/tests/comp_groups.js b/tests/comp_groups.js
new file mode 100644
index 0000000..f771b46
--- /dev/null
+++ b/tests/comp_groups.js
@@ -0,0 +1,79 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var protoRequired = "message Test {\
+    required group MyGroup = 1 {\
+        option foo = \"bar\";\
+        required uint32 a = 2;\
+    };\
+}";
+
+var protoRepeated = "message Test {\
+    repeated group MyGroup = 1 {\
+        option foo = \"bar\";\
+        required uint32 a = 2;\
+    };\
+}";
+
+tape.test("legacy groups", function(test) {
+    var root = protobuf.parse(protoRequired).root;
+
+    var Test = root.resolveAll().lookup("Test");
+    var MyGroupType = Test.get("MyGroup");
+    var MyGroupField = Test.get("myGroup");
+    var msg = {
+        myGroup: {
+            a: 111
+        }
+    };
+    
+    test.ok(MyGroupType instanceof protobuf.Type && MyGroupField instanceof protobuf.Field, "should parse to a type and a field");
+    test.equal(MyGroupType.group, true, "should have the group flag set on the type");
+    test.equal(MyGroupField.resolvedType, MyGroupType, "should reference the type from the field");
+    var json = MyGroupType.toJSON();
+    test.equal(json.group, true, "should export group=true to JSON");
+    var MyGroupType2 = protobuf.Type.fromJSON("MyGroup", json);
+    test.equal(MyGroupType2.group, true, "should import group=true from JSON");
+    // NOTE: fromJSON alone does not add the sister-field.
+    // The parser does this explicitly and the field is part of the exported JSON itself.
+
+    test.test(test.name + " - should encode required", (function(Test, msg) { return function(test) {
+        var buf = Test.encode(msg).finish();
+        test.equal(buf.length, 4, "a total of 4 bytes");
+        test.equal(buf[0], 1 << 3 | 3, "id 1, wireType 3");
+        test.equal(buf[1], 2 << 3 | 0, "id 2, wireType 0");
+        test.equal(buf[2], 111, "111");
+        test.equal(buf[3], 1 << 3 | 4, "id 1, wireType 4");
+        test.same(Test.decode(buf), msg, "and decode back the original message");
+        test.end();
+    };})(Test, msg));
+
+    // Same but repeated
+    root = protobuf.parse(protoRepeated).root;
+    Test = root.resolveAll().lookup("Test");
+    msg = {
+        myGroup: [{
+            a: 111
+        },{
+            a: 112
+        }]
+    };
+
+    test.test(test.name + " - should encode repeated", (function(Test, msg) { return function(test) {
+        var buf = Test.encode(msg).finish();
+        test.equal(buf.length, 8, "a total of 8 bytes");
+        test.equal(buf[0], 1 << 3 | 3, "id 1, wireType 3");
+        test.equal(buf[1], 2 << 3 | 0, "id 2, wireType 0");
+        test.equal(buf[2], 111, "111");
+        test.equal(buf[3], 1 << 3 | 4, "id 1, wireType 4");
+        test.equal(buf[4], 1 << 3 | 3, "id 1, wireType 3");
+        test.equal(buf[5], 2 << 3 | 0, "id 2, wireType 0");
+        test.equal(buf[6], 112, "112");
+        test.equal(buf[7], 1 << 3 | 4, "id 1, wireType 4");
+        test.same(Test.decode(buf), msg, "and decode back the original message");
+        test.end();
+    };})(Test, msg));
+
+    test.end();
+});
diff --git a/tests/comp_import_extend.js b/tests/comp_import_extend.js
new file mode 100644
index 0000000..f694503
--- /dev/null
+++ b/tests/comp_import_extend.js
@@ -0,0 +1,18 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var path = require("path");
+var tape = require("tape");
+var protobuf = require("../index");
+// to extend Root
+require("../ext/descriptor");
+tape.test("extensions", function (test) {
+    // load document with extended field imported multiple times
+    var root = protobuf.loadSync(path.resolve(__dirname, "data/test.proto"));
+    root.resolveAll();
+    // convert to Descriptor Set
+    var decodedDescriptorSet = root.toDescriptor("proto3");
+    // load back from descriptor set
+    var root2 = protobuf.Root.fromDescriptor(decodedDescriptorSet);
+    test.pass("should parse and resolve without errors");
+    test.end();
+});
diff --git a/tests/comp_import_extend.ts b/tests/comp_import_extend.ts
new file mode 100644
index 0000000..e25cd22
--- /dev/null
+++ b/tests/comp_import_extend.ts
@@ -0,0 +1,35 @@
+import path = require("path");
+import * as tape from "tape";
+
+import * as protobuf from "../index";
+import { IFileDescriptorSet } from "../ext/descriptor";
+// to extend Root
+require("../ext/descriptor");
+
+interface Descriptor {
+  toDescriptor(
+    protoVersion: string
+  ): protobuf.Message<IFileDescriptorSet> & IFileDescriptorSet;
+  fromDescriptor(
+    descriptor: IFileDescriptorSet | protobuf.Reader | Uint8Array
+  ): protobuf.Root;
+}
+
+tape.test("extensions", function (test) {
+  // load document with extended field imported multiple times
+  const root = protobuf.loadSync(path.resolve(__dirname, "data/test.proto"));
+  root.resolveAll();
+
+  // convert to Descriptor Set
+  const decodedDescriptorSet = (root as unknown as Descriptor).toDescriptor(
+    "proto3"
+  );
+
+  // load back from descriptor set
+  const root2 = (protobuf.Root as unknown as Descriptor).fromDescriptor(
+    decodedDescriptorSet
+  );
+
+  test.pass("should parse and resolve without errors");
+  test.end();
+});
diff --git a/tests/comp_jspb-test.js b/tests/comp_jspb-test.js
new file mode 100644
index 0000000..cb77a59
--- /dev/null
+++ b/tests/comp_jspb-test.js
@@ -0,0 +1,30 @@
+var tape = require("tape");
+var protobuf  = require("..");
+
+tape.test("jspb test proto", function(test) {
+    var existingRoot = new protobuf.Root();
+    protobuf.load("tests/data/test.proto", existingRoot, function(err, root) {
+        if (err)
+            return test.fail(err.message);
+
+        test.pass("should parse without errors");
+        test.equal(root, existingRoot, "should reuse existing root");
+
+        test.doesNotThrow(function() {
+            root.resolveAll();
+            traverse(root);
+        }, "should resolve all types and generate code for them without errors");
+
+        test.end();
+    });
+
+});
+
+function traverse(ns) {
+    ns.nestedArray.forEach(function(nested) {
+        if (nested instanceof protobuf.Type)
+            nested.setup();
+        if (nested instanceof protobuf.Namespace)
+            traverse(nested);
+    });
+}
diff --git a/tests/comp_long-tags.js b/tests/comp_long-tags.js
new file mode 100644
index 0000000..c133e68
--- /dev/null
+++ b/tests/comp_long-tags.js
@@ -0,0 +1,35 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var root = protobuf.Root.fromJSON({
+    nested: {
+        Message: {
+            fields: {
+                val: {
+                    type: "uint32",
+                    id: 0x1FFFFFFF
+                }
+            }
+        }
+    }
+});
+
+tape.test("long tags", function(test) {
+
+    var Message = root.lookup("Message");
+    var message = { val: 1 };
+    var buf = Message.encode(message).finish();
+    
+    test.equal(buf[0], 0xf8, "should write F8 (78)");
+    test.equal(buf[1], 0xff, "should write FF (7F)");
+    test.equal(buf[2], 0xff, "should write FF (7F)");
+    test.equal(buf[3], 0xff, "should write FF (7F)");
+    test.equal(buf[4], 0x0f, "should write 1111b");
+    test.equal(buf[5], 1, "should write value 1");
+
+    var comp = Message.decode(buf);
+    test.deepEqual(comp, message, "should decode back the original data");
+
+    test.end();
+});
diff --git a/tests/comp_maps.js b/tests/comp_maps.js
new file mode 100644
index 0000000..37051f6
--- /dev/null
+++ b/tests/comp_maps.js
@@ -0,0 +1,176 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var root = protobuf.Root.fromJSON({
+    nested: {
+        Inner: {
+            fields: {
+                key: {
+                    type: "string",
+                    id: 1
+                },
+                values: {
+                    rule: "repeated",
+                    type: "string",
+                    id: 2
+                }
+            }
+        },
+        Outer: {
+            fields: {
+                value: {
+                    keyType: "string",
+                    type: "Inner",
+                    id: 1
+                }
+            }
+        }        
+    }
+});
+
+var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+function randomString(len) {
+    var str = "";
+    for (var i = 0; i < len; ++i)
+        str += chars.charAt((Math.random() * chars.length)|0);
+    return str;
+}
+
+function randomMap() {
+    var map = {};
+    for (var i = 0; i < 10; ++i) {
+        var values = [];
+        for (var j = 0; j < 10; ++j)
+            values.push(randomString(10));
+        var key; do { key = randomString(10); } while(map[key]);
+        map[key] = {
+            key: randomString(10),
+            values: values
+        };
+    }
+    return map;
+}
+
+tape.test("maps", function(test) {
+    var Inner = root.lookup("Inner"),
+        Outer = root.lookup("Outer");
+
+    test.test(test.name + " - randomly generated", function(test) {
+
+        var outer = { value: randomMap() };
+        var buf = Outer.encode(outer).finish();
+        var dec = Outer.decode(buf);
+
+        test.deepEqual(dec, outer, "should decode back the original random map");
+
+        test.end();
+    });
+
+    test.test(test.name + " - specifically crafted", function(test) {
+
+        var outer = {
+            value: {
+                b: {
+                    key: "1",
+                    values: ["c", "d"]
+                },
+                a: {
+                    key: "2",
+                    values: ["a", "b"]
+                }
+            }
+        };
+
+        var buf = Outer.encode(outer).finish();
+        verifyEncode(test, buf);
+
+        var dec = Outer.decode(buf);
+        test.deepEqual(dec, outer, "should decode back the original map");
+
+        test.end();
+    });
+
+    test.test(test.name + " - omitted fields", function(test) {
+
+        var mapRoot = protobuf.Root.fromJSON({
+            nested: {
+                MapMessage: {
+                    fields: {
+                        value: {
+                            keyType: "int32",
+                            type: "string",
+                            id: 1
+                        }
+                    }
+                }
+            }
+        });
+
+        var MapMessage = mapRoot.lookup("MapMessage");
+
+        var value = {
+            value: {
+                0: ''
+            }
+        };
+        var dec;
+
+        // 1 <chunk> = message(1 <varint> = 0, 2 <chunk> = empty chunk)
+        dec = MapMessage.decode(Uint8Array.of(0x0a, 0x04, 0x08, 0x00, 0x12, 0x00));
+        test.deepEqual(dec, value, "should correct decode the buffer without omitted fields");
+
+        // 1 <chunk> = message(1 <varint> = 0)
+        dec = MapMessage.decode(Uint8Array.of(0x0a, 0x02, 0x08, 0x00));
+        test.deepEqual(dec, value, "should correct decode the buffer with omitted value");
+
+        // 1 <chunk> = message(2 <chunk> = empty chunk)
+        dec = MapMessage.decode(Uint8Array.of(0x0a, 0x02, 0x12, 0x00));
+        test.deepEqual(dec, value, "should correct decode the buffer with omitted key");
+
+        // 1 <chunk> = empty chunk
+        dec = MapMessage.decode(Uint8Array.of(0x0a, 0x00));
+        test.deepEqual(dec, value, "should correct decode the buffer with both key and value omitted");
+
+        test.end();
+    });
+
+    test.end();
+});
+
+function verifyEncode(test, buf) {
+    test.test(test.name + " - should encode", function(test) {
+        test.equal(buf.length, 32, "a total of 30 bytes");
+
+        // first kv:
+        /*
+            b: {
+                key: "1",
+                values: ["c", "d"]
+            },
+        */
+        test.equal(buf[ 0], 10, "id 1, wireType 2"); // Outer.value
+        test.equal(buf[ 1], 14, "a length of 14");
+        test.equal(buf[ 2], 10, "id 1, wireType 2"); //   Outer.value $key
+        test.equal(buf[ 3],  1, "a length of 1");
+        test.equal(buf[ 4], 98, "'b'");
+        test.equal(buf[ 5], 18, "id 2, wireType 2"); //   Outer.value $value
+        test.equal(buf[ 6],  9, "a length of 9");
+        test.equal(buf[ 7], 10, "id 1, wireType 2"); //     Inner.key
+        test.equal(buf[ 8],  1 , "a length of 1");
+        test.equal(buf[ 9], 49, "'1'");
+        test.equal(buf[10], 18, "id 2, wireType 2"); //     Inner.values (1)
+        test.equal(buf[11],  1, "a length of 1");
+        test.equal(buf[12], 99, "'c'");
+        test.equal(buf[13], 18, "id 2, wireType 2"); //     Inner.values (2)
+        test.equal(buf[14],  1, "a length of 1");
+        test.equal(buf[15],100, "'d'");
+
+        // second
+        test.equal(buf[16], 10, "id 1, wireType 2"); // Outer.value
+        // ...
+
+        test.end();
+    });
+}
diff --git a/tests/comp_negative-int32.js b/tests/comp_negative-int32.js
new file mode 100644
index 0000000..33452d1
--- /dev/null
+++ b/tests/comp_negative-int32.js
@@ -0,0 +1,19 @@
+var tape = require("tape");
+
+var protobuf  = require("..");
+
+tape.test("negative int32 values", function(test) {
+    var writer = protobuf.Writer.create();
+    writer.int32(-5615122);
+    var buf = writer.finish();
+
+    test.equal(buf.length, 10, "should encode to 10 bytes");
+
+    var reader = protobuf.Reader.create(buf);
+
+    test.equal(reader.int32(), -5615122, "should decode from 10 bytes");
+
+    test.equal(reader.pos, 10, "should have consumed the entire test buffer");
+
+    test.end();
+});
diff --git a/tests/comp_oneof.js b/tests/comp_oneof.js
new file mode 100644
index 0000000..b7a7d19
--- /dev/null
+++ b/tests/comp_oneof.js
@@ -0,0 +1,58 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var proto = "syntax = \"proto3\";\
+message Message {\
+    oneof kind {\
+        string str = 1;\
+        int32 num = 2;\
+        Type enm = 4;\
+    }\
+    bool other = 3;\
+}\
+enum Type {\
+    ONE = 1;\
+    TWO = 2;\
+}";
+
+tape.test("oneofs", function(test) {
+    var root = protobuf.parse(proto).root;
+
+    var Message = root.lookup("Message");
+
+    var message = Message.create({
+        str: "a",
+        num: 1,
+        other: false
+    });
+
+    test.equal(message.num, 1, "should initialize the last value");
+    test.equal(message.kind, "num", "should reference the last value");
+    
+    message.kind = 'num';
+    test.notOk(message.hasOwnProperty('str'), "should delete other values");
+
+    message.str = "a";
+    message.kind = 'str';
+
+    test.notOk(message.hasOwnProperty('num'), "should delete the previous value");
+    test.equal(message.str, "a", "should set the new value");
+    test.equal(message.kind, "str", "should reference the new value");
+
+    message.num = 0; // default
+    message.kind = 'num';
+    test.notOk(message.hasOwnProperty('str'), "should delete the previous value");
+    test.equal(message.num, 0, "should set the new value");
+    test.equal(message.kind, "num", "should reference the new value");
+    test.equal(message.hasOwnProperty("num"), true, "should have the new value on the instance, not just the prototype");
+
+    delete message.other;
+    var buf = Message.encode(message).finish();
+    test.equal(buf.length, 2, "should write a total of 2 bytes");
+    test.equal(buf[0], 16, "should write id 1, wireType 0");
+    test.equal(buf[1], 0, "should write a value of 0");
+
+    test.end();
+
+});
diff --git a/tests/comp_optional.js b/tests/comp_optional.js
new file mode 100644
index 0000000..f0a5e50
--- /dev/null
+++ b/tests/comp_optional.js
@@ -0,0 +1,30 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var proto = "syntax = \"proto3\";\
+\
+message Message {\
+    int32 regular_int32 = 1;\
+    optional int32 optional_int32 = 2;\
+    oneof _oneof_int32 {\
+        int32 oneof_int32 = 3;\
+    }\
+}\
+";
+
+tape.test("proto3 optional", function(test) {
+    var root = protobuf.parse(proto).root;
+
+    var Message = root.lookup("Message");
+    test.equal(Message.fields.optionalInt32.optional, true);
+    test.equal(Message.fields.optionalInt32.options.proto3_optional, true);
+    test.equal(Message.oneofs._optionalInt32.name, '_optionalInt32');
+    test.deepEqual(Message.oneofs._optionalInt32.oneof, ['optionalInt32']);
+
+    var m = Message.create({});
+    test.strictEqual(m.regularInt32, 0);
+    test.strictEqual(m.optionalInt32, null);
+
+    test.end();
+});
diff --git a/tests/comp_options-parse.js b/tests/comp_options-parse.js
new file mode 100644
index 0000000..18690a4
--- /dev/null
+++ b/tests/comp_options-parse.js
@@ -0,0 +1,161 @@
+var tape = require("tape");
+var protobuf = require("..");
+
+tape.test("Options", function (test) {
+    var root = protobuf.loadSync("tests/data/options_test.proto");
+
+    test.test(test.name + " - field options (Int)", function (test) {
+        var TestFieldOptionsInt = root.lookup("TestFieldOptionsInt");
+        test.equal(TestFieldOptionsInt.fields.field1.options["(fo_rep_int)"], 2, "should take second repeated int option");
+        test.same(TestFieldOptionsInt.fields.field1.parsedOptions, [{"(fo_rep_int)": 1}, {"(fo_rep_int)": 2}], "should take all repeated int option");
+
+        test.equal(TestFieldOptionsInt.fields.field2.options["(fo_single_int)"], 3, "should correctly parse single int option");
+        test.same(TestFieldOptionsInt.fields.field2.parsedOptions, [{"(fo_single_int)": 3}], "should correctly parse single int option");
+        test.end();
+    });
+
+    test.test(test.name + " - message options (Int)", function (test) {
+        var TestMessageOptionsInt = root.lookup("TestMessageOptionsInt");
+        test.equal(TestMessageOptionsInt.options["(mo_rep_int)"], 2, "should take second repeated int message option");
+        test.equal(TestMessageOptionsInt.options["(mo_single_int)"], 3, "should correctly parse single int message option");
+        test.same(TestMessageOptionsInt.parsedOptions, [{"(mo_rep_int)": 1}, {"(mo_rep_int)": 2}, {"(mo_single_int)": 3}], "should take all int message option");
+        test.end();
+    });
+
+    test.test(test.name + " - field options (Message)", function (test) {
+        var TestFieldOptionsMsg = root.lookup("TestFieldOptionsMsg");
+        test.equal(TestFieldOptionsMsg.fields.field1.options["(fo_rep_msg).value"], 4, "should take second repeated message option");
+        test.equal(TestFieldOptionsMsg.fields.field1.options["(fo_rep_msg).rep_value"], 6, "should take second repeated int in second repeated option");
+        test.same(TestFieldOptionsMsg.fields.field1.parsedOptions, [
+            {"(fo_rep_msg)": {value: 1, rep_value: [2, 3]}},
+            {"(fo_rep_msg)": {value: 4, rep_value: [5, 6]}}], "should take all repeated message option");
+        test.equal(TestFieldOptionsMsg.fields.field2.options["(fo_single_msg).value"], 7, "should correctly parse single msg option");
+        test.equal(TestFieldOptionsMsg.fields.field2.options["(fo_single_msg).rep_value"], 9, "should take second repeated int in single msg option");
+        test.same(TestFieldOptionsMsg.fields.field2.parsedOptions, [{"(fo_single_msg)": {value: 7, rep_value: [8,9]}}], "should take all repeated message option");
+        test.end();
+    });
+
+    test.test(test.name + " - message options (Message)", function (test) {
+        var TestMessageOptionsMsg = root.lookup("TestMessageOptionsMsg");
+        test.equal(TestMessageOptionsMsg.options["(mo_rep_msg).value"], 5, "should take last repeated message option");
+        test.equal(TestMessageOptionsMsg.options["(mo_rep_msg).rep_value"], 8, "should take last repeated int in last repeated option");
+        test.equal(TestMessageOptionsMsg.options["(mo_single_msg).value"], 7, "should correctly parse single msg option");
+        test.equal(TestMessageOptionsMsg.options["(mo_single_msg).rep_value"], 9, "should take second repeated int in single msg option");
+        test.same(TestMessageOptionsMsg.parsedOptions, [
+            {"(mo_rep_msg)": {value: 1, rep_value: [2, 3]}},
+            {"(mo_rep_msg)": {value: 4, rep_value: [5, 6]}},
+            {"(mo_rep_msg)": {value: 5, rep_value: [7, 8]}},
+            {"(mo_single_msg)": {value: 7, rep_value: [8, 9]}},
+        ], "should take all message options");
+        test.end();
+    });
+
+    test.test(test.name + " - field options (Nested)", function (test) {
+        var TestFieldOptionsNested = root.lookup("TestFieldOptionsNested");
+        test.equal(TestFieldOptionsNested.fields.field1.options["(fo_rep_msg).value"], 1, "should merge repeated options messages");
+        test.equal(TestFieldOptionsNested.fields.field1.options["(fo_rep_msg).rep_value"], 3, "should parse in any order");
+        test.equal(TestFieldOptionsNested.fields.field1.options["(fo_rep_msg).nested.nested.value"], "x", "should correctly parse nested field options");
+        test.equal(TestFieldOptionsNested.fields.field1.options["(fo_rep_msg).rep_nested.value"], "z", "should take second repeated nested options");
+        test.equal(TestFieldOptionsNested.fields.field1.options["(fo_rep_msg).nested.value"], "w", "should merge nested options");
+        test.same(TestFieldOptionsNested.fields.field1.parsedOptions,[
+            {"(fo_rep_msg)": {value: 1, nested: { nested: { value: "x"}}, rep_nested: [{value: "y"},{value: "z"}], rep_value: 3}},
+            {"(fo_rep_msg)": { nested: { value: "w"}}},
+        ],"should parse all options including nested");
+
+        test.equal(TestFieldOptionsNested.fields.field2.options["(fo_single_msg).nested.value"], "x", "should correctly parse nested property name");
+        test.equal(TestFieldOptionsNested.fields.field2.options["(fo_single_msg).rep_nested.value"], "y", "should take second repeated nested options");
+        test.same(TestFieldOptionsNested.fields.field2.parsedOptions, [{
+            "(fo_single_msg)": {
+                nested: {value: "x"},
+                rep_nested: [{value: "x"}, {value: "y"}]
+            }
+        }
+        ], "should parse single nested option correctly");
+
+        test.equal(TestFieldOptionsNested.fields.field3.options["(fo_single_msg).nested.value"], "x", "should correctly parse nested field options");
+        test.equal(TestFieldOptionsNested.fields.field3.options["(fo_single_msg).nested.nested.nested.value"], "y", "should correctly parse several nesting levels");
+        test.same(TestFieldOptionsNested.fields.field3.parsedOptions, [{
+            "(fo_single_msg)": {
+                nested: {
+                    value: "x",
+                    nested: {nested: {value: "y"}}
+                }
+            }
+        }], "should correctly parse several nesting levels");
+
+        test.end();
+    });
+
+    test.test(test.name + " - message options (Nested)", function (test) {
+        var TestMessageOptionsNested = root.lookup("TestMessageOptionsNested");
+        test.equal(TestMessageOptionsNested.options["(mo_rep_msg).value"], 1, "should merge repeated options messages");
+        test.equal(TestMessageOptionsNested.options["(mo_rep_msg).rep_value"], 3, "should parse in any order");
+        test.equal(TestMessageOptionsNested.options["(mo_rep_msg).nested.nested.value"], "x", "should correctly parse nested field options");
+        test.equal(TestMessageOptionsNested.options["(mo_rep_msg).rep_nested.value"], "z", "should take second repeated nested options");
+        test.equal(TestMessageOptionsNested.options["(mo_rep_msg).nested.value"], "w", "should merge nested options");
+
+        test.equal(TestMessageOptionsNested.options["(mo_single_msg).nested.value"], "x", "should correctly parse nested property name");
+        test.equal(TestMessageOptionsNested.options["(mo_single_msg).rep_nested.value"], "y", "should take second repeated nested options");
+        test.equal(TestMessageOptionsNested.options["(mo_single_msg).rep_nested.nested.nested.value"], "y", "should correctly parse several nesting levels");
+
+        test.same(TestMessageOptionsNested.parsedOptions, [
+            {
+                "(mo_rep_msg)": {
+                    value: 1,
+                    nested: {nested: {value: "x"}},
+                    rep_nested: [{value: "y"}, {value: "z"}],
+                    rep_value: 3
+                }
+            },
+            {"(mo_rep_msg)": {nested: {value: "w"}}},
+            {
+                "(mo_single_msg)": {
+                    nested: {value: "x"},
+                    rep_nested: [{value: "x", nested: {nested: {value: "y"}}}, {value: "y"}]
+                }
+            }
+        ], "should correctly parse all nested message options");
+        test.end();
+    });
+
+    test.test(test.name + " - rpc options (Nested)", function (test) {
+        var TestOptionsRpc = root.lookup("TestOptionsRpc");
+        test.equal(TestOptionsRpc.options["(method_rep_msg).value"], 1, "should merge repeated options messages");
+        test.equal(TestOptionsRpc.options["(method_rep_msg).rep_value"], 3, "should parse in any order");
+        test.equal(TestOptionsRpc.options["(method_rep_msg).nested.nested.value"], "x", "should correctly parse nested field options");
+        test.equal(TestOptionsRpc.options["(method_rep_msg).rep_nested.value"], "z", "should take second repeated nested options");
+        test.equal(TestOptionsRpc.options["(method_rep_msg).nested.value"], "w", "should merge nested options");
+
+        test.equal(TestOptionsRpc.options["(method_single_msg).nested.value"], "x", "should correctly parse nested property name");
+        test.equal(TestOptionsRpc.options["(method_single_msg).rep_nested.value"], "y", "should take second repeated nested options");
+        test.equal(TestOptionsRpc.options["(method_single_msg).rep_nested.nested.nested.value"], "y", "should correctly parse several nesting levels");
+
+        var expectedParsedOptions = [
+            {
+                "(method_rep_msg)": {
+                    value: 1,
+                    nested: {nested: {value: "x"}},
+                    rep_nested: [{value: "y"}, {value: "z"}],
+                    rep_value: 3
+                }
+            },
+            {"(method_rep_msg)": {nested: {value: "w"}}},
+            {
+                "(method_single_msg)": {
+                    nested: {value: "x"},
+                    rep_nested: [{value: "x", nested: {nested: {value: "y"}}}, {value: "y"}]
+                }
+            }
+        ];
+
+        test.same(TestOptionsRpc.parsedOptions, expectedParsedOptions, "should correctly parse all nested message options");
+        var jsonTestOptionsRpc = TestOptionsRpc.toJSON();
+        test.same(jsonTestOptionsRpc.parsedOptions, expectedParsedOptions, "should correctly store all nested method options in JSON");
+        var rootFromJson = protobuf.Root.fromJSON(root.toJSON());
+        var TestOptionsRpcFromJson = rootFromJson.lookup("TestOptionsRpc");
+        test.same(TestOptionsRpcFromJson.parsedOptions, expectedParsedOptions, "should correctly read all nested method options from JSON");
+        test.end();
+    });
+
+    test.end();
+});
diff --git a/tests/comp_options-textformat.js b/tests/comp_options-textformat.js
new file mode 100644
index 0000000..83e6ac0
--- /dev/null
+++ b/tests/comp_options-textformat.js
@@ -0,0 +1,37 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var proto = "syntax = \"proto3\";\
+import \"google/protobuf/descriptor.proto\";\
+message MyOptions {\
+  string a = 1;\
+  string b = 2;\
+}\
+extend google.protobuf.FieldOptions {\
+  MyOptions my_options = 50000;\
+}\
+extend google.protobuf.EnumValueOptions {\
+  MyOptions my_value_option = 50001;\
+}\
+message Test {\
+  string value = 1 [(my_options) = { a: \"foo\" b: \"bar\" }];\
+  string value2 = 2 [(my_options) = { a: \"foo\" b { c: \"bar\" } }];\
+  string value3 = 3 [(my_options) = { a: \"foo\", b: \"bar\" }];\
+  string value4 = 4 [(my_options) = { a: \"foo\"; b: \"bar\" }];\
+}\
+enum TestEnum {\
+  TEST_ITEM = 0 [(my_value_option) = { a: \"foo\", b: \"bar\" }];\
+}";
+
+tape.test("options in textformat", function(test) {
+    var root = protobuf.parse(proto).root;
+    var Test = root.lookup("Test");
+    var TestEnum = root.lookup("TestEnum");
+    test.same(Test.fields.value.options, { "(my_options).a": "foo", "(my_options).b": "bar" }, "should parse correctly");
+    test.same(Test.fields.value2.options, { "(my_options).a": "foo", "(my_options).b.c": "bar" }, "should parse correctly when nested");
+    test.same(Test.fields.value3.options, { "(my_options).a": "foo", "(my_options).b": "bar" }, "should parse correctly when comma-separated");
+    test.same(Test.fields.value4.options, { "(my_options).a": "foo", "(my_options).b": "bar" }, "should parse correctly when semicolon-separated");
+    test.same(TestEnum.valuesOptions["TEST_ITEM"], { "(my_value_option).a": "foo", "(my_value_option).b": "bar" }, "should parse correctly in enum");
+    test.end();
+});
diff --git a/tests/comp_options.js b/tests/comp_options.js
new file mode 100644
index 0000000..ec98884
--- /dev/null
+++ b/tests/comp_options.js
@@ -0,0 +1,54 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var proto = `
+syntax = "proto3";
+
+option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+    info: {
+      title: "Some info";
+      version: "0";
+    };
+    host: "some.host";
+};
+
+message Message {
+    int32 regular_int32 = 1;
+    optional int32 optional_int32 = 2;
+    oneof _oneof_int32 {
+        int32 oneof_int32 = 3;
+    }
+    actionType action = 4 [ (validate.rules).enum = {
+        defined_only: true,
+        not_in: [ 0 ],
+        in: ["google","github","azuread"]
+    } ];
+}
+`;
+
+tape.test("complex options", function (test) {
+  var root = protobuf.parse(proto).root;
+
+  test.deepEqual(root.parsedOptions[0], {
+    "(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger)": {
+      info: {
+        title: "Some info",
+        version: "0",
+      },
+      host: "some.host",
+    },
+  });
+
+  test.deepEqual(root.Message.fields.action.parsedOptions[0], {
+    "(validate.rules)": {
+      enum: {
+        defined_only: true,
+        not_in: [0],
+        in: ["google", "github", "azuread"],
+      },
+    },
+  });
+
+  test.end();
+});
diff --git a/tests/comp_packed-repeated.js b/tests/comp_packed-repeated.js
new file mode 100644
index 0000000..2a8c413
--- /dev/null
+++ b/tests/comp_packed-repeated.js
@@ -0,0 +1,29 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var proto1 = "message Test {\
+  repeated uint32 a = 1 [packed = true];\
+}";
+
+var proto2 = "message Test {\
+  repeated uint32 a = 1 [packed = false];\
+}";
+
+var msg = {
+    a: [1,2,3]
+};
+
+tape.test("packed repeated values", function(test) {
+    var root1 = protobuf.parse(proto1).root,
+        root2 = protobuf.parse(proto2).root;
+    var Test1 = root1.lookup("Test"),
+        Test2 = root2.lookup("Test");
+    
+    var dec1 = Test2.decode(Test1.encode(msg).finish());
+    test.same(dec1, msg, "should decode packed even if defined non-packed");
+    var dec2 = Test1.decode(Test2.encode(msg).finish());
+    test.same(dec2, msg, "should decode non-packed even if defined packed");
+
+    test.end();
+});
diff --git a/tests/comp_parse-uncommon.js b/tests/comp_parse-uncommon.js
new file mode 100644
index 0000000..07ce363
--- /dev/null
+++ b/tests/comp_parse-uncommon.js
@@ -0,0 +1,36 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("uncommon statements", function(test) {
+    test.plan(3);
+    protobuf.load("tests/data/uncommon.proto", function(err, root) {
+        if (err || !root)
+            test.fail(err && err.message || "should parse without errors");
+        new protobuf.Root().load("tests/data/uncommon.proto", { keepCase: true }, function(err, root) {
+            if (err || !root) {
+                test.fail(err && err.message || "should parse without errors");
+                return;
+            }
+            test.pass("should parse without errors");
+            test.doesNotThrow(function() {
+                root.resolveAll();
+            }, "should resolve without errors");
+            test.doesNotThrow(function() {
+                traverseTypes(root, function(type) {
+                    type.setup();
+                });
+            }, "should setup all types without errors");
+            test.end();
+        });
+    });
+});
+
+function traverseTypes(current, fn) {
+    if (current instanceof protobuf.Type) // and/or protobuf.Enum, protobuf.Service etc.
+        fn(current);
+    if (current.nestedArray)
+        current.nestedArray.forEach(function(nested) {
+            traverseTypes(nested, fn);
+        });
+}
diff --git a/tests/comp_repeated-message.js b/tests/comp_repeated-message.js
new file mode 100644
index 0000000..bc95738
--- /dev/null
+++ b/tests/comp_repeated-message.js
@@ -0,0 +1,20 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var proto = "message Outer {\
+    repeated Inner inner = 1;\
+}\
+message Inner {\
+}";
+
+var msg = { inner: [{}, {}, {}] };
+
+tape.test("repeated messages", function(test) {
+    var root = protobuf.parse(proto).root,
+        Outer = root.lookup("Outer");
+    
+    var dec = Outer.decode(Outer.encode(msg).finish());
+    test.same(dec, msg, "should encode and decode back to the original values");
+    test.end();
+});
diff --git a/tests/comp_sfixed64-grpc.js b/tests/comp_sfixed64-grpc.js
new file mode 100644
index 0000000..5f396e5
--- /dev/null
+++ b/tests/comp_sfixed64-grpc.js
@@ -0,0 +1,38 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("sfixed64 (grpc)", function(test) {
+
+    var root = protobuf.Root.fromJSON({
+        nested: {
+            test: {
+                nested: {
+                    Test: {
+                        fields: {
+                            int_64: {
+                                type: 'sfixed64',
+                                id: 1
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    });
+
+    var Test = root.lookup("test.Test");
+
+    var buffer = Test.encode({
+        int_64: '-9095674951825889465'
+    }).finish();
+
+    test.equal(buffer.length, 9, "should encode a total of 9 bytes");
+    test.equal(buffer[0], 9, "should encode id 1, wireType 1");
+
+    var decoded = Test.decode(buffer);
+    test.ok(decoded.int_64 == '-9095674951825889465', "should decode back the original value");
+
+    test.end();
+
+});
diff --git a/tests/comp_typescript.js b/tests/comp_typescript.js
new file mode 100644
index 0000000..631a5f4
--- /dev/null
+++ b/tests/comp_typescript.js
@@ -0,0 +1,122 @@
+"use strict";
+// test currently consists only of not throwing
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = function (d, b) {
+        extendStatics = Object.setPrototypeOf ||
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+        return extendStatics(d, b);
+    };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var __metadata = (this && this.__metadata) || function (k, v) {
+    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
+};
+exports.__esModule = true;
+exports.AwesomeMessage = exports.AwesomeSubMessage = exports.AwesomeEnum = exports.Hello = void 0;
+var __1 = require("..");
+// Reflection
+var root = __1.Root.fromJSON({
+    nested: {
+        Hello: {
+            fields: {
+                value: {
+                    rule: "required",
+                    type: "string",
+                    id: 1
+                }
+            }
+        }
+    }
+});
+var HelloReflected = root.lookupType("Hello");
+HelloReflected.create({ value: "hi" });
+// Custom classes
+var Hello = /** @class */ (function (_super) {
+    __extends(Hello, _super);
+    function Hello() {
+        return _super !== null && _super.apply(this, arguments) || this;
+    }
+    Hello.prototype.foo = function () {
+        this.value = "hi";
+        return this;
+    };
+    return Hello;
+}(__1.Message));
+exports.Hello = Hello;
+root.lookupType("Hello").ctor = Hello;
+Hello.create({ value: "hi" });
+var helloMessage = new Hello({ value: "hi" });
+var helloBuffer = Hello.encode(helloMessage.foo()).finish();
+var helloDecoded = Hello.decode(helloBuffer);
+// Decorators
+require("reflect-metadata");
+var AwesomeEnum;
+(function (AwesomeEnum) {
+    AwesomeEnum[AwesomeEnum["ONE"] = 1] = "ONE";
+    AwesomeEnum[AwesomeEnum["TWO"] = 2] = "TWO";
+})(AwesomeEnum = exports.AwesomeEnum || (exports.AwesomeEnum = {}));
+var AwesomeSubMessage = /** @class */ (function (_super) {
+    __extends(AwesomeSubMessage, _super);
+    function AwesomeSubMessage() {
+        return _super !== null && _super.apply(this, arguments) || this;
+    }
+    __decorate([
+        __1.Field.d(1, "string"),
+        __metadata("design:type", String)
+    ], AwesomeSubMessage.prototype, "awesomeString");
+    __decorate([
+        __1.MapField.d(2, "string", "string"),
+        __metadata("design:type", Object)
+    ], AwesomeSubMessage.prototype, "awesomeMapString");
+    __decorate([
+        __1.MapField.d(3, "string", AwesomeEnum),
+        __metadata("design:type", Object)
+    ], AwesomeSubMessage.prototype, "awesomeMapEnum");
+    __decorate([
+        __1.MapField.d(4, "string", AwesomeSubMessage),
+        __metadata("design:type", Object)
+    ], AwesomeSubMessage.prototype, "awesomeMapMessage");
+    return AwesomeSubMessage;
+}(__1.Message));
+exports.AwesomeSubMessage = AwesomeSubMessage;
+var AwesomeMessage = /** @class */ (function (_super) {
+    __extends(AwesomeMessage, _super);
+    function AwesomeMessage() {
+        return _super !== null && _super.apply(this, arguments) || this;
+    }
+    __decorate([
+        __1.Field.d(1, "string", "optional", "awesome default string"),
+        __metadata("design:type", String)
+    ], AwesomeMessage.prototype, "awesomeField");
+    __decorate([
+        __1.Field.d(2, AwesomeSubMessage),
+        __metadata("design:type", AwesomeSubMessage)
+    ], AwesomeMessage.prototype, "awesomeSubMessage");
+    __decorate([
+        __1.Field.d(3, AwesomeEnum, "optional", AwesomeEnum.ONE),
+        __metadata("design:type", Number)
+    ], AwesomeMessage.prototype, "awesomeEnum");
+    __decorate([
+        __1.OneOf.d("awesomeSubMessage", "awesomeEnum"),
+        __metadata("design:type", String)
+    ], AwesomeMessage.prototype, "which");
+    AwesomeMessage = __decorate([
+        __1.Type.d("SuperAwesomeMessage")
+    ], AwesomeMessage);
+    return AwesomeMessage;
+}(__1.Message));
+exports.AwesomeMessage = AwesomeMessage;
+var awesomeMessage = new AwesomeMessage({ awesomeField: "hi" });
+var awesomeBuffer = AwesomeMessage.encode(awesomeMessage).finish();
+var awesomeDecoded = AwesomeMessage.decode(awesomeBuffer);
diff --git a/tests/comp_typescript.ts b/tests/comp_typescript.ts
new file mode 100644
index 0000000..8ca8483
--- /dev/null
+++ b/tests/comp_typescript.ts
@@ -0,0 +1,86 @@
+// test currently consists only of not throwing
+
+import { Root, Message, Type, Field, MapField, OneOf } from "..";
+
+// Reflection
+const root = Root.fromJSON({
+    nested: {
+        Hello: {
+            fields: {
+                value: {
+                    rule: "required",
+                    type: "string",
+                    id: 1
+                }
+            }
+        }
+    }
+});
+const HelloReflected = root.lookupType("Hello");
+
+HelloReflected.create({ value: "hi" });
+
+// Custom classes
+
+export class Hello extends Message<Hello> {
+
+    public value: string; // for MessageProperties<T> coercion
+
+    public foo() {
+        this.value = "hi";
+        return this;
+    }
+}
+
+root.lookupType("Hello").ctor = Hello;
+
+Hello.create({ value: "hi" });
+let helloMessage = new Hello({ value: "hi" });
+let helloBuffer  = Hello.encode(helloMessage.foo()).finish();
+let helloDecoded = Hello.decode(helloBuffer);
+
+// Decorators
+
+import "reflect-metadata";
+
+export enum AwesomeEnum {
+  ONE = 1,
+  TWO = 2
+}
+
+export class AwesomeSubMessage extends Message<AwesomeSubMessage> {
+
+  @Field.d(1, "string")
+  public awesomeString: string;
+
+  @MapField.d(2, "string", "string")
+  public awesomeMapString : { [key: string]: string };
+
+  @MapField.d(3, "string", AwesomeEnum)
+  public awesomeMapEnum : { [key: string]: string };
+
+  @MapField.d(4, "string", AwesomeSubMessage)
+  public awesomeMapMessage : { [key: string]: Message<AwesomeSubMessage> };
+
+}
+
+@Type.d("SuperAwesomeMessage")
+export class AwesomeMessage extends Message<AwesomeMessage> {
+
+  @Field.d(1, "string", "optional", "awesome default string")
+  public awesomeField: string;
+
+  @Field.d(2, AwesomeSubMessage)
+  public awesomeSubMessage: AwesomeSubMessage;
+
+  @Field.d(3, AwesomeEnum, "optional", AwesomeEnum.ONE)
+  public awesomeEnum: AwesomeEnum;
+
+  @OneOf.d("awesomeSubMessage", "awesomeEnum")
+  public which: string;
+
+}
+
+let awesomeMessage = new AwesomeMessage({ awesomeField: "hi" });
+let awesomeBuffer  = AwesomeMessage.encode(awesomeMessage).finish();
+let awesomeDecoded = AwesomeMessage.decode(awesomeBuffer);
diff --git a/tests/data/cli/filter.json b/tests/data/cli/filter.json
new file mode 100644
index 0000000..d6d1d00
--- /dev/null
+++ b/tests/data/cli/filter.json
@@ -0,0 +1,3 @@
+{
+  "messageNames": ["filtertest.NeedMessage1", "filtertest.NeedMessage2"]
+}
\ No newline at end of file
diff --git a/tests/data/cli/null-defaults.proto b/tests/data/cli/null-defaults.proto
new file mode 100644
index 0000000..6a140b1
--- /dev/null
+++ b/tests/data/cli/null-defaults.proto
@@ -0,0 +1,11 @@
+syntax = "proto2";
+
+message OptionalFields {
+  message SubMessage {
+    required string a = 1;
+  }
+
+  optional SubMessage a = 1;
+  optional string b = 2;
+  optional uint32 c = 3;
+}
diff --git a/tests/data/cli/test-filter-import.proto b/tests/data/cli/test-filter-import.proto
new file mode 100644
index 0000000..30c6406
--- /dev/null
+++ b/tests/data/cli/test-filter-import.proto
@@ -0,0 +1,8 @@
+
+message DependentMessageFromImport {
+  optional int32 test1 = 1;
+}
+
+message NotNeedMessageInImportFile {
+  optional int32 test1 = 1;
+}
\ No newline at end of file
diff --git a/tests/data/cli/test-filter.proto b/tests/data/cli/test-filter.proto
new file mode 100644
index 0000000..aa50ca1
--- /dev/null
+++ b/tests/data/cli/test-filter.proto
@@ -0,0 +1,21 @@
+package filtertest;
+import "./test-filter-import.proto";
+
+message NeedMessage1 {
+  optional uint32 test1 = 1;
+  optional NeedMessage2 needMessage2 = 2;
+  optional DependentMessage1 dependentMessage1 = 3;
+  optional DependentMessageFromImport dependentMessage2 = 4;
+}
+
+message NeedMessage2 {
+  optional uint32 test1 = 1;
+}
+
+message DependentMessage1 {
+  optional uint32 test1 = 1;
+}
+
+message NotNeedMessageInRootFile {
+  optional uint32 test1 = 1;
+}
\ No newline at end of file
diff --git a/tests/data/cli/test.proto b/tests/data/cli/test.proto
new file mode 100644
index 0000000..f1ffc1c
--- /dev/null
+++ b/tests/data/cli/test.proto
@@ -0,0 +1,22 @@
+syntax = "proto3";
+
+message Message {
+  int32 value = 1;
+}
+
+enum Enum {
+  option allow_alias = true;
+
+  UNSPECIFIED = 0;
+  DEFAULT = 0; // checking that an alias does not break things
+  SOMETHING = 1;
+}
+
+message OneofContainer {
+  oneof some_oneof {
+    string string_in_oneof = 1;
+    Message message_in_oneof = 2;
+  }
+  string regular_field = 3;
+  Enum enum_field = 4;
+}
diff --git a/tests/data/comment_serialization.proto b/tests/data/comment_serialization.proto
new file mode 100644
index 0000000..8ddce09
--- /dev/null
+++ b/tests/data/comment_serialization.proto
@@ -0,0 +1,30 @@
+syntax = "proto3";
+
+/// message comment
+message TestMessage {
+    /// field comment
+    string testField = 1;
+
+    /// map field comment
+    map<string, string> testMap = 2;
+
+    /// oneof field comment
+    oneof testOneof {
+        /// oneof string comment
+        string testOneofString = 3;
+        /// oneof bool comment
+        bool testOneofBool = 4;
+    }
+}
+
+/// service comment
+service TestService {
+  /// method comment
+  rpc testMethod(TestMessage) returns (TestMessage) {}
+}
+
+/// enum comment
+enum TestEnum {
+    /// enum value comment
+    VALUE = 1;
+}
diff --git a/tests/data/comments-alternate-parse.proto b/tests/data/comments-alternate-parse.proto
new file mode 100644
index 0000000..8ec9924
--- /dev/null
+++ b/tests/data/comments-alternate-parse.proto
@@ -0,0 +1,107 @@
+/**
+ * File with alternate comment syntax.
+ * This file uses double slash and regular star-slash comment styles for doc
+ * strings.
+ */
+
+syntax = "proto3";
+
+// Message with
+// a
+// multi-line comment.
+message Test1 {
+
+    /**
+     * Field with a doc-block comment.
+     */
+    string field1 = 1;
+
+    // Field with a single-line comment starting with two slashes.
+    uint32 field2 = 2;
+
+    /// Field with a single-line comment starting with three slashes.
+    bool field3 = 3;
+
+    /* Field with a single-line slash-star comment. */
+    bool field4 = 4;
+
+    bool field5 = 5; // Field with a trailing single-line two-slash comment.
+
+    bool field6 = 6; /// Field with a trailing single-line three-slash comment.
+
+    bool field7 = 7; /* Field with a trailing single-line slash-star comment. */
+
+    bool field8 = 8;
+
+    // Field with a
+    // multi-line comment.
+    bool field9 = 9;
+
+    /**
+     * Field with a
+     * multi-line doc-block comment.
+     */
+    string field10 = 10;
+
+    // Field with both block comment
+    string field11 = 11; // and trailing comment.
+    string field12 = 12; // Trailing comment in last line should not be recognized as leading comment for this field.
+}
+
+/* Message
+   with
+   a multiline plain slash-star
+   comment.
+*/
+message Test2 {
+}
+
+/*
+ * Message
+ * with
+ * a
+ * comment and stars.
+ */
+enum Test3 {
+
+    /** Value with a comment. */
+    ONE = 1;
+
+    // Value with a single-line comment.
+    TWO = 2;
+
+    /// Value with a triple-slash comment.
+    THREE = 3;  // ignored
+
+    FOUR = 4; /// Other value with a comment.
+
+    // Leading comment for value with both types of comments after field with trailing comment.
+    FIVE = 5; // Trailing comment for value with both types of comments after field with trailing comment.
+}
+
+service ServiceTest {
+    // My method does things
+    rpc SingleLineMethod (MyRequest) returns (MyResponse);
+
+    // TwoLineMethodWithComment documentation
+    rpc TwoLineMethodWithComment (MyRequest)
+      returns (MyResponse);
+
+    // Very very long method
+    rpc
+      ThreeLine012345678901234567890123456712345671234567123456783927483923473892837489238749832432874983274983274983274(MyRequest)
+      returns (MyResponse);
+
+    // Random comment
+
+    rpc TwoLineMethodNoComment (MyRequest)
+      returns (MyResponse);
+}
+
+message MyRequest {
+    string path = 1;
+}
+
+message MyResponse {
+    int32 status = 2;
+}
diff --git a/tests/data/comments.d.ts b/tests/data/comments.d.ts
new file mode 100644
index 0000000..1a49e9e
--- /dev/null
+++ b/tests/data/comments.d.ts
@@ -0,0 +1,48 @@
+import * as $protobuf from "../..";
+export interface ITest1 {
+    field1?: (string|null);
+    field2?: (number|null);
+    field3?: (boolean|null);
+}
+
+export class Test1 implements ITest1 {
+    constructor(properties?: ITest1);
+    public field1: string;
+    public field2: number;
+    public field3: boolean;
+    public static create(properties?: ITest1): Test1;
+    public static encode(message: ITest1, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: ITest1, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): Test1;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): Test1;
+    public static verify(message: { [k: string]: any }): (string|null);
+    public static fromObject(object: { [k: string]: any }): Test1;
+    public static toObject(message: Test1, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public toJSON(): { [k: string]: any };
+    public static getTypeUrl(typeUrlPrefix?: string): string;
+}
+
+export interface ITest2 {
+}
+
+export class Test2 implements ITest2 {
+    constructor(properties?: ITest2);
+    public static create(properties?: ITest2): Test2;
+    public static encode(message: ITest2, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: ITest2, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): Test2;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): Test2;
+    public static verify(message: { [k: string]: any }): (string|null);
+    public static fromObject(object: { [k: string]: any }): Test2;
+    public static toObject(message: Test2, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public toJSON(): { [k: string]: any };
+    public static getTypeUrl(typeUrlPrefix?: string): string;
+}
+
+export enum Test3 {
+    ONE = 1,
+    TWO = 2,
+    THREE = 3,
+    FOUR = 4,
+    FIVE = 5
+}
diff --git a/tests/data/comments.js b/tests/data/comments.js
new file mode 100644
index 0000000..706ae29
--- /dev/null
+++ b/tests/data/comments.js
@@ -0,0 +1,457 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+"use strict";
+
+var $protobuf = require("../../minimal");
+
+// Common aliases
+var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+// Exported root namespace
+var $root = $protobuf.roots.test_comments || ($protobuf.roots.test_comments = {});
+
+$root.Test1 = (function() {
+
+    /**
+     * Properties of a Test1.
+     * @exports ITest1
+     * @interface ITest1
+     * @property {string|null} [field1] Field with a comment.
+     * @property {number|null} [field2] Test1 field2
+     * @property {boolean|null} [field3] Field with a comment and a <a href="http://example.com/foo/">link</a>
+     */
+
+    /**
+     * Constructs a new Test1.
+     * @exports Test1
+     * @classdesc Message
+     * with
+     * a
+     * comment.
+     * @implements ITest1
+     * @constructor
+     * @param {ITest1=} [properties] Properties to set
+     */
+    function Test1(properties) {
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * Field with a comment.
+     * @member {string} field1
+     * @memberof Test1
+     * @instance
+     */
+    Test1.prototype.field1 = "";
+
+    /**
+     * Test1 field2.
+     * @member {number} field2
+     * @memberof Test1
+     * @instance
+     */
+    Test1.prototype.field2 = 0;
+
+    /**
+     * Field with a comment and a <a href="http://example.com/foo/">link</a>
+     * @member {boolean} field3
+     * @memberof Test1
+     * @instance
+     */
+    Test1.prototype.field3 = false;
+
+    /**
+     * Creates a new Test1 instance using the specified properties.
+     * @function create
+     * @memberof Test1
+     * @static
+     * @param {ITest1=} [properties] Properties to set
+     * @returns {Test1} Test1 instance
+     */
+    Test1.create = function create(properties) {
+        return new Test1(properties);
+    };
+
+    /**
+     * Encodes the specified Test1 message. Does not implicitly {@link Test1.verify|verify} messages.
+     * @function encode
+     * @memberof Test1
+     * @static
+     * @param {ITest1} message Test1 message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    Test1.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.field1 != null && Object.hasOwnProperty.call(message, "field1"))
+            writer.uint32(/* id 1, wireType 2 =*/10).string(message.field1);
+        if (message.field2 != null && Object.hasOwnProperty.call(message, "field2"))
+            writer.uint32(/* id 2, wireType 0 =*/16).uint32(message.field2);
+        if (message.field3 != null && Object.hasOwnProperty.call(message, "field3"))
+            writer.uint32(/* id 3, wireType 0 =*/24).bool(message.field3);
+        return writer;
+    };
+
+    /**
+     * Encodes the specified Test1 message, length delimited. Does not implicitly {@link Test1.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof Test1
+     * @static
+     * @param {ITest1} message Test1 message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    Test1.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a Test1 message from the specified reader or buffer.
+     * @function decode
+     * @memberof Test1
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {Test1} Test1
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    Test1.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Test1();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 1:
+                message.field1 = reader.string();
+                break;
+            case 2:
+                message.field2 = reader.uint32();
+                break;
+            case 3:
+                message.field3 = reader.bool();
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a Test1 message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof Test1
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {Test1} Test1
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    Test1.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a Test1 message.
+     * @function verify
+     * @memberof Test1
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    Test1.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.field1 != null && message.hasOwnProperty("field1"))
+            if (!$util.isString(message.field1))
+                return "field1: string expected";
+        if (message.field2 != null && message.hasOwnProperty("field2"))
+            if (!$util.isInteger(message.field2))
+                return "field2: integer expected";
+        if (message.field3 != null && message.hasOwnProperty("field3"))
+            if (typeof message.field3 !== "boolean")
+                return "field3: boolean expected";
+        return null;
+    };
+
+    /**
+     * Creates a Test1 message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof Test1
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {Test1} Test1
+     */
+    Test1.fromObject = function fromObject(object) {
+        if (object instanceof $root.Test1)
+            return object;
+        var message = new $root.Test1();
+        if (object.field1 != null)
+            message.field1 = String(object.field1);
+        if (object.field2 != null)
+            message.field2 = object.field2 >>> 0;
+        if (object.field3 != null)
+            message.field3 = Boolean(object.field3);
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a Test1 message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof Test1
+     * @static
+     * @param {Test1} message Test1
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    Test1.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        var object = {};
+        if (options.defaults) {
+            object.field1 = "";
+            object.field2 = 0;
+            object.field3 = false;
+        }
+        if (message.field1 != null && message.hasOwnProperty("field1"))
+            object.field1 = message.field1;
+        if (message.field2 != null && message.hasOwnProperty("field2"))
+            object.field2 = message.field2;
+        if (message.field3 != null && message.hasOwnProperty("field3"))
+            object.field3 = message.field3;
+        return object;
+    };
+
+    /**
+     * Converts this Test1 to JSON.
+     * @function toJSON
+     * @memberof Test1
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    Test1.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    /**
+     * Gets the default type url for Test1
+     * @function getTypeUrl
+     * @memberof Test1
+     * @static
+     * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+     * @returns {string} The default type url
+     */
+    Test1.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+        if (typeUrlPrefix === undefined) {
+            typeUrlPrefix = "type.googleapis.com";
+        }
+        return typeUrlPrefix + "/Test1";
+    };
+
+    return Test1;
+})();
+
+$root.Test2 = (function() {
+
+    /**
+     * Properties of a Test2.
+     * @exports ITest2
+     * @interface ITest2
+     */
+
+    /**
+     * Constructs a new Test2.
+     * @exports Test2
+     * @classdesc Represents a Test2.
+     * @implements ITest2
+     * @constructor
+     * @param {ITest2=} [properties] Properties to set
+     */
+    function Test2(properties) {
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * Creates a new Test2 instance using the specified properties.
+     * @function create
+     * @memberof Test2
+     * @static
+     * @param {ITest2=} [properties] Properties to set
+     * @returns {Test2} Test2 instance
+     */
+    Test2.create = function create(properties) {
+        return new Test2(properties);
+    };
+
+    /**
+     * Encodes the specified Test2 message. Does not implicitly {@link Test2.verify|verify} messages.
+     * @function encode
+     * @memberof Test2
+     * @static
+     * @param {ITest2} message Test2 message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    Test2.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        return writer;
+    };
+
+    /**
+     * Encodes the specified Test2 message, length delimited. Does not implicitly {@link Test2.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof Test2
+     * @static
+     * @param {ITest2} message Test2 message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    Test2.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a Test2 message from the specified reader or buffer.
+     * @function decode
+     * @memberof Test2
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {Test2} Test2
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    Test2.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Test2();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a Test2 message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof Test2
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {Test2} Test2
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    Test2.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a Test2 message.
+     * @function verify
+     * @memberof Test2
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    Test2.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        return null;
+    };
+
+    /**
+     * Creates a Test2 message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof Test2
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {Test2} Test2
+     */
+    Test2.fromObject = function fromObject(object) {
+        if (object instanceof $root.Test2)
+            return object;
+        return new $root.Test2();
+    };
+
+    /**
+     * Creates a plain object from a Test2 message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof Test2
+     * @static
+     * @param {Test2} message Test2
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    Test2.toObject = function toObject() {
+        return {};
+    };
+
+    /**
+     * Converts this Test2 to JSON.
+     * @function toJSON
+     * @memberof Test2
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    Test2.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    /**
+     * Gets the default type url for Test2
+     * @function getTypeUrl
+     * @memberof Test2
+     * @static
+     * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+     * @returns {string} The default type url
+     */
+    Test2.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+        if (typeUrlPrefix === undefined) {
+            typeUrlPrefix = "type.googleapis.com";
+        }
+        return typeUrlPrefix + "/Test2";
+    };
+
+    return Test2;
+})();
+
+/**
+ * Test3 enum.
+ * @exports Test3
+ * @enum {number}
+ * @property {number} ONE=1 Value with a comment.
+ * @property {number} TWO=2 TWO value
+ * @property {number} THREE=3 Preferred value with a comment.
+ * @property {number} FOUR=4 Other value with a comment.
+ * @property {number} FIVE=5 Leading comment for value with both types of comments after field with trailing comment.
+ */
+$root.Test3 = (function() {
+    var valuesById = {}, values = Object.create(valuesById);
+    values[valuesById[1] = "ONE"] = 1;
+    values[valuesById[2] = "TWO"] = 2;
+    values[valuesById[3] = "THREE"] = 3;
+    values[valuesById[4] = "FOUR"] = 4;
+    values[valuesById[5] = "FIVE"] = 5;
+    return values;
+})();
+
+module.exports = $root;
diff --git a/tests/data/comments.proto b/tests/data/comments.proto
new file mode 100644
index 0000000..7009297
--- /dev/null
+++ b/tests/data/comments.proto
@@ -0,0 +1,54 @@
+/**
+ * File with a comment. (TODO)
+ */
+
+syntax = "proto3";
+
+/**
+ * Message
+ * with
+a
+ ** comment.
+ */
+message Test1 { /// not a valid comment
+
+    /**
+     * Field with a comment.
+     */
+    string field1 = 1;
+
+    // Field with no comment.
+    uint32 field2 = 2;
+
+    bool field3 = 3; /// Field with a comment and a <a href="http://example.com/foo/">link</a>
+}
+
+// Message
+// with
+// no
+// comment.
+message Test2 {
+}
+
+/*
+ * Message
+ * with
+ * no
+ * comment
+ */
+enum Test3 {
+
+    /** Value with a comment. */
+    ONE = 1;
+
+    // Value with no comment.
+    TWO = 2;
+
+    /// Preferred value with a comment.
+    THREE = 3; /// Value with a comment.
+
+    FOUR = 4; /// Other value with a comment.
+
+    /// Leading comment for value with both types of comments after field with trailing comment.
+    FIVE = 5; /// Trailing comment for value with both types of comments after field with trailing comment.
+}
diff --git a/tests/data/common.json b/tests/data/common.json
new file mode 100644
index 0000000..f2875a7
--- /dev/null
+++ b/tests/data/common.json
@@ -0,0 +1,117 @@
+{
+  "nested": {
+    "Something": {
+      "fields": {}
+    },
+    "google": {
+      "nested": {
+        "protobuf": {
+          "nested": {
+            "Any": {
+              "fields": {
+                "type_url": {
+                  "type": "string",
+                  "id": 1
+                },
+                "value": {
+                  "type": "bytes",
+                  "id": 2
+                }
+              }
+            },
+            "Duration": {
+              "fields": {
+                "seconds": {
+                  "type": "int64",
+                  "id": 1
+                },
+                "nanos": {
+                  "type": "int32",
+                  "id": 2
+                }
+              }
+            },
+            "Empty": {
+              "fields": {}
+            },
+            "Struct": {
+              "fields": {
+                "fields": {
+                  "keyType": "string",
+                  "type": "Value",
+                  "id": 1
+                }
+              }
+            },
+            "Value": {
+              "oneofs": {
+                "kind": {
+                  "oneof": [
+                    "nullValue",
+                    "numberValue",
+                    "stringValue",
+                    "boolValue",
+                    "structValue",
+                    "listValue"
+                  ]
+                }
+              },
+              "fields": {
+                "nullValue": {
+                  "type": "NullValue",
+                  "id": 1
+                },
+                "numberValue": {
+                  "type": "double",
+                  "id": 2
+                },
+                "stringValue": {
+                  "type": "string",
+                  "id": 3
+                },
+                "boolValue": {
+                  "type": "bool",
+                  "id": 4
+                },
+                "structValue": {
+                  "type": "Struct",
+                  "id": 5
+                },
+                "listValue": {
+                  "type": "ListValue",
+                  "id": 6
+                }
+              }
+            },
+            "NullValue": {
+              "values": {
+                "NULL_VALUE": 0
+              }
+            },
+            "ListValue": {
+              "fields": {
+                "values": {
+                  "rule": "repeated",
+                  "type": "Value",
+                  "id": 1
+                }
+              }
+            },
+            "Timestamp": {
+              "fields": {
+                "seconds": {
+                  "type": "int64",
+                  "id": 1
+                },
+                "nanos": {
+                  "type": "int32",
+                  "id": 2
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/tests/data/common.proto b/tests/data/common.proto
new file mode 100644
index 0000000..b725a55
--- /dev/null
+++ b/tests/data/common.proto
@@ -0,0 +1,10 @@
+syntax = "proto3";
+
+import "google/protobuf/any.proto";
+import "google/protobuf/duration.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/struct.proto";
+import "google/protobuf/timestamp.proto";
+
+message Something {
+}
diff --git a/tests/data/convert.d.ts b/tests/data/convert.d.ts
new file mode 100644
index 0000000..b40b881
--- /dev/null
+++ b/tests/data/convert.d.ts
@@ -0,0 +1,45 @@
+import * as $protobuf from "../..";
+import Long from "long";
+
+export interface IMessage {
+    stringVal?: (string|null);
+    stringRepeated?: (string[]|null);
+    uint64Val?: (number|Long|null);
+    uint64Repeated?: ((number|Long)[]|null);
+    bytesVal?: (Uint8Array|null);
+    bytesRepeated?: (Uint8Array[]|null);
+    enumVal?: (Message.SomeEnum|null);
+    enumRepeated?: (Message.SomeEnum[]|null);
+    int64Map?: ({ [k: string]: (number|Long) }|null);
+}
+
+export class Message implements IMessage {
+    constructor(properties?: IMessage);
+    public stringVal: string;
+    public stringRepeated: string[];
+    public uint64Val: (number|Long);
+    public uint64Repeated: (number|Long)[];
+    public bytesVal: Uint8Array;
+    public bytesRepeated: Uint8Array[];
+    public enumVal: Message.SomeEnum;
+    public enumRepeated: Message.SomeEnum[];
+    public int64Map: { [k: string]: (number|Long) };
+    public static create(properties?: IMessage): Message;
+    public static encode(message: IMessage, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: IMessage, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): Message;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): Message;
+    public static verify(message: { [k: string]: any }): (string|null);
+    public static fromObject(object: { [k: string]: any }): Message;
+    public static toObject(message: Message, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public toJSON(): { [k: string]: any };
+    public static getTypeUrl(typeUrlPrefix?: string): string;
+}
+
+export namespace Message {
+
+    enum SomeEnum {
+        ONE = 1,
+        TWO = 2
+    }
+}
diff --git a/tests/data/convert.js b/tests/data/convert.js
new file mode 100644
index 0000000..34f2528
--- /dev/null
+++ b/tests/data/convert.js
@@ -0,0 +1,597 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+"use strict";
+
+var $protobuf = require("../../minimal");
+
+// Common aliases
+var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+// Exported root namespace
+var $root = $protobuf.roots.test_convert || ($protobuf.roots.test_convert = {});
+
+$root.Message = (function() {
+
+    /**
+     * Properties of a Message.
+     * @exports IMessage
+     * @interface IMessage
+     * @property {string|null} [stringVal] Message stringVal
+     * @property {Array.<string>|null} [stringRepeated] Message stringRepeated
+     * @property {number|Long|null} [uint64Val] Message uint64Val
+     * @property {Array.<number|Long>|null} [uint64Repeated] Message uint64Repeated
+     * @property {Uint8Array|null} [bytesVal] Message bytesVal
+     * @property {Array.<Uint8Array>|null} [bytesRepeated] Message bytesRepeated
+     * @property {Message.SomeEnum|null} [enumVal] Message enumVal
+     * @property {Array.<Message.SomeEnum>|null} [enumRepeated] Message enumRepeated
+     * @property {Object.<string,number|Long>|null} [int64Map] Message int64Map
+     */
+
+    /**
+     * Constructs a new Message.
+     * @exports Message
+     * @classdesc Represents a Message.
+     * @implements IMessage
+     * @constructor
+     * @param {IMessage=} [properties] Properties to set
+     */
+    function Message(properties) {
+        this.stringRepeated = [];
+        this.uint64Repeated = [];
+        this.bytesRepeated = [];
+        this.enumRepeated = [];
+        this.int64Map = {};
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * Message stringVal.
+     * @member {string} stringVal
+     * @memberof Message
+     * @instance
+     */
+    Message.prototype.stringVal = "";
+
+    /**
+     * Message stringRepeated.
+     * @member {Array.<string>} stringRepeated
+     * @memberof Message
+     * @instance
+     */
+    Message.prototype.stringRepeated = $util.emptyArray;
+
+    /**
+     * Message uint64Val.
+     * @member {number|Long} uint64Val
+     * @memberof Message
+     * @instance
+     */
+    Message.prototype.uint64Val = $util.Long ? $util.Long.fromBits(0,0,true) : 0;
+
+    /**
+     * Message uint64Repeated.
+     * @member {Array.<number|Long>} uint64Repeated
+     * @memberof Message
+     * @instance
+     */
+    Message.prototype.uint64Repeated = $util.emptyArray;
+
+    /**
+     * Message bytesVal.
+     * @member {Uint8Array} bytesVal
+     * @memberof Message
+     * @instance
+     */
+    Message.prototype.bytesVal = $util.newBuffer([]);
+
+    /**
+     * Message bytesRepeated.
+     * @member {Array.<Uint8Array>} bytesRepeated
+     * @memberof Message
+     * @instance
+     */
+    Message.prototype.bytesRepeated = $util.emptyArray;
+
+    /**
+     * Message enumVal.
+     * @member {Message.SomeEnum} enumVal
+     * @memberof Message
+     * @instance
+     */
+    Message.prototype.enumVal = 1;
+
+    /**
+     * Message enumRepeated.
+     * @member {Array.<Message.SomeEnum>} enumRepeated
+     * @memberof Message
+     * @instance
+     */
+    Message.prototype.enumRepeated = $util.emptyArray;
+
+    /**
+     * Message int64Map.
+     * @member {Object.<string,number|Long>} int64Map
+     * @memberof Message
+     * @instance
+     */
+    Message.prototype.int64Map = $util.emptyObject;
+
+    /**
+     * Creates a new Message instance using the specified properties.
+     * @function create
+     * @memberof Message
+     * @static
+     * @param {IMessage=} [properties] Properties to set
+     * @returns {Message} Message instance
+     */
+    Message.create = function create(properties) {
+        return new Message(properties);
+    };
+
+    /**
+     * Encodes the specified Message message. Does not implicitly {@link Message.verify|verify} messages.
+     * @function encode
+     * @memberof Message
+     * @static
+     * @param {IMessage} message Message message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    Message.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.stringVal != null && Object.hasOwnProperty.call(message, "stringVal"))
+            writer.uint32(/* id 1, wireType 2 =*/10).string(message.stringVal);
+        if (message.stringRepeated != null && message.stringRepeated.length)
+            for (var i = 0; i < message.stringRepeated.length; ++i)
+                writer.uint32(/* id 2, wireType 2 =*/18).string(message.stringRepeated[i]);
+        if (message.uint64Val != null && Object.hasOwnProperty.call(message, "uint64Val"))
+            writer.uint32(/* id 3, wireType 0 =*/24).uint64(message.uint64Val);
+        if (message.uint64Repeated != null && message.uint64Repeated.length) {
+            writer.uint32(/* id 4, wireType 2 =*/34).fork();
+            for (var i = 0; i < message.uint64Repeated.length; ++i)
+                writer.uint64(message.uint64Repeated[i]);
+            writer.ldelim();
+        }
+        if (message.bytesVal != null && Object.hasOwnProperty.call(message, "bytesVal"))
+            writer.uint32(/* id 5, wireType 2 =*/42).bytes(message.bytesVal);
+        if (message.bytesRepeated != null && message.bytesRepeated.length)
+            for (var i = 0; i < message.bytesRepeated.length; ++i)
+                writer.uint32(/* id 6, wireType 2 =*/50).bytes(message.bytesRepeated[i]);
+        if (message.enumVal != null && Object.hasOwnProperty.call(message, "enumVal"))
+            writer.uint32(/* id 7, wireType 0 =*/56).int32(message.enumVal);
+        if (message.enumRepeated != null && message.enumRepeated.length) {
+            writer.uint32(/* id 8, wireType 2 =*/66).fork();
+            for (var i = 0; i < message.enumRepeated.length; ++i)
+                writer.int32(message.enumRepeated[i]);
+            writer.ldelim();
+        }
+        if (message.int64Map != null && Object.hasOwnProperty.call(message, "int64Map"))
+            for (var keys = Object.keys(message.int64Map), i = 0; i < keys.length; ++i)
+                writer.uint32(/* id 9, wireType 2 =*/74).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]).uint32(/* id 2, wireType 0 =*/16).int64(message.int64Map[keys[i]]).ldelim();
+        return writer;
+    };
+
+    /**
+     * Encodes the specified Message message, length delimited. Does not implicitly {@link Message.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof Message
+     * @static
+     * @param {IMessage} message Message message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    Message.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a Message message from the specified reader or buffer.
+     * @function decode
+     * @memberof Message
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {Message} Message
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    Message.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Message(), key, value;
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 1:
+                message.stringVal = reader.string();
+                break;
+            case 2:
+                if (!(message.stringRepeated && message.stringRepeated.length))
+                    message.stringRepeated = [];
+                message.stringRepeated.push(reader.string());
+                break;
+            case 3:
+                message.uint64Val = reader.uint64();
+                break;
+            case 4:
+                if (!(message.uint64Repeated && message.uint64Repeated.length))
+                    message.uint64Repeated = [];
+                if ((tag & 7) === 2) {
+                    var end2 = reader.uint32() + reader.pos;
+                    while (reader.pos < end2)
+                        message.uint64Repeated.push(reader.uint64());
+                } else
+                    message.uint64Repeated.push(reader.uint64());
+                break;
+            case 5:
+                message.bytesVal = reader.bytes();
+                break;
+            case 6:
+                if (!(message.bytesRepeated && message.bytesRepeated.length))
+                    message.bytesRepeated = [];
+                message.bytesRepeated.push(reader.bytes());
+                break;
+            case 7:
+                message.enumVal = reader.int32();
+                break;
+            case 8:
+                if (!(message.enumRepeated && message.enumRepeated.length))
+                    message.enumRepeated = [];
+                if ((tag & 7) === 2) {
+                    var end2 = reader.uint32() + reader.pos;
+                    while (reader.pos < end2)
+                        message.enumRepeated.push(reader.int32());
+                } else
+                    message.enumRepeated.push(reader.int32());
+                break;
+            case 9:
+                if (message.int64Map === $util.emptyObject)
+                    message.int64Map = {};
+                var end2 = reader.uint32() + reader.pos;
+                key = "";
+                value = 0;
+                while (reader.pos < end2) {
+                    var tag2 = reader.uint32();
+                    switch (tag2 >>> 3) {
+                    case 1:
+                        key = reader.string();
+                        break;
+                    case 2:
+                        value = reader.int64();
+                        break;
+                    default:
+                        reader.skipType(tag2 & 7);
+                        break;
+                    }
+                }
+                message.int64Map[key] = value;
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a Message message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof Message
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {Message} Message
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    Message.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a Message message.
+     * @function verify
+     * @memberof Message
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    Message.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.stringVal != null && message.hasOwnProperty("stringVal"))
+            if (!$util.isString(message.stringVal))
+                return "stringVal: string expected";
+        if (message.stringRepeated != null && message.hasOwnProperty("stringRepeated")) {
+            if (!Array.isArray(message.stringRepeated))
+                return "stringRepeated: array expected";
+            for (var i = 0; i < message.stringRepeated.length; ++i)
+                if (!$util.isString(message.stringRepeated[i]))
+                    return "stringRepeated: string[] expected";
+        }
+        if (message.uint64Val != null && message.hasOwnProperty("uint64Val"))
+            if (!$util.isInteger(message.uint64Val) && !(message.uint64Val && $util.isInteger(message.uint64Val.low) && $util.isInteger(message.uint64Val.high)))
+                return "uint64Val: integer|Long expected";
+        if (message.uint64Repeated != null && message.hasOwnProperty("uint64Repeated")) {
+            if (!Array.isArray(message.uint64Repeated))
+                return "uint64Repeated: array expected";
+            for (var i = 0; i < message.uint64Repeated.length; ++i)
+                if (!$util.isInteger(message.uint64Repeated[i]) && !(message.uint64Repeated[i] && $util.isInteger(message.uint64Repeated[i].low) && $util.isInteger(message.uint64Repeated[i].high)))
+                    return "uint64Repeated: integer|Long[] expected";
+        }
+        if (message.bytesVal != null && message.hasOwnProperty("bytesVal"))
+            if (!(message.bytesVal && typeof message.bytesVal.length === "number" || $util.isString(message.bytesVal)))
+                return "bytesVal: buffer expected";
+        if (message.bytesRepeated != null && message.hasOwnProperty("bytesRepeated")) {
+            if (!Array.isArray(message.bytesRepeated))
+                return "bytesRepeated: array expected";
+            for (var i = 0; i < message.bytesRepeated.length; ++i)
+                if (!(message.bytesRepeated[i] && typeof message.bytesRepeated[i].length === "number" || $util.isString(message.bytesRepeated[i])))
+                    return "bytesRepeated: buffer[] expected";
+        }
+        if (message.enumVal != null && message.hasOwnProperty("enumVal"))
+            switch (message.enumVal) {
+            default:
+                return "enumVal: enum value expected";
+            case 1:
+            case 2:
+                break;
+            }
+        if (message.enumRepeated != null && message.hasOwnProperty("enumRepeated")) {
+            if (!Array.isArray(message.enumRepeated))
+                return "enumRepeated: array expected";
+            for (var i = 0; i < message.enumRepeated.length; ++i)
+                switch (message.enumRepeated[i]) {
+                default:
+                    return "enumRepeated: enum value[] expected";
+                case 1:
+                case 2:
+                    break;
+                }
+        }
+        if (message.int64Map != null && message.hasOwnProperty("int64Map")) {
+            if (!$util.isObject(message.int64Map))
+                return "int64Map: object expected";
+            var key = Object.keys(message.int64Map);
+            for (var i = 0; i < key.length; ++i)
+                if (!$util.isInteger(message.int64Map[key[i]]) && !(message.int64Map[key[i]] && $util.isInteger(message.int64Map[key[i]].low) && $util.isInteger(message.int64Map[key[i]].high)))
+                    return "int64Map: integer|Long{k:string} expected";
+        }
+        return null;
+    };
+
+    /**
+     * Creates a Message message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof Message
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {Message} Message
+     */
+    Message.fromObject = function fromObject(object) {
+        if (object instanceof $root.Message)
+            return object;
+        var message = new $root.Message();
+        if (object.stringVal != null)
+            message.stringVal = String(object.stringVal);
+        if (object.stringRepeated) {
+            if (!Array.isArray(object.stringRepeated))
+                throw TypeError(".Message.stringRepeated: array expected");
+            message.stringRepeated = [];
+            for (var i = 0; i < object.stringRepeated.length; ++i)
+                message.stringRepeated[i] = String(object.stringRepeated[i]);
+        }
+        if (object.uint64Val != null)
+            if ($util.Long)
+                (message.uint64Val = $util.Long.fromValue(object.uint64Val)).unsigned = true;
+            else if (typeof object.uint64Val === "string")
+                message.uint64Val = parseInt(object.uint64Val, 10);
+            else if (typeof object.uint64Val === "number")
+                message.uint64Val = object.uint64Val;
+            else if (typeof object.uint64Val === "object")
+                message.uint64Val = new $util.LongBits(object.uint64Val.low >>> 0, object.uint64Val.high >>> 0).toNumber(true);
+        if (object.uint64Repeated) {
+            if (!Array.isArray(object.uint64Repeated))
+                throw TypeError(".Message.uint64Repeated: array expected");
+            message.uint64Repeated = [];
+            for (var i = 0; i < object.uint64Repeated.length; ++i)
+                if ($util.Long)
+                    (message.uint64Repeated[i] = $util.Long.fromValue(object.uint64Repeated[i])).unsigned = true;
+                else if (typeof object.uint64Repeated[i] === "string")
+                    message.uint64Repeated[i] = parseInt(object.uint64Repeated[i], 10);
+                else if (typeof object.uint64Repeated[i] === "number")
+                    message.uint64Repeated[i] = object.uint64Repeated[i];
+                else if (typeof object.uint64Repeated[i] === "object")
+                    message.uint64Repeated[i] = new $util.LongBits(object.uint64Repeated[i].low >>> 0, object.uint64Repeated[i].high >>> 0).toNumber(true);
+        }
+        if (object.bytesVal != null)
+            if (typeof object.bytesVal === "string")
+                $util.base64.decode(object.bytesVal, message.bytesVal = $util.newBuffer($util.base64.length(object.bytesVal)), 0);
+            else if (object.bytesVal.length >= 0)
+                message.bytesVal = object.bytesVal;
+        if (object.bytesRepeated) {
+            if (!Array.isArray(object.bytesRepeated))
+                throw TypeError(".Message.bytesRepeated: array expected");
+            message.bytesRepeated = [];
+            for (var i = 0; i < object.bytesRepeated.length; ++i)
+                if (typeof object.bytesRepeated[i] === "string")
+                    $util.base64.decode(object.bytesRepeated[i], message.bytesRepeated[i] = $util.newBuffer($util.base64.length(object.bytesRepeated[i])), 0);
+                else if (object.bytesRepeated[i].length >= 0)
+                    message.bytesRepeated[i] = object.bytesRepeated[i];
+        }
+        switch (object.enumVal) {
+        case "ONE":
+        case 1:
+            message.enumVal = 1;
+            break;
+        case "TWO":
+        case 2:
+            message.enumVal = 2;
+            break;
+        }
+        if (object.enumRepeated) {
+            if (!Array.isArray(object.enumRepeated))
+                throw TypeError(".Message.enumRepeated: array expected");
+            message.enumRepeated = [];
+            for (var i = 0; i < object.enumRepeated.length; ++i)
+                switch (object.enumRepeated[i]) {
+                default:
+                case "ONE":
+                case 1:
+                    message.enumRepeated[i] = 1;
+                    break;
+                case "TWO":
+                case 2:
+                    message.enumRepeated[i] = 2;
+                    break;
+                }
+        }
+        if (object.int64Map) {
+            if (typeof object.int64Map !== "object")
+                throw TypeError(".Message.int64Map: object expected");
+            message.int64Map = {};
+            for (var keys = Object.keys(object.int64Map), i = 0; i < keys.length; ++i)
+                if ($util.Long)
+                    (message.int64Map[keys[i]] = $util.Long.fromValue(object.int64Map[keys[i]])).unsigned = false;
+                else if (typeof object.int64Map[keys[i]] === "string")
+                    message.int64Map[keys[i]] = parseInt(object.int64Map[keys[i]], 10);
+                else if (typeof object.int64Map[keys[i]] === "number")
+                    message.int64Map[keys[i]] = object.int64Map[keys[i]];
+                else if (typeof object.int64Map[keys[i]] === "object")
+                    message.int64Map[keys[i]] = new $util.LongBits(object.int64Map[keys[i]].low >>> 0, object.int64Map[keys[i]].high >>> 0).toNumber();
+        }
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a Message message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof Message
+     * @static
+     * @param {Message} message Message
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    Message.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        var object = {};
+        if (options.arrays || options.defaults) {
+            object.stringRepeated = [];
+            object.uint64Repeated = [];
+            object.bytesRepeated = [];
+            object.enumRepeated = [];
+        }
+        if (options.objects || options.defaults)
+            object.int64Map = {};
+        if (options.defaults) {
+            object.stringVal = "";
+            if ($util.Long) {
+                var long = new $util.Long(0, 0, true);
+                object.uint64Val = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
+            } else
+                object.uint64Val = options.longs === String ? "0" : 0;
+            if (options.bytes === String)
+                object.bytesVal = "";
+            else {
+                object.bytesVal = [];
+                if (options.bytes !== Array)
+                    object.bytesVal = $util.newBuffer(object.bytesVal);
+            }
+            object.enumVal = options.enums === String ? "ONE" : 1;
+        }
+        if (message.stringVal != null && message.hasOwnProperty("stringVal"))
+            object.stringVal = message.stringVal;
+        if (message.stringRepeated && message.stringRepeated.length) {
+            object.stringRepeated = [];
+            for (var j = 0; j < message.stringRepeated.length; ++j)
+                object.stringRepeated[j] = message.stringRepeated[j];
+        }
+        if (message.uint64Val != null && message.hasOwnProperty("uint64Val"))
+            if (typeof message.uint64Val === "number")
+                object.uint64Val = options.longs === String ? String(message.uint64Val) : message.uint64Val;
+            else
+                object.uint64Val = options.longs === String ? $util.Long.prototype.toString.call(message.uint64Val) : options.longs === Number ? new $util.LongBits(message.uint64Val.low >>> 0, message.uint64Val.high >>> 0).toNumber(true) : message.uint64Val;
+        if (message.uint64Repeated && message.uint64Repeated.length) {
+            object.uint64Repeated = [];
+            for (var j = 0; j < message.uint64Repeated.length; ++j)
+                if (typeof message.uint64Repeated[j] === "number")
+                    object.uint64Repeated[j] = options.longs === String ? String(message.uint64Repeated[j]) : message.uint64Repeated[j];
+                else
+                    object.uint64Repeated[j] = options.longs === String ? $util.Long.prototype.toString.call(message.uint64Repeated[j]) : options.longs === Number ? new $util.LongBits(message.uint64Repeated[j].low >>> 0, message.uint64Repeated[j].high >>> 0).toNumber(true) : message.uint64Repeated[j];
+        }
+        if (message.bytesVal != null && message.hasOwnProperty("bytesVal"))
+            object.bytesVal = options.bytes === String ? $util.base64.encode(message.bytesVal, 0, message.bytesVal.length) : options.bytes === Array ? Array.prototype.slice.call(message.bytesVal) : message.bytesVal;
+        if (message.bytesRepeated && message.bytesRepeated.length) {
+            object.bytesRepeated = [];
+            for (var j = 0; j < message.bytesRepeated.length; ++j)
+                object.bytesRepeated[j] = options.bytes === String ? $util.base64.encode(message.bytesRepeated[j], 0, message.bytesRepeated[j].length) : options.bytes === Array ? Array.prototype.slice.call(message.bytesRepeated[j]) : message.bytesRepeated[j];
+        }
+        if (message.enumVal != null && message.hasOwnProperty("enumVal"))
+            object.enumVal = options.enums === String ? $root.Message.SomeEnum[message.enumVal] : message.enumVal;
+        if (message.enumRepeated && message.enumRepeated.length) {
+            object.enumRepeated = [];
+            for (var j = 0; j < message.enumRepeated.length; ++j)
+                object.enumRepeated[j] = options.enums === String ? $root.Message.SomeEnum[message.enumRepeated[j]] : message.enumRepeated[j];
+        }
+        var keys2;
+        if (message.int64Map && (keys2 = Object.keys(message.int64Map)).length) {
+            object.int64Map = {};
+            for (var j = 0; j < keys2.length; ++j)
+                if (typeof message.int64Map[keys2[j]] === "number")
+                    object.int64Map[keys2[j]] = options.longs === String ? String(message.int64Map[keys2[j]]) : message.int64Map[keys2[j]];
+                else
+                    object.int64Map[keys2[j]] = options.longs === String ? $util.Long.prototype.toString.call(message.int64Map[keys2[j]]) : options.longs === Number ? new $util.LongBits(message.int64Map[keys2[j]].low >>> 0, message.int64Map[keys2[j]].high >>> 0).toNumber() : message.int64Map[keys2[j]];
+        }
+        return object;
+    };
+
+    /**
+     * Converts this Message to JSON.
+     * @function toJSON
+     * @memberof Message
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    Message.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    /**
+     * Gets the default type url for Message
+     * @function getTypeUrl
+     * @memberof Message
+     * @static
+     * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+     * @returns {string} The default type url
+     */
+    Message.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+        if (typeUrlPrefix === undefined) {
+            typeUrlPrefix = "type.googleapis.com";
+        }
+        return typeUrlPrefix + "/Message";
+    };
+
+    /**
+     * SomeEnum enum.
+     * @name Message.SomeEnum
+     * @enum {number}
+     * @property {number} ONE=1 ONE value
+     * @property {number} TWO=2 TWO value
+     */
+    Message.SomeEnum = (function() {
+        var valuesById = {}, values = Object.create(valuesById);
+        values[valuesById[1] = "ONE"] = 1;
+        values[valuesById[2] = "TWO"] = 2;
+        return values;
+    })();
+
+    return Message;
+})();
+
+module.exports = $root;
diff --git a/tests/data/convert.proto b/tests/data/convert.proto
new file mode 100644
index 0000000..dbb89ee
--- /dev/null
+++ b/tests/data/convert.proto
@@ -0,0 +1,23 @@
+syntax = "proto3";
+
+message Message {
+
+    string string_val = 1;
+    repeated string string_repeated = 2;
+
+    uint64 uint64_val = 3;
+    repeated uint64 uint64_repeated = 4;
+
+    bytes bytes_val = 5;
+    repeated bytes bytes_repeated = 6;
+
+    SomeEnum enum_val = 7;
+    repeated SomeEnum enum_repeated = 8;
+
+    enum SomeEnum {
+        ONE = 1;
+        TWO = 2;
+    }
+
+    map<string,int64> int64_map = 9;
+}
diff --git a/tests/data/google/protobuf/LICENSE b/tests/data/google/protobuf/LICENSE
new file mode 100644
index 0000000..868bd40
--- /dev/null
+++ b/tests/data/google/protobuf/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.
diff --git a/tests/data/google/protobuf/descriptor.proto b/tests/data/google/protobuf/descriptor.proto
new file mode 100644
index 0000000..747d90c
--- /dev/null
+++ b/tests/data/google/protobuf/descriptor.proto
@@ -0,0 +1,816 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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 Google 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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// The messages in this file describe the definitions found in .proto files.
+// A valid .proto file can be translated directly to a FileDescriptorProto
+// without any other information (e.g. without reading its imports).
+
+
+syntax = "proto2";
+
+package google.protobuf;
+option go_package = "descriptor";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DescriptorProtos";
+option csharp_namespace = "Google.Protobuf.Reflection";
+option objc_class_prefix = "GPB";
+
+// descriptor.proto must be optimized for speed because reflection-based
+// algorithms don't work during bootstrapping.
+option optimize_for = SPEED;
+
+// The protocol compiler can output a FileDescriptorSet containing the .proto
+// files it parses.
+message FileDescriptorSet {
+  repeated FileDescriptorProto file = 1;
+}
+
+// Describes a complete .proto file.
+message FileDescriptorProto {
+  optional string name = 1;       // file name, relative to root of source tree
+  optional string package = 2;    // e.g. "foo", "foo.bar", etc.
+
+  // Names of files imported by this file.
+  repeated string dependency = 3;
+  // Indexes of the public imported files in the dependency list above.
+  repeated int32 public_dependency = 10;
+  // Indexes of the weak imported files in the dependency list.
+  // For Google-internal migration only. Do not use.
+  repeated int32 weak_dependency = 11;
+
+  // All top-level definitions in this file.
+  repeated DescriptorProto message_type = 4;
+  repeated EnumDescriptorProto enum_type = 5;
+  repeated ServiceDescriptorProto service = 6;
+  repeated FieldDescriptorProto extension = 7;
+
+  optional FileOptions options = 8;
+
+  // This field contains optional information about the original source code.
+  // You may safely remove this entire field without harming runtime
+  // functionality of the descriptors -- the information is needed only by
+  // development tools.
+  optional SourceCodeInfo source_code_info = 9;
+
+  // The syntax of the proto file.
+  // The supported values are "proto2" and "proto3".
+  optional string syntax = 12;
+}
+
+// Describes a message type.
+message DescriptorProto {
+  optional string name = 1;
+
+  repeated FieldDescriptorProto field = 2;
+  repeated FieldDescriptorProto extension = 6;
+
+  repeated DescriptorProto nested_type = 3;
+  repeated EnumDescriptorProto enum_type = 4;
+
+  message ExtensionRange {
+    optional int32 start = 1;
+    optional int32 end = 2;
+  }
+  repeated ExtensionRange extension_range = 5;
+
+  repeated OneofDescriptorProto oneof_decl = 8;
+
+  optional MessageOptions options = 7;
+
+  // Range of reserved tag numbers. Reserved tag numbers may not be used by
+  // fields or extension ranges in the same message. Reserved ranges may
+  // not overlap.
+  message ReservedRange {
+    optional int32 start = 1; // Inclusive.
+    optional int32 end = 2;   // Exclusive.
+  }
+  repeated ReservedRange reserved_range = 9;
+  // Reserved field names, which may not be used by fields in the same message.
+  // A given name may only be reserved once.
+  repeated string reserved_name = 10;
+}
+
+// Describes a field within a message.
+message FieldDescriptorProto {
+  enum Type {
+    // 0 is reserved for errors.
+    // Order is weird for historical reasons.
+    TYPE_DOUBLE         = 1;
+    TYPE_FLOAT          = 2;
+    // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT64 if
+    // negative values are likely.
+    TYPE_INT64          = 3;
+    TYPE_UINT64         = 4;
+    // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT32 if
+    // negative values are likely.
+    TYPE_INT32          = 5;
+    TYPE_FIXED64        = 6;
+    TYPE_FIXED32        = 7;
+    TYPE_BOOL           = 8;
+    TYPE_STRING         = 9;
+    TYPE_GROUP          = 10;  // Tag-delimited aggregate.
+    TYPE_MESSAGE        = 11;  // Length-delimited aggregate.
+
+    // New in version 2.
+    TYPE_BYTES          = 12;
+    TYPE_UINT32         = 13;
+    TYPE_ENUM           = 14;
+    TYPE_SFIXED32       = 15;
+    TYPE_SFIXED64       = 16;
+    TYPE_SINT32         = 17;  // Uses ZigZag encoding.
+    TYPE_SINT64         = 18;  // Uses ZigZag encoding.
+  };
+
+  enum Label {
+    // 0 is reserved for errors
+    LABEL_OPTIONAL      = 1;
+    LABEL_REQUIRED      = 2;
+    LABEL_REPEATED      = 3;
+  };
+
+  optional string name = 1;
+  optional int32 number = 3;
+  optional Label label = 4;
+
+  // If type_name is set, this need not be set.  If both this and type_name
+  // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
+  optional Type type = 5;
+
+  // For message and enum types, this is the name of the type.  If the name
+  // starts with a '.', it is fully-qualified.  Otherwise, C++-like scoping
+  // rules are used to find the type (i.e. first the nested types within this
+  // message are searched, then within the parent, on up to the root
+  // namespace).
+  optional string type_name = 6;
+
+  // For extensions, this is the name of the type being extended.  It is
+  // resolved in the same manner as type_name.
+  optional string extendee = 2;
+
+  // For numeric types, contains the original text representation of the value.
+  // For booleans, "true" or "false".
+  // For strings, contains the default text contents (not escaped in any way).
+  // For bytes, contains the C escaped value.  All bytes >= 128 are escaped.
+  // TODO(kenton):  Base-64 encode?
+  optional string default_value = 7;
+
+  // If set, gives the index of a oneof in the containing type's oneof_decl
+  // list.  This field is a member of that oneof.
+  optional int32 oneof_index = 9;
+
+  // JSON name of this field. The value is set by protocol compiler. If the
+  // user has set a "json_name" option on this field, that option's value
+  // will be used. Otherwise, it's deduced from the field's name by converting
+  // it to camelCase.
+  optional string json_name = 10;
+
+  optional FieldOptions options = 8;
+}
+
+// Describes a oneof.
+message OneofDescriptorProto {
+  optional string name = 1;
+  optional OneofOptions options = 2;
+}
+
+// Describes an enum type.
+message EnumDescriptorProto {
+  optional string name = 1;
+
+  repeated EnumValueDescriptorProto value = 2;
+
+  optional EnumOptions options = 3;
+}
+
+// Describes a value within an enum.
+message EnumValueDescriptorProto {
+  optional string name = 1;
+  optional int32 number = 2;
+
+  optional EnumValueOptions options = 3;
+}
+
+// Describes a service.
+message ServiceDescriptorProto {
+  optional string name = 1;
+  repeated MethodDescriptorProto method = 2;
+
+  optional ServiceOptions options = 3;
+}
+
+// Describes a method of a service.
+message MethodDescriptorProto {
+  optional string name = 1;
+
+  // Input and output type names.  These are resolved in the same way as
+  // FieldDescriptorProto.type_name, but must refer to a message type.
+  optional string input_type = 2;
+  optional string output_type = 3;
+
+  optional MethodOptions options = 4;
+
+  // Identifies if client streams multiple client messages
+  optional bool client_streaming = 5 [default=false];
+  // Identifies if server streams multiple server messages
+  optional bool server_streaming = 6 [default=false];
+}
+
+
+// ===================================================================
+// Options
+
+// Each of the definitions above may have "options" attached.  These are
+// just annotations which may cause code to be generated slightly differently
+// or may contain hints for code that manipulates protocol messages.
+//
+// Clients may define custom options as extensions of the *Options messages.
+// These extensions may not yet be known at parsing time, so the parser cannot
+// store the values in them.  Instead it stores them in a field in the *Options
+// message called uninterpreted_option. This field must have the same name
+// across all *Options messages. We then use this field to populate the
+// extensions when we build a descriptor, at which point all protos have been
+// parsed and so all extensions are known.
+//
+// Extension numbers for custom options may be chosen as follows:
+// * For options which will only be used within a single application or
+//   organization, or for experimental options, use field numbers 50000
+//   through 99999.  It is up to you to ensure that you do not use the
+//   same number for multiple options.
+// * For options which will be published and used publicly by multiple
+//   independent entities, e-mail protobuf-global-extension-registry@google.com
+//   to reserve extension numbers. Simply provide your project name (e.g.
+//   Objective-C plugin) and your project website (if available) -- there's no
+//   need to explain how you intend to use them. Usually you only need one
+//   extension number. You can declare multiple options with only one extension
+//   number by putting them in a sub-message. See the Custom Options section of
+//   the docs for examples:
+//   https://developers.google.com/protocol-buffers/docs/proto#options
+//   If this turns out to be popular, a web service will be set up
+//   to automatically assign option numbers.
+
+
+message FileOptions {
+
+  // Sets the Java package where classes generated from this .proto will be
+  // placed.  By default, the proto package is used, but this is often
+  // inappropriate because proto packages do not normally start with backwards
+  // domain names.
+  optional string java_package = 1;
+
+
+  // If set, all the classes from the .proto file are wrapped in a single
+  // outer class with the given name.  This applies to both Proto1
+  // (equivalent to the old "--one_java_file" option) and Proto2 (where
+  // a .proto always translates to a single class, but you may want to
+  // explicitly choose the class name).
+  optional string java_outer_classname = 8;
+
+  // If set true, then the Java code generator will generate a separate .java
+  // file for each top-level message, enum, and service defined in the .proto
+  // file.  Thus, these types will *not* be nested inside the outer class
+  // named by java_outer_classname.  However, the outer class will still be
+  // generated to contain the file's getDescriptor() method as well as any
+  // top-level extensions defined in the file.
+  optional bool java_multiple_files = 10 [default=false];
+
+  // This option does nothing.
+  optional bool java_generate_equals_and_hash = 20 [deprecated=true];
+
+  // If set true, then the Java2 code generator will generate code that
+  // throws an exception whenever an attempt is made to assign a non-UTF-8
+  // byte sequence to a string field.
+  // Message reflection will do the same.
+  // However, an extension field still accepts non-UTF-8 byte sequences.
+  // This option has no effect on when used with the lite runtime.
+  optional bool java_string_check_utf8 = 27 [default=false];
+
+
+  // Generated classes can be optimized for speed or code size.
+  enum OptimizeMode {
+    SPEED = 1;        // Generate complete code for parsing, serialization,
+                      // etc.
+    CODE_SIZE = 2;    // Use ReflectionOps to implement these methods.
+    LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
+  }
+  optional OptimizeMode optimize_for = 9 [default=SPEED];
+
+  // Sets the Go package where structs generated from this .proto will be
+  // placed. If omitted, the Go package will be derived from the following:
+  //   - The basename of the package import path, if provided.
+  //   - Otherwise, the package statement in the .proto file, if present.
+  //   - Otherwise, the basename of the .proto file, without extension.
+  optional string go_package = 11;
+
+
+
+  // Should generic services be generated in each language?  "Generic" services
+  // are not specific to any particular RPC system.  They are generated by the
+  // main code generators in each language (without additional plugins).
+  // Generic services were the only kind of service generation supported by
+  // early versions of google.protobuf.
+  //
+  // Generic services are now considered deprecated in favor of using plugins
+  // that generate code specific to your particular RPC system.  Therefore,
+  // these default to false.  Old code which depends on generic services should
+  // explicitly set them to true.
+  optional bool cc_generic_services = 16 [default=false];
+  optional bool java_generic_services = 17 [default=false];
+  optional bool py_generic_services = 18 [default=false];
+
+  // Is this file deprecated?
+  // Depending on the target platform, this can emit Deprecated annotations
+  // for everything in the file, or it will be completely ignored; in the very
+  // least, this is a formalization for deprecating files.
+  optional bool deprecated = 23 [default=false];
+
+  // Enables the use of arenas for the proto messages in this file. This applies
+  // only to generated classes for C++.
+  optional bool cc_enable_arenas = 31 [default=false];
+
+
+  // Sets the objective c class prefix which is prepended to all objective c
+  // generated classes from this .proto. There is no default.
+  optional string objc_class_prefix = 36;
+
+  // Namespace for generated classes; defaults to the package.
+  optional string csharp_namespace = 37;
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+
+  reserved 38;
+}
+
+message MessageOptions {
+  // Set true to use the old proto1 MessageSet wire format for extensions.
+  // This is provided for backwards-compatibility with the MessageSet wire
+  // format.  You should not use this for any other reason:  It's less
+  // efficient, has fewer features, and is more complicated.
+  //
+  // The message must be defined exactly as follows:
+  //   message Foo {
+  //     option message_set_wire_format = true;
+  //     extensions 4 to max;
+  //   }
+  // Note that the message cannot have any defined fields; MessageSets only
+  // have extensions.
+  //
+  // All extensions of your type must be singular messages; e.g. they cannot
+  // be int32s, enums, or repeated messages.
+  //
+  // Because this is an option, the above two restrictions are not enforced by
+  // the protocol compiler.
+  optional bool message_set_wire_format = 1 [default=false];
+
+  // Disables the generation of the standard "descriptor()" accessor, which can
+  // conflict with a field of the same name.  This is meant to make migration
+  // from proto1 easier; new code should avoid fields named "descriptor".
+  optional bool no_standard_descriptor_accessor = 2 [default=false];
+
+  // Is this message deprecated?
+  // Depending on the target platform, this can emit Deprecated annotations
+  // for the message, or it will be completely ignored; in the very least,
+  // this is a formalization for deprecating messages.
+  optional bool deprecated = 3 [default=false];
+
+  // Whether the message is an automatically generated map entry type for the
+  // maps field.
+  //
+  // For maps fields:
+  //     map<KeyType, ValueType> map_field = 1;
+  // The parsed descriptor looks like:
+  //     message MapFieldEntry {
+  //         option map_entry = true;
+  //         optional KeyType key = 1;
+  //         optional ValueType value = 2;
+  //     }
+  //     repeated MapFieldEntry map_field = 1;
+  //
+  // Implementations may choose not to generate the map_entry=true message, but
+  // use a native map in the target language to hold the keys and values.
+  // The reflection APIs in such implementions still need to work as
+  // if the field is a repeated message field.
+  //
+  // NOTE: Do not set the option in .proto files. Always use the maps syntax
+  // instead. The option should only be implicitly set by the proto compiler
+  // parser.
+  optional bool map_entry = 7;
+
+  reserved 8;  // javalite_serializable
+
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message FieldOptions {
+  // The ctype option instructs the C++ code generator to use a different
+  // representation of the field than it normally would.  See the specific
+  // options below.  This option is not yet implemented in the open source
+  // release -- sorry, we'll try to include it in a future version!
+  optional CType ctype = 1 [default = STRING];
+  enum CType {
+    // Default mode.
+    STRING = 0;
+
+    CORD = 1;
+
+    STRING_PIECE = 2;
+  }
+  // The packed option can be enabled for repeated primitive fields to enable
+  // a more efficient representation on the wire. Rather than repeatedly
+  // writing the tag and type for each element, the entire array is encoded as
+  // a single length-delimited blob. In proto3, only explicit setting it to
+  // false will avoid using packed encoding.
+  optional bool packed = 2;
+
+  // The jstype option determines the JavaScript type used for values of the
+  // field.  The option is permitted only for 64 bit integral and fixed types
+  // (int64, uint64, sint64, fixed64, sfixed64).  By default these types are
+  // represented as JavaScript strings.  This avoids loss of precision that can
+  // happen when a large value is converted to a floating point JavaScript
+  // numbers.  Specifying JS_NUMBER for the jstype causes the generated
+  // JavaScript code to use the JavaScript "number" type instead of strings.
+  // This option is an enum to permit additional types to be added,
+  // e.g. goog.math.Integer.
+  optional JSType jstype = 6 [default = JS_NORMAL];
+  enum JSType {
+    // Use the default type.
+    JS_NORMAL = 0;
+
+    // Use JavaScript strings.
+    JS_STRING = 1;
+
+    // Use JavaScript numbers.
+    JS_NUMBER = 2;
+  }
+
+  // Should this field be parsed lazily?  Lazy applies only to message-type
+  // fields.  It means that when the outer message is initially parsed, the
+  // inner message's contents will not be parsed but instead stored in encoded
+  // form.  The inner message will actually be parsed when it is first accessed.
+  //
+  // This is only a hint.  Implementations are free to choose whether to use
+  // eager or lazy parsing regardless of the value of this option.  However,
+  // setting this option true suggests that the protocol author believes that
+  // using lazy parsing on this field is worth the additional bookkeeping
+  // overhead typically needed to implement it.
+  //
+  // This option does not affect the public interface of any generated code;
+  // all method signatures remain the same.  Furthermore, thread-safety of the
+  // interface is not affected by this option; const methods remain safe to
+  // call from multiple threads concurrently, while non-const methods continue
+  // to require exclusive access.
+  //
+  //
+  // Note that implementations may choose not to check required fields within
+  // a lazy sub-message.  That is, calling IsInitialized() on the outer message
+  // may return true even if the inner message has missing required fields.
+  // This is necessary because otherwise the inner message would have to be
+  // parsed in order to perform the check, defeating the purpose of lazy
+  // parsing.  An implementation which chooses not to check required fields
+  // must be consistent about it.  That is, for any particular sub-message, the
+  // implementation must either *always* check its required fields, or *never*
+  // check its required fields, regardless of whether or not the message has
+  // been parsed.
+  optional bool lazy = 5 [default=false];
+
+  // Is this field deprecated?
+  // Depending on the target platform, this can emit Deprecated annotations
+  // for accessors, or it will be completely ignored; in the very least, this
+  // is a formalization for deprecating fields.
+  optional bool deprecated = 3 [default=false];
+
+  // For Google-internal migration only. Do not use.
+  optional bool weak = 10 [default=false];
+
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+
+  reserved 4;  // removed jtype
+}
+
+message OneofOptions {
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message EnumOptions {
+
+  // Set this option to true to allow mapping different tag names to the same
+  // value.
+  optional bool allow_alias = 2;
+
+  // Is this enum deprecated?
+  // Depending on the target platform, this can emit Deprecated annotations
+  // for the enum, or it will be completely ignored; in the very least, this
+  // is a formalization for deprecating enums.
+  optional bool deprecated = 3 [default=false];
+
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message EnumValueOptions {
+  // Is this enum value deprecated?
+  // Depending on the target platform, this can emit Deprecated annotations
+  // for the enum value, or it will be completely ignored; in the very least,
+  // this is a formalization for deprecating enum values.
+  optional bool deprecated = 1 [default=false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message ServiceOptions {
+
+  // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
+  //   framework.  We apologize for hoarding these numbers to ourselves, but
+  //   we were already using them long before we decided to release Protocol
+  //   Buffers.
+
+  // Is this service deprecated?
+  // Depending on the target platform, this can emit Deprecated annotations
+  // for the service, or it will be completely ignored; in the very least,
+  // this is a formalization for deprecating services.
+  optional bool deprecated = 33 [default=false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message MethodOptions {
+
+  // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
+  //   framework.  We apologize for hoarding these numbers to ourselves, but
+  //   we were already using them long before we decided to release Protocol
+  //   Buffers.
+
+  // Is this method deprecated?
+  // Depending on the target platform, this can emit Deprecated annotations
+  // for the method, or it will be completely ignored; in the very least,
+  // this is a formalization for deprecating methods.
+  optional bool deprecated = 33 [default=false];
+
+  // Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
+  // or neither? HTTP based RPC implementation may choose GET verb for safe
+  // methods, and PUT verb for idempotent methods instead of the default POST.
+  enum IdempotencyLevel {
+    IDEMPOTENCY_UNKNOWN = 0;
+    NO_SIDE_EFFECTS     = 1; // implies idempotent
+    IDEMPOTENT          = 2; // idempotent, but may have side effects
+  }
+  optional IdempotencyLevel idempotency_level =
+      34 [default=IDEMPOTENCY_UNKNOWN];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+
+// A message representing a option the parser does not recognize. This only
+// appears in options protos created by the compiler::Parser class.
+// DescriptorPool resolves these when building Descriptor objects. Therefore,
+// options protos in descriptor objects (e.g. returned by Descriptor::options(),
+// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
+// in them.
+message UninterpretedOption {
+  // The name of the uninterpreted option.  Each string represents a segment in
+  // a dot-separated name.  is_extension is true iff a segment represents an
+  // extension (denoted with parentheses in options specs in .proto files).
+  // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
+  // "foo.(bar.baz).qux".
+  message NamePart {
+    required string name_part = 1;
+    required bool is_extension = 2;
+  }
+  repeated NamePart name = 2;
+
+  // The value of the uninterpreted option, in whatever type the tokenizer
+  // identified it as during parsing. Exactly one of these should be set.
+  optional string identifier_value = 3;
+  optional uint64 positive_int_value = 4;
+  optional int64 negative_int_value = 5;
+  optional double double_value = 6;
+  optional bytes string_value = 7;
+  optional string aggregate_value = 8;
+}
+
+// ===================================================================
+// Optional source code info
+
+// Encapsulates information about the original source file from which a
+// FileDescriptorProto was generated.
+message SourceCodeInfo {
+  // A Location identifies a piece of source code in a .proto file which
+  // corresponds to a particular definition.  This information is intended
+  // to be useful to IDEs, code indexers, documentation generators, and similar
+  // tools.
+  //
+  // For example, say we have a file like:
+  //   message Foo {
+  //     optional string foo = 1;
+  //   }
+  // Let's look at just the field definition:
+  //   optional string foo = 1;
+  //   ^       ^^     ^^  ^  ^^^
+  //   a       bc     de  f  ghi
+  // We have the following locations:
+  //   span   path               represents
+  //   [a,i)  [ 4, 0, 2, 0 ]     The whole field definition.
+  //   [a,b)  [ 4, 0, 2, 0, 4 ]  The label (optional).
+  //   [c,d)  [ 4, 0, 2, 0, 5 ]  The type (string).
+  //   [e,f)  [ 4, 0, 2, 0, 1 ]  The name (foo).
+  //   [g,h)  [ 4, 0, 2, 0, 3 ]  The number (1).
+  //
+  // Notes:
+  // - A location may refer to a repeated field itself (i.e. not to any
+  //   particular index within it).  This is used whenever a set of elements are
+  //   logically enclosed in a single code segment.  For example, an entire
+  //   extend block (possibly containing multiple extension definitions) will
+  //   have an outer location whose path refers to the "extensions" repeated
+  //   field without an index.
+  // - Multiple locations may have the same path.  This happens when a single
+  //   logical declaration is spread out across multiple places.  The most
+  //   obvious example is the "extend" block again -- there may be multiple
+  //   extend blocks in the same scope, each of which will have the same path.
+  // - A location's span is not always a subset of its parent's span.  For
+  //   example, the "extendee" of an extension declaration appears at the
+  //   beginning of the "extend" block and is shared by all extensions within
+  //   the block.
+  // - Just because a location's span is a subset of some other location's span
+  //   does not mean that it is a descendent.  For example, a "group" defines
+  //   both a type and a field in a single declaration.  Thus, the locations
+  //   corresponding to the type and field and their components will overlap.
+  // - Code which tries to interpret locations should probably be designed to
+  //   ignore those that it doesn't understand, as more types of locations could
+  //   be recorded in the future.
+  repeated Location location = 1;
+  message Location {
+    // Identifies which part of the FileDescriptorProto was defined at this
+    // location.
+    //
+    // Each element is a field number or an index.  They form a path from
+    // the root FileDescriptorProto to the place where the definition.  For
+    // example, this path:
+    //   [ 4, 3, 2, 7, 1 ]
+    // refers to:
+    //   file.message_type(3)  // 4, 3
+    //       .field(7)         // 2, 7
+    //       .name()           // 1
+    // This is because FileDescriptorProto.message_type has field number 4:
+    //   repeated DescriptorProto message_type = 4;
+    // and DescriptorProto.field has field number 2:
+    //   repeated FieldDescriptorProto field = 2;
+    // and FieldDescriptorProto.name has field number 1:
+    //   optional string name = 1;
+    //
+    // Thus, the above path gives the location of a field name.  If we removed
+    // the last element:
+    //   [ 4, 3, 2, 7 ]
+    // this path refers to the whole field declaration (from the beginning
+    // of the label to the terminating semicolon).
+    repeated int32 path = 1 [packed=true];
+
+    // Always has exactly three or four elements: start line, start column,
+    // end line (optional, otherwise assumed same as start line), end column.
+    // These are packed into a single field for efficiency.  Note that line
+    // and column numbers are zero-based -- typically you will want to add
+    // 1 to each before displaying to a user.
+    repeated int32 span = 2 [packed=true];
+
+    // If this SourceCodeInfo represents a complete declaration, these are any
+    // comments appearing before and after the declaration which appear to be
+    // attached to the declaration.
+    //
+    // A series of line comments appearing on consecutive lines, with no other
+    // tokens appearing on those lines, will be treated as a single comment.
+    //
+    // leading_detached_comments will keep paragraphs of comments that appear
+    // before (but not connected to) the current element. Each paragraph,
+    // separated by empty lines, will be one comment element in the repeated
+    // field.
+    //
+    // Only the comment content is provided; comment markers (e.g. //) are
+    // stripped out.  For block comments, leading whitespace and an asterisk
+    // will be stripped from the beginning of each line other than the first.
+    // Newlines are included in the output.
+    //
+    // Examples:
+    //
+    //   optional int32 foo = 1;  // Comment attached to foo.
+    //   // Comment attached to bar.
+    //   optional int32 bar = 2;
+    //
+    //   optional string baz = 3;
+    //   // Comment attached to baz.
+    //   // Another line attached to baz.
+    //
+    //   // Comment attached to qux.
+    //   //
+    //   // Another line attached to qux.
+    //   optional double qux = 4;
+    //
+    //   // Detached comment for corge. This is not leading or trailing comments
+    //   // to qux or corge because there are blank lines separating it from
+    //   // both.
+    //
+    //   // Detached comment for corge paragraph 2.
+    //
+    //   optional string corge = 5;
+    //   /* Block comment attached
+    //    * to corge.  Leading asterisks
+    //    * will be removed. */
+    //   /* Block comment attached to
+    //    * grault. */
+    //   optional int32 grault = 6;
+    //
+    //   // ignored detached comments.
+    optional string leading_comments = 3;
+    optional string trailing_comments = 4;
+    repeated string leading_detached_comments = 6;
+  }
+}
+
+// Describes the relationship between generated code and its original source
+// file. A GeneratedCodeInfo message is associated with only one generated
+// source file, but may contain references to different source .proto files.
+message GeneratedCodeInfo {
+  // An Annotation connects some span of text in generated code to an element
+  // of its generating .proto file.
+  repeated Annotation annotation = 1;
+  message Annotation {
+    // Identifies the element in the original source .proto file. This field
+    // is formatted the same as SourceCodeInfo.Location.path.
+    repeated int32 path = 1 [packed=true];
+
+    // Identifies the filesystem path to the original source .proto.
+    optional string source_file = 2;
+
+    // Identifies the starting offset in bytes in the generated code
+    // that relates to the identified object.
+    optional int32 begin = 3;
+
+    // Identifies the ending offset in bytes in the generated code that
+    // relates to the identified offset. The end offset should be one past
+    // the last relevant byte (so the length of the text = end - begin).
+    optional int32 end = 4;
+  }
+}
\ No newline at end of file
diff --git a/tests/data/invalid.json b/tests/data/invalid.json
new file mode 100644
index 0000000..4c58f56
--- /dev/null
+++ b/tests/data/invalid.json
@@ -0,0 +1,4 @@
+{
+    "nested": {
+        "Test": {
+            "fields": {
diff --git a/tests/data/invalid.proto b/tests/data/invalid.proto
new file mode 100644
index 0000000..793d3b2
--- /dev/null
+++ b/tests/data/invalid.proto
@@ -0,0 +1 @@
+message Test {
\ No newline at end of file
diff --git a/tests/data/issue936.proto b/tests/data/issue936.proto
new file mode 100644
index 0000000..b900e06
--- /dev/null
+++ b/tests/data/issue936.proto
@@ -0,0 +1,8 @@
+message Meta {
+  extensions 10 to 20;
+}
+
+extend Meta {
+  required string workflow_id = 10;
+  required string task_id = 11;
+}
diff --git a/tests/data/mapbox/LICENSE b/tests/data/mapbox/LICENSE
new file mode 100644
index 0000000..54b5f9a
--- /dev/null
+++ b/tests/data/mapbox/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2016, Mapbox
+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 pbf 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.
diff --git a/tests/data/mapbox/vector_tile.bin b/tests/data/mapbox/vector_tile.bin
new file mode 100644
index 0000000..5d375f6
--- /dev/null
+++ b/tests/data/mapbox/vector_tile.bin
Binary files differ
diff --git a/tests/data/mapbox/vector_tile.d.ts b/tests/data/mapbox/vector_tile.d.ts
new file mode 100644
index 0000000..c11da06
--- /dev/null
+++ b/tests/data/mapbox/vector_tile.d.ts
@@ -0,0 +1,119 @@
+import * as $protobuf from "../../..";
+import Long from "long";
+
+export namespace vector_tile {
+
+    interface ITile {
+        layers?: (vector_tile.Tile.ILayer[]|null);
+    }
+
+    class Tile implements ITile {
+        constructor(properties?: vector_tile.ITile);
+        public layers: vector_tile.Tile.ILayer[];
+        public static create(properties?: vector_tile.ITile): vector_tile.Tile;
+        public static encode(message: vector_tile.ITile, writer?: $protobuf.Writer): $protobuf.Writer;
+        public static encodeDelimited(message: vector_tile.ITile, writer?: $protobuf.Writer): $protobuf.Writer;
+        public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): vector_tile.Tile;
+        public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): vector_tile.Tile;
+        public static verify(message: { [k: string]: any }): (string|null);
+        public static fromObject(object: { [k: string]: any }): vector_tile.Tile;
+        public static toObject(message: vector_tile.Tile, options?: $protobuf.IConversionOptions): { [k: string]: any };
+        public toJSON(): { [k: string]: any };
+        public static getTypeUrl(typeUrlPrefix?: string): string;
+    }
+
+    namespace Tile {
+
+        enum GeomType {
+            UNKNOWN = 0,
+            POINT = 1,
+            LINESTRING = 2,
+            POLYGON = 3
+        }
+
+        interface IValue {
+            stringValue?: (string|null);
+            floatValue?: (number|null);
+            doubleValue?: (number|null);
+            intValue?: (number|Long|null);
+            uintValue?: (number|Long|null);
+            sintValue?: (number|Long|null);
+            boolValue?: (boolean|null);
+        }
+
+        class Value implements IValue {
+            constructor(properties?: vector_tile.Tile.IValue);
+            public stringValue: string;
+            public floatValue: number;
+            public doubleValue: number;
+            public intValue: (number|Long);
+            public uintValue: (number|Long);
+            public sintValue: (number|Long);
+            public boolValue: boolean;
+            public static create(properties?: vector_tile.Tile.IValue): vector_tile.Tile.Value;
+            public static encode(message: vector_tile.Tile.IValue, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: vector_tile.Tile.IValue, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): vector_tile.Tile.Value;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): vector_tile.Tile.Value;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): vector_tile.Tile.Value;
+            public static toObject(message: vector_tile.Tile.Value, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IFeature {
+            id?: (number|Long|null);
+            tags?: (number[]|null);
+            type?: (vector_tile.Tile.GeomType|null);
+            geometry?: (number[]|null);
+        }
+
+        class Feature implements IFeature {
+            constructor(properties?: vector_tile.Tile.IFeature);
+            public id: (number|Long);
+            public tags: number[];
+            public type: vector_tile.Tile.GeomType;
+            public geometry: number[];
+            public static create(properties?: vector_tile.Tile.IFeature): vector_tile.Tile.Feature;
+            public static encode(message: vector_tile.Tile.IFeature, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: vector_tile.Tile.IFeature, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): vector_tile.Tile.Feature;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): vector_tile.Tile.Feature;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): vector_tile.Tile.Feature;
+            public static toObject(message: vector_tile.Tile.Feature, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface ILayer {
+            version: number;
+            name: string;
+            features?: (vector_tile.Tile.IFeature[]|null);
+            keys?: (string[]|null);
+            values?: (vector_tile.Tile.IValue[]|null);
+            extent?: (number|null);
+        }
+
+        class Layer implements ILayer {
+            constructor(properties?: vector_tile.Tile.ILayer);
+            public version: number;
+            public name: string;
+            public features: vector_tile.Tile.IFeature[];
+            public keys: string[];
+            public values: vector_tile.Tile.IValue[];
+            public extent: number;
+            public static create(properties?: vector_tile.Tile.ILayer): vector_tile.Tile.Layer;
+            public static encode(message: vector_tile.Tile.ILayer, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: vector_tile.Tile.ILayer, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): vector_tile.Tile.Layer;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): vector_tile.Tile.Layer;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): vector_tile.Tile.Layer;
+            public static toObject(message: vector_tile.Tile.Layer, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+    }
+}
diff --git a/tests/data/mapbox/vector_tile.js b/tests/data/mapbox/vector_tile.js
new file mode 100644
index 0000000..134aaae
--- /dev/null
+++ b/tests/data/mapbox/vector_tile.js
@@ -0,0 +1,1371 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+"use strict";
+
+var $protobuf = require("../../../minimal");
+
+// Common aliases
+var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+// Exported root namespace
+var $root = $protobuf.roots.test_vector_tile || ($protobuf.roots.test_vector_tile = {});
+
+$root.vector_tile = (function() {
+
+    /**
+     * Namespace vector_tile.
+     * @exports vector_tile
+     * @namespace
+     */
+    var vector_tile = {};
+
+    vector_tile.Tile = (function() {
+
+        /**
+         * Properties of a Tile.
+         * @memberof vector_tile
+         * @interface ITile
+         * @property {Array.<vector_tile.Tile.ILayer>|null} [layers] Tile layers
+         */
+
+        /**
+         * Constructs a new Tile.
+         * @memberof vector_tile
+         * @classdesc Represents a Tile.
+         * @implements ITile
+         * @constructor
+         * @param {vector_tile.ITile=} [properties] Properties to set
+         */
+        function Tile(properties) {
+            this.layers = [];
+            if (properties)
+                for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                    if (properties[keys[i]] != null)
+                        this[keys[i]] = properties[keys[i]];
+        }
+
+        /**
+         * Tile layers.
+         * @member {Array.<vector_tile.Tile.ILayer>} layers
+         * @memberof vector_tile.Tile
+         * @instance
+         */
+        Tile.prototype.layers = $util.emptyArray;
+
+        /**
+         * Creates a new Tile instance using the specified properties.
+         * @function create
+         * @memberof vector_tile.Tile
+         * @static
+         * @param {vector_tile.ITile=} [properties] Properties to set
+         * @returns {vector_tile.Tile} Tile instance
+         */
+        Tile.create = function create(properties) {
+            return new Tile(properties);
+        };
+
+        /**
+         * Encodes the specified Tile message. Does not implicitly {@link vector_tile.Tile.verify|verify} messages.
+         * @function encode
+         * @memberof vector_tile.Tile
+         * @static
+         * @param {vector_tile.ITile} message Tile message or plain object to encode
+         * @param {$protobuf.Writer} [writer] Writer to encode to
+         * @returns {$protobuf.Writer} Writer
+         */
+        Tile.encode = function encode(message, writer) {
+            if (!writer)
+                writer = $Writer.create();
+            if (message.layers != null && message.layers.length)
+                for (var i = 0; i < message.layers.length; ++i)
+                    $root.vector_tile.Tile.Layer.encode(message.layers[i], writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim();
+            return writer;
+        };
+
+        /**
+         * Encodes the specified Tile message, length delimited. Does not implicitly {@link vector_tile.Tile.verify|verify} messages.
+         * @function encodeDelimited
+         * @memberof vector_tile.Tile
+         * @static
+         * @param {vector_tile.ITile} message Tile message or plain object to encode
+         * @param {$protobuf.Writer} [writer] Writer to encode to
+         * @returns {$protobuf.Writer} Writer
+         */
+        Tile.encodeDelimited = function encodeDelimited(message, writer) {
+            return this.encode(message, writer).ldelim();
+        };
+
+        /**
+         * Decodes a Tile message from the specified reader or buffer.
+         * @function decode
+         * @memberof vector_tile.Tile
+         * @static
+         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+         * @param {number} [length] Message length if known beforehand
+         * @returns {vector_tile.Tile} Tile
+         * @throws {Error} If the payload is not a reader or valid buffer
+         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+         */
+        Tile.decode = function decode(reader, length) {
+            if (!(reader instanceof $Reader))
+                reader = $Reader.create(reader);
+            var end = length === undefined ? reader.len : reader.pos + length, message = new $root.vector_tile.Tile();
+            while (reader.pos < end) {
+                var tag = reader.uint32();
+                switch (tag >>> 3) {
+                case 3:
+                    if (!(message.layers && message.layers.length))
+                        message.layers = [];
+                    message.layers.push($root.vector_tile.Tile.Layer.decode(reader, reader.uint32()));
+                    break;
+                default:
+                    reader.skipType(tag & 7);
+                    break;
+                }
+            }
+            return message;
+        };
+
+        /**
+         * Decodes a Tile message from the specified reader or buffer, length delimited.
+         * @function decodeDelimited
+         * @memberof vector_tile.Tile
+         * @static
+         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+         * @returns {vector_tile.Tile} Tile
+         * @throws {Error} If the payload is not a reader or valid buffer
+         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+         */
+        Tile.decodeDelimited = function decodeDelimited(reader) {
+            if (!(reader instanceof $Reader))
+                reader = new $Reader(reader);
+            return this.decode(reader, reader.uint32());
+        };
+
+        /**
+         * Verifies a Tile message.
+         * @function verify
+         * @memberof vector_tile.Tile
+         * @static
+         * @param {Object.<string,*>} message Plain object to verify
+         * @returns {string|null} `null` if valid, otherwise the reason why it is not
+         */
+        Tile.verify = function verify(message) {
+            if (typeof message !== "object" || message === null)
+                return "object expected";
+            if (message.layers != null && message.hasOwnProperty("layers")) {
+                if (!Array.isArray(message.layers))
+                    return "layers: array expected";
+                for (var i = 0; i < message.layers.length; ++i) {
+                    var error = $root.vector_tile.Tile.Layer.verify(message.layers[i]);
+                    if (error)
+                        return "layers." + error;
+                }
+            }
+            return null;
+        };
+
+        /**
+         * Creates a Tile message from a plain object. Also converts values to their respective internal types.
+         * @function fromObject
+         * @memberof vector_tile.Tile
+         * @static
+         * @param {Object.<string,*>} object Plain object
+         * @returns {vector_tile.Tile} Tile
+         */
+        Tile.fromObject = function fromObject(object) {
+            if (object instanceof $root.vector_tile.Tile)
+                return object;
+            var message = new $root.vector_tile.Tile();
+            if (object.layers) {
+                if (!Array.isArray(object.layers))
+                    throw TypeError(".vector_tile.Tile.layers: array expected");
+                message.layers = [];
+                for (var i = 0; i < object.layers.length; ++i) {
+                    if (typeof object.layers[i] !== "object")
+                        throw TypeError(".vector_tile.Tile.layers: object expected");
+                    message.layers[i] = $root.vector_tile.Tile.Layer.fromObject(object.layers[i]);
+                }
+            }
+            return message;
+        };
+
+        /**
+         * Creates a plain object from a Tile message. Also converts values to other types if specified.
+         * @function toObject
+         * @memberof vector_tile.Tile
+         * @static
+         * @param {vector_tile.Tile} message Tile
+         * @param {$protobuf.IConversionOptions} [options] Conversion options
+         * @returns {Object.<string,*>} Plain object
+         */
+        Tile.toObject = function toObject(message, options) {
+            if (!options)
+                options = {};
+            var object = {};
+            if (options.arrays || options.defaults)
+                object.layers = [];
+            if (message.layers && message.layers.length) {
+                object.layers = [];
+                for (var j = 0; j < message.layers.length; ++j)
+                    object.layers[j] = $root.vector_tile.Tile.Layer.toObject(message.layers[j], options);
+            }
+            return object;
+        };
+
+        /**
+         * Converts this Tile to JSON.
+         * @function toJSON
+         * @memberof vector_tile.Tile
+         * @instance
+         * @returns {Object.<string,*>} JSON object
+         */
+        Tile.prototype.toJSON = function toJSON() {
+            return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+        };
+
+        /**
+         * Gets the default type url for Tile
+         * @function getTypeUrl
+         * @memberof vector_tile.Tile
+         * @static
+         * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+         * @returns {string} The default type url
+         */
+        Tile.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+            if (typeUrlPrefix === undefined) {
+                typeUrlPrefix = "type.googleapis.com";
+            }
+            return typeUrlPrefix + "/vector_tile.Tile";
+        };
+
+        /**
+         * GeomType enum.
+         * @name vector_tile.Tile.GeomType
+         * @enum {number}
+         * @property {number} UNKNOWN=0 UNKNOWN value
+         * @property {number} POINT=1 POINT value
+         * @property {number} LINESTRING=2 LINESTRING value
+         * @property {number} POLYGON=3 POLYGON value
+         */
+        Tile.GeomType = (function() {
+            var valuesById = {}, values = Object.create(valuesById);
+            values[valuesById[0] = "UNKNOWN"] = 0;
+            values[valuesById[1] = "POINT"] = 1;
+            values[valuesById[2] = "LINESTRING"] = 2;
+            values[valuesById[3] = "POLYGON"] = 3;
+            return values;
+        })();
+
+        Tile.Value = (function() {
+
+            /**
+             * Properties of a Value.
+             * @memberof vector_tile.Tile
+             * @interface IValue
+             * @property {string|null} [stringValue] Value stringValue
+             * @property {number|null} [floatValue] Value floatValue
+             * @property {number|null} [doubleValue] Value doubleValue
+             * @property {number|Long|null} [intValue] Value intValue
+             * @property {number|Long|null} [uintValue] Value uintValue
+             * @property {number|Long|null} [sintValue] Value sintValue
+             * @property {boolean|null} [boolValue] Value boolValue
+             */
+
+            /**
+             * Constructs a new Value.
+             * @memberof vector_tile.Tile
+             * @classdesc Represents a Value.
+             * @implements IValue
+             * @constructor
+             * @param {vector_tile.Tile.IValue=} [properties] Properties to set
+             */
+            function Value(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * Value stringValue.
+             * @member {string} stringValue
+             * @memberof vector_tile.Tile.Value
+             * @instance
+             */
+            Value.prototype.stringValue = "";
+
+            /**
+             * Value floatValue.
+             * @member {number} floatValue
+             * @memberof vector_tile.Tile.Value
+             * @instance
+             */
+            Value.prototype.floatValue = 0;
+
+            /**
+             * Value doubleValue.
+             * @member {number} doubleValue
+             * @memberof vector_tile.Tile.Value
+             * @instance
+             */
+            Value.prototype.doubleValue = 0;
+
+            /**
+             * Value intValue.
+             * @member {number|Long} intValue
+             * @memberof vector_tile.Tile.Value
+             * @instance
+             */
+            Value.prototype.intValue = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
+
+            /**
+             * Value uintValue.
+             * @member {number|Long} uintValue
+             * @memberof vector_tile.Tile.Value
+             * @instance
+             */
+            Value.prototype.uintValue = $util.Long ? $util.Long.fromBits(0,0,true) : 0;
+
+            /**
+             * Value sintValue.
+             * @member {number|Long} sintValue
+             * @memberof vector_tile.Tile.Value
+             * @instance
+             */
+            Value.prototype.sintValue = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
+
+            /**
+             * Value boolValue.
+             * @member {boolean} boolValue
+             * @memberof vector_tile.Tile.Value
+             * @instance
+             */
+            Value.prototype.boolValue = false;
+
+            /**
+             * Creates a new Value instance using the specified properties.
+             * @function create
+             * @memberof vector_tile.Tile.Value
+             * @static
+             * @param {vector_tile.Tile.IValue=} [properties] Properties to set
+             * @returns {vector_tile.Tile.Value} Value instance
+             */
+            Value.create = function create(properties) {
+                return new Value(properties);
+            };
+
+            /**
+             * Encodes the specified Value message. Does not implicitly {@link vector_tile.Tile.Value.verify|verify} messages.
+             * @function encode
+             * @memberof vector_tile.Tile.Value
+             * @static
+             * @param {vector_tile.Tile.IValue} message Value message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Value.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.stringValue != null && Object.hasOwnProperty.call(message, "stringValue"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.stringValue);
+                if (message.floatValue != null && Object.hasOwnProperty.call(message, "floatValue"))
+                    writer.uint32(/* id 2, wireType 5 =*/21).float(message.floatValue);
+                if (message.doubleValue != null && Object.hasOwnProperty.call(message, "doubleValue"))
+                    writer.uint32(/* id 3, wireType 1 =*/25).double(message.doubleValue);
+                if (message.intValue != null && Object.hasOwnProperty.call(message, "intValue"))
+                    writer.uint32(/* id 4, wireType 0 =*/32).int64(message.intValue);
+                if (message.uintValue != null && Object.hasOwnProperty.call(message, "uintValue"))
+                    writer.uint32(/* id 5, wireType 0 =*/40).uint64(message.uintValue);
+                if (message.sintValue != null && Object.hasOwnProperty.call(message, "sintValue"))
+                    writer.uint32(/* id 6, wireType 0 =*/48).sint64(message.sintValue);
+                if (message.boolValue != null && Object.hasOwnProperty.call(message, "boolValue"))
+                    writer.uint32(/* id 7, wireType 0 =*/56).bool(message.boolValue);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified Value message, length delimited. Does not implicitly {@link vector_tile.Tile.Value.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof vector_tile.Tile.Value
+             * @static
+             * @param {vector_tile.Tile.IValue} message Value message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Value.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a Value message from the specified reader or buffer.
+             * @function decode
+             * @memberof vector_tile.Tile.Value
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {vector_tile.Tile.Value} Value
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Value.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.vector_tile.Tile.Value();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.stringValue = reader.string();
+                        break;
+                    case 2:
+                        message.floatValue = reader.float();
+                        break;
+                    case 3:
+                        message.doubleValue = reader.double();
+                        break;
+                    case 4:
+                        message.intValue = reader.int64();
+                        break;
+                    case 5:
+                        message.uintValue = reader.uint64();
+                        break;
+                    case 6:
+                        message.sintValue = reader.sint64();
+                        break;
+                    case 7:
+                        message.boolValue = reader.bool();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a Value message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof vector_tile.Tile.Value
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {vector_tile.Tile.Value} Value
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Value.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a Value message.
+             * @function verify
+             * @memberof vector_tile.Tile.Value
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            Value.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.stringValue != null && message.hasOwnProperty("stringValue"))
+                    if (!$util.isString(message.stringValue))
+                        return "stringValue: string expected";
+                if (message.floatValue != null && message.hasOwnProperty("floatValue"))
+                    if (typeof message.floatValue !== "number")
+                        return "floatValue: number expected";
+                if (message.doubleValue != null && message.hasOwnProperty("doubleValue"))
+                    if (typeof message.doubleValue !== "number")
+                        return "doubleValue: number expected";
+                if (message.intValue != null && message.hasOwnProperty("intValue"))
+                    if (!$util.isInteger(message.intValue) && !(message.intValue && $util.isInteger(message.intValue.low) && $util.isInteger(message.intValue.high)))
+                        return "intValue: integer|Long expected";
+                if (message.uintValue != null && message.hasOwnProperty("uintValue"))
+                    if (!$util.isInteger(message.uintValue) && !(message.uintValue && $util.isInteger(message.uintValue.low) && $util.isInteger(message.uintValue.high)))
+                        return "uintValue: integer|Long expected";
+                if (message.sintValue != null && message.hasOwnProperty("sintValue"))
+                    if (!$util.isInteger(message.sintValue) && !(message.sintValue && $util.isInteger(message.sintValue.low) && $util.isInteger(message.sintValue.high)))
+                        return "sintValue: integer|Long expected";
+                if (message.boolValue != null && message.hasOwnProperty("boolValue"))
+                    if (typeof message.boolValue !== "boolean")
+                        return "boolValue: boolean expected";
+                return null;
+            };
+
+            /**
+             * Creates a Value message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof vector_tile.Tile.Value
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {vector_tile.Tile.Value} Value
+             */
+            Value.fromObject = function fromObject(object) {
+                if (object instanceof $root.vector_tile.Tile.Value)
+                    return object;
+                var message = new $root.vector_tile.Tile.Value();
+                if (object.stringValue != null)
+                    message.stringValue = String(object.stringValue);
+                if (object.floatValue != null)
+                    message.floatValue = Number(object.floatValue);
+                if (object.doubleValue != null)
+                    message.doubleValue = Number(object.doubleValue);
+                if (object.intValue != null)
+                    if ($util.Long)
+                        (message.intValue = $util.Long.fromValue(object.intValue)).unsigned = false;
+                    else if (typeof object.intValue === "string")
+                        message.intValue = parseInt(object.intValue, 10);
+                    else if (typeof object.intValue === "number")
+                        message.intValue = object.intValue;
+                    else if (typeof object.intValue === "object")
+                        message.intValue = new $util.LongBits(object.intValue.low >>> 0, object.intValue.high >>> 0).toNumber();
+                if (object.uintValue != null)
+                    if ($util.Long)
+                        (message.uintValue = $util.Long.fromValue(object.uintValue)).unsigned = true;
+                    else if (typeof object.uintValue === "string")
+                        message.uintValue = parseInt(object.uintValue, 10);
+                    else if (typeof object.uintValue === "number")
+                        message.uintValue = object.uintValue;
+                    else if (typeof object.uintValue === "object")
+                        message.uintValue = new $util.LongBits(object.uintValue.low >>> 0, object.uintValue.high >>> 0).toNumber(true);
+                if (object.sintValue != null)
+                    if ($util.Long)
+                        (message.sintValue = $util.Long.fromValue(object.sintValue)).unsigned = false;
+                    else if (typeof object.sintValue === "string")
+                        message.sintValue = parseInt(object.sintValue, 10);
+                    else if (typeof object.sintValue === "number")
+                        message.sintValue = object.sintValue;
+                    else if (typeof object.sintValue === "object")
+                        message.sintValue = new $util.LongBits(object.sintValue.low >>> 0, object.sintValue.high >>> 0).toNumber();
+                if (object.boolValue != null)
+                    message.boolValue = Boolean(object.boolValue);
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a Value message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof vector_tile.Tile.Value
+             * @static
+             * @param {vector_tile.Tile.Value} message Value
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            Value.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults) {
+                    object.stringValue = "";
+                    object.floatValue = 0;
+                    object.doubleValue = 0;
+                    if ($util.Long) {
+                        var long = new $util.Long(0, 0, false);
+                        object.intValue = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
+                    } else
+                        object.intValue = options.longs === String ? "0" : 0;
+                    if ($util.Long) {
+                        var long = new $util.Long(0, 0, true);
+                        object.uintValue = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
+                    } else
+                        object.uintValue = options.longs === String ? "0" : 0;
+                    if ($util.Long) {
+                        var long = new $util.Long(0, 0, false);
+                        object.sintValue = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
+                    } else
+                        object.sintValue = options.longs === String ? "0" : 0;
+                    object.boolValue = false;
+                }
+                if (message.stringValue != null && message.hasOwnProperty("stringValue"))
+                    object.stringValue = message.stringValue;
+                if (message.floatValue != null && message.hasOwnProperty("floatValue"))
+                    object.floatValue = options.json && !isFinite(message.floatValue) ? String(message.floatValue) : message.floatValue;
+                if (message.doubleValue != null && message.hasOwnProperty("doubleValue"))
+                    object.doubleValue = options.json && !isFinite(message.doubleValue) ? String(message.doubleValue) : message.doubleValue;
+                if (message.intValue != null && message.hasOwnProperty("intValue"))
+                    if (typeof message.intValue === "number")
+                        object.intValue = options.longs === String ? String(message.intValue) : message.intValue;
+                    else
+                        object.intValue = options.longs === String ? $util.Long.prototype.toString.call(message.intValue) : options.longs === Number ? new $util.LongBits(message.intValue.low >>> 0, message.intValue.high >>> 0).toNumber() : message.intValue;
+                if (message.uintValue != null && message.hasOwnProperty("uintValue"))
+                    if (typeof message.uintValue === "number")
+                        object.uintValue = options.longs === String ? String(message.uintValue) : message.uintValue;
+                    else
+                        object.uintValue = options.longs === String ? $util.Long.prototype.toString.call(message.uintValue) : options.longs === Number ? new $util.LongBits(message.uintValue.low >>> 0, message.uintValue.high >>> 0).toNumber(true) : message.uintValue;
+                if (message.sintValue != null && message.hasOwnProperty("sintValue"))
+                    if (typeof message.sintValue === "number")
+                        object.sintValue = options.longs === String ? String(message.sintValue) : message.sintValue;
+                    else
+                        object.sintValue = options.longs === String ? $util.Long.prototype.toString.call(message.sintValue) : options.longs === Number ? new $util.LongBits(message.sintValue.low >>> 0, message.sintValue.high >>> 0).toNumber() : message.sintValue;
+                if (message.boolValue != null && message.hasOwnProperty("boolValue"))
+                    object.boolValue = message.boolValue;
+                return object;
+            };
+
+            /**
+             * Converts this Value to JSON.
+             * @function toJSON
+             * @memberof vector_tile.Tile.Value
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            Value.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for Value
+             * @function getTypeUrl
+             * @memberof vector_tile.Tile.Value
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            Value.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/vector_tile.Tile.Value";
+            };
+
+            return Value;
+        })();
+
+        Tile.Feature = (function() {
+
+            /**
+             * Properties of a Feature.
+             * @memberof vector_tile.Tile
+             * @interface IFeature
+             * @property {number|Long|null} [id] Feature id
+             * @property {Array.<number>|null} [tags] Feature tags
+             * @property {vector_tile.Tile.GeomType|null} [type] Feature type
+             * @property {Array.<number>|null} [geometry] Feature geometry
+             */
+
+            /**
+             * Constructs a new Feature.
+             * @memberof vector_tile.Tile
+             * @classdesc Represents a Feature.
+             * @implements IFeature
+             * @constructor
+             * @param {vector_tile.Tile.IFeature=} [properties] Properties to set
+             */
+            function Feature(properties) {
+                this.tags = [];
+                this.geometry = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * Feature id.
+             * @member {number|Long} id
+             * @memberof vector_tile.Tile.Feature
+             * @instance
+             */
+            Feature.prototype.id = $util.Long ? $util.Long.fromBits(0,0,true) : 0;
+
+            /**
+             * Feature tags.
+             * @member {Array.<number>} tags
+             * @memberof vector_tile.Tile.Feature
+             * @instance
+             */
+            Feature.prototype.tags = $util.emptyArray;
+
+            /**
+             * Feature type.
+             * @member {vector_tile.Tile.GeomType} type
+             * @memberof vector_tile.Tile.Feature
+             * @instance
+             */
+            Feature.prototype.type = 0;
+
+            /**
+             * Feature geometry.
+             * @member {Array.<number>} geometry
+             * @memberof vector_tile.Tile.Feature
+             * @instance
+             */
+            Feature.prototype.geometry = $util.emptyArray;
+
+            /**
+             * Creates a new Feature instance using the specified properties.
+             * @function create
+             * @memberof vector_tile.Tile.Feature
+             * @static
+             * @param {vector_tile.Tile.IFeature=} [properties] Properties to set
+             * @returns {vector_tile.Tile.Feature} Feature instance
+             */
+            Feature.create = function create(properties) {
+                return new Feature(properties);
+            };
+
+            /**
+             * Encodes the specified Feature message. Does not implicitly {@link vector_tile.Tile.Feature.verify|verify} messages.
+             * @function encode
+             * @memberof vector_tile.Tile.Feature
+             * @static
+             * @param {vector_tile.Tile.IFeature} message Feature message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Feature.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.id != null && Object.hasOwnProperty.call(message, "id"))
+                    writer.uint32(/* id 1, wireType 0 =*/8).uint64(message.id);
+                if (message.tags != null && message.tags.length) {
+                    writer.uint32(/* id 2, wireType 2 =*/18).fork();
+                    for (var i = 0; i < message.tags.length; ++i)
+                        writer.uint32(message.tags[i]);
+                    writer.ldelim();
+                }
+                if (message.type != null && Object.hasOwnProperty.call(message, "type"))
+                    writer.uint32(/* id 3, wireType 0 =*/24).int32(message.type);
+                if (message.geometry != null && message.geometry.length) {
+                    writer.uint32(/* id 4, wireType 2 =*/34).fork();
+                    for (var i = 0; i < message.geometry.length; ++i)
+                        writer.uint32(message.geometry[i]);
+                    writer.ldelim();
+                }
+                return writer;
+            };
+
+            /**
+             * Encodes the specified Feature message, length delimited. Does not implicitly {@link vector_tile.Tile.Feature.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof vector_tile.Tile.Feature
+             * @static
+             * @param {vector_tile.Tile.IFeature} message Feature message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Feature.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a Feature message from the specified reader or buffer.
+             * @function decode
+             * @memberof vector_tile.Tile.Feature
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {vector_tile.Tile.Feature} Feature
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Feature.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.vector_tile.Tile.Feature();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.id = reader.uint64();
+                        break;
+                    case 2:
+                        if (!(message.tags && message.tags.length))
+                            message.tags = [];
+                        if ((tag & 7) === 2) {
+                            var end2 = reader.uint32() + reader.pos;
+                            while (reader.pos < end2)
+                                message.tags.push(reader.uint32());
+                        } else
+                            message.tags.push(reader.uint32());
+                        break;
+                    case 3:
+                        message.type = reader.int32();
+                        break;
+                    case 4:
+                        if (!(message.geometry && message.geometry.length))
+                            message.geometry = [];
+                        if ((tag & 7) === 2) {
+                            var end2 = reader.uint32() + reader.pos;
+                            while (reader.pos < end2)
+                                message.geometry.push(reader.uint32());
+                        } else
+                            message.geometry.push(reader.uint32());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a Feature message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof vector_tile.Tile.Feature
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {vector_tile.Tile.Feature} Feature
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Feature.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a Feature message.
+             * @function verify
+             * @memberof vector_tile.Tile.Feature
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            Feature.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.id != null && message.hasOwnProperty("id"))
+                    if (!$util.isInteger(message.id) && !(message.id && $util.isInteger(message.id.low) && $util.isInteger(message.id.high)))
+                        return "id: integer|Long expected";
+                if (message.tags != null && message.hasOwnProperty("tags")) {
+                    if (!Array.isArray(message.tags))
+                        return "tags: array expected";
+                    for (var i = 0; i < message.tags.length; ++i)
+                        if (!$util.isInteger(message.tags[i]))
+                            return "tags: integer[] expected";
+                }
+                if (message.type != null && message.hasOwnProperty("type"))
+                    switch (message.type) {
+                    default:
+                        return "type: enum value expected";
+                    case 0:
+                    case 1:
+                    case 2:
+                    case 3:
+                        break;
+                    }
+                if (message.geometry != null && message.hasOwnProperty("geometry")) {
+                    if (!Array.isArray(message.geometry))
+                        return "geometry: array expected";
+                    for (var i = 0; i < message.geometry.length; ++i)
+                        if (!$util.isInteger(message.geometry[i]))
+                            return "geometry: integer[] expected";
+                }
+                return null;
+            };
+
+            /**
+             * Creates a Feature message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof vector_tile.Tile.Feature
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {vector_tile.Tile.Feature} Feature
+             */
+            Feature.fromObject = function fromObject(object) {
+                if (object instanceof $root.vector_tile.Tile.Feature)
+                    return object;
+                var message = new $root.vector_tile.Tile.Feature();
+                if (object.id != null)
+                    if ($util.Long)
+                        (message.id = $util.Long.fromValue(object.id)).unsigned = true;
+                    else if (typeof object.id === "string")
+                        message.id = parseInt(object.id, 10);
+                    else if (typeof object.id === "number")
+                        message.id = object.id;
+                    else if (typeof object.id === "object")
+                        message.id = new $util.LongBits(object.id.low >>> 0, object.id.high >>> 0).toNumber(true);
+                if (object.tags) {
+                    if (!Array.isArray(object.tags))
+                        throw TypeError(".vector_tile.Tile.Feature.tags: array expected");
+                    message.tags = [];
+                    for (var i = 0; i < object.tags.length; ++i)
+                        message.tags[i] = object.tags[i] >>> 0;
+                }
+                switch (object.type) {
+                case "UNKNOWN":
+                case 0:
+                    message.type = 0;
+                    break;
+                case "POINT":
+                case 1:
+                    message.type = 1;
+                    break;
+                case "LINESTRING":
+                case 2:
+                    message.type = 2;
+                    break;
+                case "POLYGON":
+                case 3:
+                    message.type = 3;
+                    break;
+                }
+                if (object.geometry) {
+                    if (!Array.isArray(object.geometry))
+                        throw TypeError(".vector_tile.Tile.Feature.geometry: array expected");
+                    message.geometry = [];
+                    for (var i = 0; i < object.geometry.length; ++i)
+                        message.geometry[i] = object.geometry[i] >>> 0;
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a Feature message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof vector_tile.Tile.Feature
+             * @static
+             * @param {vector_tile.Tile.Feature} message Feature
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            Feature.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults) {
+                    object.tags = [];
+                    object.geometry = [];
+                }
+                if (options.defaults) {
+                    if ($util.Long) {
+                        var long = new $util.Long(0, 0, true);
+                        object.id = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
+                    } else
+                        object.id = options.longs === String ? "0" : 0;
+                    object.type = options.enums === String ? "UNKNOWN" : 0;
+                }
+                if (message.id != null && message.hasOwnProperty("id"))
+                    if (typeof message.id === "number")
+                        object.id = options.longs === String ? String(message.id) : message.id;
+                    else
+                        object.id = options.longs === String ? $util.Long.prototype.toString.call(message.id) : options.longs === Number ? new $util.LongBits(message.id.low >>> 0, message.id.high >>> 0).toNumber(true) : message.id;
+                if (message.tags && message.tags.length) {
+                    object.tags = [];
+                    for (var j = 0; j < message.tags.length; ++j)
+                        object.tags[j] = message.tags[j];
+                }
+                if (message.type != null && message.hasOwnProperty("type"))
+                    object.type = options.enums === String ? $root.vector_tile.Tile.GeomType[message.type] : message.type;
+                if (message.geometry && message.geometry.length) {
+                    object.geometry = [];
+                    for (var j = 0; j < message.geometry.length; ++j)
+                        object.geometry[j] = message.geometry[j];
+                }
+                return object;
+            };
+
+            /**
+             * Converts this Feature to JSON.
+             * @function toJSON
+             * @memberof vector_tile.Tile.Feature
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            Feature.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for Feature
+             * @function getTypeUrl
+             * @memberof vector_tile.Tile.Feature
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            Feature.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/vector_tile.Tile.Feature";
+            };
+
+            return Feature;
+        })();
+
+        Tile.Layer = (function() {
+
+            /**
+             * Properties of a Layer.
+             * @memberof vector_tile.Tile
+             * @interface ILayer
+             * @property {number} version Layer version
+             * @property {string} name Layer name
+             * @property {Array.<vector_tile.Tile.IFeature>|null} [features] Layer features
+             * @property {Array.<string>|null} [keys] Layer keys
+             * @property {Array.<vector_tile.Tile.IValue>|null} [values] Layer values
+             * @property {number|null} [extent] Layer extent
+             */
+
+            /**
+             * Constructs a new Layer.
+             * @memberof vector_tile.Tile
+             * @classdesc Represents a Layer.
+             * @implements ILayer
+             * @constructor
+             * @param {vector_tile.Tile.ILayer=} [properties] Properties to set
+             */
+            function Layer(properties) {
+                this.features = [];
+                this.keys = [];
+                this.values = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * Layer version.
+             * @member {number} version
+             * @memberof vector_tile.Tile.Layer
+             * @instance
+             */
+            Layer.prototype.version = 1;
+
+            /**
+             * Layer name.
+             * @member {string} name
+             * @memberof vector_tile.Tile.Layer
+             * @instance
+             */
+            Layer.prototype.name = "";
+
+            /**
+             * Layer features.
+             * @member {Array.<vector_tile.Tile.IFeature>} features
+             * @memberof vector_tile.Tile.Layer
+             * @instance
+             */
+            Layer.prototype.features = $util.emptyArray;
+
+            /**
+             * Layer keys.
+             * @member {Array.<string>} keys
+             * @memberof vector_tile.Tile.Layer
+             * @instance
+             */
+            Layer.prototype.keys = $util.emptyArray;
+
+            /**
+             * Layer values.
+             * @member {Array.<vector_tile.Tile.IValue>} values
+             * @memberof vector_tile.Tile.Layer
+             * @instance
+             */
+            Layer.prototype.values = $util.emptyArray;
+
+            /**
+             * Layer extent.
+             * @member {number} extent
+             * @memberof vector_tile.Tile.Layer
+             * @instance
+             */
+            Layer.prototype.extent = 4096;
+
+            /**
+             * Creates a new Layer instance using the specified properties.
+             * @function create
+             * @memberof vector_tile.Tile.Layer
+             * @static
+             * @param {vector_tile.Tile.ILayer=} [properties] Properties to set
+             * @returns {vector_tile.Tile.Layer} Layer instance
+             */
+            Layer.create = function create(properties) {
+                return new Layer(properties);
+            };
+
+            /**
+             * Encodes the specified Layer message. Does not implicitly {@link vector_tile.Tile.Layer.verify|verify} messages.
+             * @function encode
+             * @memberof vector_tile.Tile.Layer
+             * @static
+             * @param {vector_tile.Tile.ILayer} message Layer message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Layer.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                writer.uint32(/* id 1, wireType 2 =*/10).string(message.name);
+                if (message.features != null && message.features.length)
+                    for (var i = 0; i < message.features.length; ++i)
+                        $root.vector_tile.Tile.Feature.encode(message.features[i], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim();
+                if (message.keys != null && message.keys.length)
+                    for (var i = 0; i < message.keys.length; ++i)
+                        writer.uint32(/* id 3, wireType 2 =*/26).string(message.keys[i]);
+                if (message.values != null && message.values.length)
+                    for (var i = 0; i < message.values.length; ++i)
+                        $root.vector_tile.Tile.Value.encode(message.values[i], writer.uint32(/* id 4, wireType 2 =*/34).fork()).ldelim();
+                if (message.extent != null && Object.hasOwnProperty.call(message, "extent"))
+                    writer.uint32(/* id 5, wireType 0 =*/40).uint32(message.extent);
+                writer.uint32(/* id 15, wireType 0 =*/120).uint32(message.version);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified Layer message, length delimited. Does not implicitly {@link vector_tile.Tile.Layer.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof vector_tile.Tile.Layer
+             * @static
+             * @param {vector_tile.Tile.ILayer} message Layer message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Layer.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a Layer message from the specified reader or buffer.
+             * @function decode
+             * @memberof vector_tile.Tile.Layer
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {vector_tile.Tile.Layer} Layer
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Layer.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.vector_tile.Tile.Layer();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 15:
+                        message.version = reader.uint32();
+                        break;
+                    case 1:
+                        message.name = reader.string();
+                        break;
+                    case 2:
+                        if (!(message.features && message.features.length))
+                            message.features = [];
+                        message.features.push($root.vector_tile.Tile.Feature.decode(reader, reader.uint32()));
+                        break;
+                    case 3:
+                        if (!(message.keys && message.keys.length))
+                            message.keys = [];
+                        message.keys.push(reader.string());
+                        break;
+                    case 4:
+                        if (!(message.values && message.values.length))
+                            message.values = [];
+                        message.values.push($root.vector_tile.Tile.Value.decode(reader, reader.uint32()));
+                        break;
+                    case 5:
+                        message.extent = reader.uint32();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("version"))
+                    throw $util.ProtocolError("missing required 'version'", { instance: message });
+                if (!message.hasOwnProperty("name"))
+                    throw $util.ProtocolError("missing required 'name'", { instance: message });
+                return message;
+            };
+
+            /**
+             * Decodes a Layer message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof vector_tile.Tile.Layer
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {vector_tile.Tile.Layer} Layer
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Layer.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a Layer message.
+             * @function verify
+             * @memberof vector_tile.Tile.Layer
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            Layer.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (!$util.isInteger(message.version))
+                    return "version: integer expected";
+                if (!$util.isString(message.name))
+                    return "name: string expected";
+                if (message.features != null && message.hasOwnProperty("features")) {
+                    if (!Array.isArray(message.features))
+                        return "features: array expected";
+                    for (var i = 0; i < message.features.length; ++i) {
+                        var error = $root.vector_tile.Tile.Feature.verify(message.features[i]);
+                        if (error)
+                            return "features." + error;
+                    }
+                }
+                if (message.keys != null && message.hasOwnProperty("keys")) {
+                    if (!Array.isArray(message.keys))
+                        return "keys: array expected";
+                    for (var i = 0; i < message.keys.length; ++i)
+                        if (!$util.isString(message.keys[i]))
+                            return "keys: string[] expected";
+                }
+                if (message.values != null && message.hasOwnProperty("values")) {
+                    if (!Array.isArray(message.values))
+                        return "values: array expected";
+                    for (var i = 0; i < message.values.length; ++i) {
+                        var error = $root.vector_tile.Tile.Value.verify(message.values[i]);
+                        if (error)
+                            return "values." + error;
+                    }
+                }
+                if (message.extent != null && message.hasOwnProperty("extent"))
+                    if (!$util.isInteger(message.extent))
+                        return "extent: integer expected";
+                return null;
+            };
+
+            /**
+             * Creates a Layer message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof vector_tile.Tile.Layer
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {vector_tile.Tile.Layer} Layer
+             */
+            Layer.fromObject = function fromObject(object) {
+                if (object instanceof $root.vector_tile.Tile.Layer)
+                    return object;
+                var message = new $root.vector_tile.Tile.Layer();
+                if (object.version != null)
+                    message.version = object.version >>> 0;
+                if (object.name != null)
+                    message.name = String(object.name);
+                if (object.features) {
+                    if (!Array.isArray(object.features))
+                        throw TypeError(".vector_tile.Tile.Layer.features: array expected");
+                    message.features = [];
+                    for (var i = 0; i < object.features.length; ++i) {
+                        if (typeof object.features[i] !== "object")
+                            throw TypeError(".vector_tile.Tile.Layer.features: object expected");
+                        message.features[i] = $root.vector_tile.Tile.Feature.fromObject(object.features[i]);
+                    }
+                }
+                if (object.keys) {
+                    if (!Array.isArray(object.keys))
+                        throw TypeError(".vector_tile.Tile.Layer.keys: array expected");
+                    message.keys = [];
+                    for (var i = 0; i < object.keys.length; ++i)
+                        message.keys[i] = String(object.keys[i]);
+                }
+                if (object.values) {
+                    if (!Array.isArray(object.values))
+                        throw TypeError(".vector_tile.Tile.Layer.values: array expected");
+                    message.values = [];
+                    for (var i = 0; i < object.values.length; ++i) {
+                        if (typeof object.values[i] !== "object")
+                            throw TypeError(".vector_tile.Tile.Layer.values: object expected");
+                        message.values[i] = $root.vector_tile.Tile.Value.fromObject(object.values[i]);
+                    }
+                }
+                if (object.extent != null)
+                    message.extent = object.extent >>> 0;
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a Layer message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof vector_tile.Tile.Layer
+             * @static
+             * @param {vector_tile.Tile.Layer} message Layer
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            Layer.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults) {
+                    object.features = [];
+                    object.keys = [];
+                    object.values = [];
+                }
+                if (options.defaults) {
+                    object.name = "";
+                    object.extent = 4096;
+                    object.version = 1;
+                }
+                if (message.name != null && message.hasOwnProperty("name"))
+                    object.name = message.name;
+                if (message.features && message.features.length) {
+                    object.features = [];
+                    for (var j = 0; j < message.features.length; ++j)
+                        object.features[j] = $root.vector_tile.Tile.Feature.toObject(message.features[j], options);
+                }
+                if (message.keys && message.keys.length) {
+                    object.keys = [];
+                    for (var j = 0; j < message.keys.length; ++j)
+                        object.keys[j] = message.keys[j];
+                }
+                if (message.values && message.values.length) {
+                    object.values = [];
+                    for (var j = 0; j < message.values.length; ++j)
+                        object.values[j] = $root.vector_tile.Tile.Value.toObject(message.values[j], options);
+                }
+                if (message.extent != null && message.hasOwnProperty("extent"))
+                    object.extent = message.extent;
+                if (message.version != null && message.hasOwnProperty("version"))
+                    object.version = message.version;
+                return object;
+            };
+
+            /**
+             * Converts this Layer to JSON.
+             * @function toJSON
+             * @memberof vector_tile.Tile.Layer
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            Layer.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for Layer
+             * @function getTypeUrl
+             * @memberof vector_tile.Tile.Layer
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            Layer.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/vector_tile.Tile.Layer";
+            };
+
+            return Layer;
+        })();
+
+        return Tile;
+    })();
+
+    return vector_tile;
+})();
+
+module.exports = $root;
diff --git a/tests/data/mapbox/vector_tile.proto b/tests/data/mapbox/vector_tile.proto
new file mode 100644
index 0000000..d224e5d
--- /dev/null
+++ b/tests/data/mapbox/vector_tile.proto
@@ -0,0 +1,49 @@
+syntax = "proto2";
+
+package vector_tile;
+
+message Tile {
+
+    enum GeomType {
+
+        UNKNOWN = 0;
+        POINT = 1;
+        LINESTRING = 2;
+        POLYGON = 3;
+    }
+
+    message Value {
+
+        optional string string_value = 1;
+        optional float float_value = 2;
+        optional double double_value = 3;
+        optional int64 int_value = 4;
+        optional uint64 uint_value = 5;
+        optional sint64 sint_value = 6;
+        optional bool bool_value = 7;
+        extensions 8 to max;
+    }
+
+    message Feature {
+
+        optional uint64 id = 1 [ default = 0 ];
+        repeated uint32 tags = 2 [ packed = true ];
+        optional GeomType type = 3 [ default = UNKNOWN ];
+        repeated uint32 geometry = 4 [ packed = true ];
+    }
+
+    message Layer {
+
+        required uint32 version = 15 [ default = 1 ];
+        required string name = 1;
+        repeated Feature features = 2;
+        repeated string keys = 3;
+        repeated Value values = 4;
+        optional uint32 extent = 5 [ default = 4096 ];
+        extensions 16 to max;
+    }
+
+    repeated Layer layers = 3;
+
+    extensions 16 to 8191;
+}
diff --git a/tests/data/options_test.proto b/tests/data/options_test.proto
new file mode 100644
index 0000000..52f0228
--- /dev/null
+++ b/tests/data/options_test.proto
@@ -0,0 +1,144 @@
+syntax = "proto3";
+
+import "google/protobuf/descriptor.proto";
+
+package test;
+
+//Simple int32 based options (both single and repeated)
+//for fields and messages
+
+extend google.protobuf.FieldOptions {
+    repeated int32 fo_rep_int = 50000;
+    int32 fo_single_int = 50001;
+}
+
+extend google.protobuf.MessageOptions {
+    repeated int32 mo_rep_int = 50000;
+    int32 mo_single_int = 50001;
+}
+
+message TestFieldOptionsInt {
+    string field1 = 2 [(fo_rep_int) = 1, (fo_rep_int) = 2];
+    string field2 = 1 [(fo_single_int) = 3];
+}
+
+message TestMessageOptionsInt {
+    option (mo_rep_int) = 1;
+    option (mo_rep_int) = 2;
+    option (mo_single_int) = 3;
+}
+
+//Message based options including nested sub messages (both single and repeated)
+//for fields and messages
+
+message Msg {
+    int32 value = 1;
+    repeated int32 rep_value = 2;
+    SubMsg nested = 3;
+    repeated SubMsg rep_nested = 4;
+}
+
+message SubMsg {
+    string value = 1;
+    SubMsg nested = 2;
+}
+
+extend google.protobuf.FieldOptions {
+    repeated Msg fo_rep_msg = 50002;
+    Msg fo_single_msg = 50003;
+}
+
+extend google.protobuf.MessageOptions {
+    repeated Msg mo_rep_msg = 50002;
+    Msg mo_single_msg = 50003;
+}
+
+extend google.protobuf.MethodOptions {
+    repeated Msg method_rep_msg = 50002;
+    Msg method_single_msg = 50003;
+}
+
+message TestFieldOptionsMsg {
+    string field1 = 1 [(fo_rep_msg) = {value: 1 rep_value: 2 rep_value: 3}, (fo_rep_msg) = {value: 4 rep_value: 5 rep_value: 6}];
+    string field2 = 2 [(fo_single_msg).value = 7, (fo_single_msg).rep_value = 8, (fo_single_msg).rep_value = 9];
+}
+
+message TestMessageOptionsMsg {
+    option (mo_rep_msg) = {
+        value: 1
+        rep_value: 2
+        rep_value: 3
+    };
+    option (mo_rep_msg) = {
+        value: 4
+        rep_value: 5
+        rep_value: 6
+    };
+    option (mo_rep_msg) = {
+        value: 5
+        rep_value: [ 7, 8 ]
+    };
+    option (mo_single_msg).value = 7;
+    option (mo_single_msg).rep_value = 8;
+    option (mo_single_msg).rep_value = 9;
+}
+
+message TestFieldOptionsNested {
+    string field1 = 1 [(fo_rep_msg) = {value: 1 nested { nested {value: "x"} } rep_nested { value: "y"} rep_nested { value: "z" } rep_value: 3}, (fo_rep_msg) = { nested { value: "w" }}];
+    string field2 = 2 [(fo_single_msg).nested.value = "x", (fo_single_msg).rep_nested = {value : "x"}, (fo_single_msg).rep_nested = {value : "y"}];
+    string field3 = 3 [(fo_single_msg).nested = {value: "x" nested {nested{value: "y"}}}];
+}
+
+message TestMessageOptionsNested {
+    option (mo_rep_msg) = {
+        value: 1
+        nested {
+            nested {
+                value: "x"
+            }
+        }
+        rep_nested {
+            value: "y"
+        }
+        rep_nested {
+            value: "z"
+        }
+        rep_value: 3
+    };
+    option (mo_rep_msg) = {
+        nested {
+            value: "w"
+        }
+    };
+    option (mo_single_msg).nested.value = "x";
+    option (mo_single_msg).rep_nested = {value : "x" nested {nested{value: "y"}}};
+    option (mo_single_msg).rep_nested = {value : "y"};
+}
+
+service TestOptionsService {
+    rpc TestOptionsRpc(Msg) returns (Msg) {
+        option (method_rep_msg) = {
+            value: 1
+            nested {
+                nested {
+                    value: "x"
+                }
+            }
+            rep_nested {
+                value: "y"
+            }
+            rep_nested {
+                value: "z"
+            }
+            rep_value: 3
+        };
+        option (method_rep_msg) = {
+            nested {
+                value: "w"
+            }
+        };
+        option (method_single_msg).nested.value = "x";
+        option (method_single_msg).rep_nested = {value : "x" nested {nested{value: "y"}}};
+        option (method_single_msg).rep_nested = {value : "y"};
+    }
+}
diff --git a/tests/data/package.d.ts b/tests/data/package.d.ts
new file mode 100644
index 0000000..d4807ba
--- /dev/null
+++ b/tests/data/package.d.ts
@@ -0,0 +1,75 @@
+import * as $protobuf from "../..";
+export interface IPackage {
+    name?: (string|null);
+    version?: (string|null);
+    versionScheme?: (string|null);
+    description?: (string|null);
+    author?: (string|null);
+    license?: (string|null);
+    repository?: (Package.IRepository|null);
+    bugs?: (string|null);
+    homepage?: (string|null);
+    keywords?: (string[]|null);
+    main?: (string|null);
+    bin?: ({ [k: string]: string }|null);
+    scripts?: ({ [k: string]: string }|null);
+    dependencies?: ({ [k: string]: string }|null);
+    devDependencies?: ({ [k: string]: string }|null);
+    types?: (string|null);
+    cliDependencies?: (string[]|null);
+}
+
+export class Package implements IPackage {
+    constructor(properties?: IPackage);
+    public name: string;
+    public version: string;
+    public versionScheme: string;
+    public description: string;
+    public author: string;
+    public license: string;
+    public repository?: (Package.IRepository|null);
+    public bugs: string;
+    public homepage: string;
+    public keywords: string[];
+    public main: string;
+    public bin: { [k: string]: string };
+    public scripts: { [k: string]: string };
+    public dependencies: { [k: string]: string };
+    public devDependencies: { [k: string]: string };
+    public types: string;
+    public cliDependencies: string[];
+    public static create(properties?: IPackage): Package;
+    public static encode(message: IPackage, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: IPackage, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): Package;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): Package;
+    public static verify(message: { [k: string]: any }): (string|null);
+    public static fromObject(object: { [k: string]: any }): Package;
+    public static toObject(message: Package, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public toJSON(): { [k: string]: any };
+    public static getTypeUrl(typeUrlPrefix?: string): string;
+}
+
+export namespace Package {
+
+    interface IRepository {
+        type?: (string|null);
+        url?: (string|null);
+    }
+
+    class Repository implements IRepository {
+        constructor(properties?: Package.IRepository);
+        public type: string;
+        public url: string;
+        public static create(properties?: Package.IRepository): Package.Repository;
+        public static encode(message: Package.IRepository, writer?: $protobuf.Writer): $protobuf.Writer;
+        public static encodeDelimited(message: Package.IRepository, writer?: $protobuf.Writer): $protobuf.Writer;
+        public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): Package.Repository;
+        public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): Package.Repository;
+        public static verify(message: { [k: string]: any }): (string|null);
+        public static fromObject(object: { [k: string]: any }): Package.Repository;
+        public static toObject(message: Package.Repository, options?: $protobuf.IConversionOptions): { [k: string]: any };
+        public toJSON(): { [k: string]: any };
+        public static getTypeUrl(typeUrlPrefix?: string): string;
+    }
+}
diff --git a/tests/data/package.js b/tests/data/package.js
new file mode 100644
index 0000000..7a3a1db
--- /dev/null
+++ b/tests/data/package.js
@@ -0,0 +1,970 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+"use strict";
+
+var $protobuf = require("../../minimal");
+
+// Common aliases
+var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+// Exported root namespace
+var $root = $protobuf.roots.test_package || ($protobuf.roots.test_package = {});
+
+$root.Package = (function() {
+
+    /**
+     * Properties of a Package.
+     * @exports IPackage
+     * @interface IPackage
+     * @property {string|null} [name] Package name
+     * @property {string|null} [version] Package version
+     * @property {string|null} [versionScheme] Package versionScheme
+     * @property {string|null} [description] Package description
+     * @property {string|null} [author] Package author
+     * @property {string|null} [license] Package license
+     * @property {Package.IRepository|null} [repository] Package repository
+     * @property {string|null} [bugs] Package bugs
+     * @property {string|null} [homepage] Package homepage
+     * @property {Array.<string>|null} [keywords] Package keywords
+     * @property {string|null} [main] Package main
+     * @property {Object.<string,string>|null} [bin] Package bin
+     * @property {Object.<string,string>|null} [scripts] Package scripts
+     * @property {Object.<string,string>|null} [dependencies] Package dependencies
+     * @property {Object.<string,string>|null} [devDependencies] Package devDependencies
+     * @property {string|null} [types] Package types
+     * @property {Array.<string>|null} [cliDependencies] Package cliDependencies
+     */
+
+    /**
+     * Constructs a new Package.
+     * @exports Package
+     * @classdesc Represents a Package.
+     * @implements IPackage
+     * @constructor
+     * @param {IPackage=} [properties] Properties to set
+     */
+    function Package(properties) {
+        this.keywords = [];
+        this.bin = {};
+        this.scripts = {};
+        this.dependencies = {};
+        this.devDependencies = {};
+        this.cliDependencies = [];
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * Package name.
+     * @member {string} name
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.name = "";
+
+    /**
+     * Package version.
+     * @member {string} version
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.version = "";
+
+    /**
+     * Package versionScheme.
+     * @member {string} versionScheme
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.versionScheme = "";
+
+    /**
+     * Package description.
+     * @member {string} description
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.description = "";
+
+    /**
+     * Package author.
+     * @member {string} author
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.author = "";
+
+    /**
+     * Package license.
+     * @member {string} license
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.license = "";
+
+    /**
+     * Package repository.
+     * @member {Package.IRepository|null|undefined} repository
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.repository = null;
+
+    /**
+     * Package bugs.
+     * @member {string} bugs
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.bugs = "";
+
+    /**
+     * Package homepage.
+     * @member {string} homepage
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.homepage = "";
+
+    /**
+     * Package keywords.
+     * @member {Array.<string>} keywords
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.keywords = $util.emptyArray;
+
+    /**
+     * Package main.
+     * @member {string} main
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.main = "";
+
+    /**
+     * Package bin.
+     * @member {Object.<string,string>} bin
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.bin = $util.emptyObject;
+
+    /**
+     * Package scripts.
+     * @member {Object.<string,string>} scripts
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.scripts = $util.emptyObject;
+
+    /**
+     * Package dependencies.
+     * @member {Object.<string,string>} dependencies
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.dependencies = $util.emptyObject;
+
+    /**
+     * Package devDependencies.
+     * @member {Object.<string,string>} devDependencies
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.devDependencies = $util.emptyObject;
+
+    /**
+     * Package types.
+     * @member {string} types
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.types = "";
+
+    /**
+     * Package cliDependencies.
+     * @member {Array.<string>} cliDependencies
+     * @memberof Package
+     * @instance
+     */
+    Package.prototype.cliDependencies = $util.emptyArray;
+
+    /**
+     * Creates a new Package instance using the specified properties.
+     * @function create
+     * @memberof Package
+     * @static
+     * @param {IPackage=} [properties] Properties to set
+     * @returns {Package} Package instance
+     */
+    Package.create = function create(properties) {
+        return new Package(properties);
+    };
+
+    /**
+     * Encodes the specified Package message. Does not implicitly {@link Package.verify|verify} messages.
+     * @function encode
+     * @memberof Package
+     * @static
+     * @param {IPackage} message Package message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    Package.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.name != null && Object.hasOwnProperty.call(message, "name"))
+            writer.uint32(/* id 1, wireType 2 =*/10).string(message.name);
+        if (message.version != null && Object.hasOwnProperty.call(message, "version"))
+            writer.uint32(/* id 2, wireType 2 =*/18).string(message.version);
+        if (message.description != null && Object.hasOwnProperty.call(message, "description"))
+            writer.uint32(/* id 3, wireType 2 =*/26).string(message.description);
+        if (message.author != null && Object.hasOwnProperty.call(message, "author"))
+            writer.uint32(/* id 4, wireType 2 =*/34).string(message.author);
+        if (message.license != null && Object.hasOwnProperty.call(message, "license"))
+            writer.uint32(/* id 5, wireType 2 =*/42).string(message.license);
+        if (message.repository != null && Object.hasOwnProperty.call(message, "repository"))
+            $root.Package.Repository.encode(message.repository, writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim();
+        if (message.bugs != null && Object.hasOwnProperty.call(message, "bugs"))
+            writer.uint32(/* id 7, wireType 2 =*/58).string(message.bugs);
+        if (message.homepage != null && Object.hasOwnProperty.call(message, "homepage"))
+            writer.uint32(/* id 8, wireType 2 =*/66).string(message.homepage);
+        if (message.keywords != null && message.keywords.length)
+            for (var i = 0; i < message.keywords.length; ++i)
+                writer.uint32(/* id 9, wireType 2 =*/74).string(message.keywords[i]);
+        if (message.main != null && Object.hasOwnProperty.call(message, "main"))
+            writer.uint32(/* id 10, wireType 2 =*/82).string(message.main);
+        if (message.bin != null && Object.hasOwnProperty.call(message, "bin"))
+            for (var keys = Object.keys(message.bin), i = 0; i < keys.length; ++i)
+                writer.uint32(/* id 11, wireType 2 =*/90).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]).uint32(/* id 2, wireType 2 =*/18).string(message.bin[keys[i]]).ldelim();
+        if (message.scripts != null && Object.hasOwnProperty.call(message, "scripts"))
+            for (var keys = Object.keys(message.scripts), i = 0; i < keys.length; ++i)
+                writer.uint32(/* id 12, wireType 2 =*/98).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]).uint32(/* id 2, wireType 2 =*/18).string(message.scripts[keys[i]]).ldelim();
+        if (message.dependencies != null && Object.hasOwnProperty.call(message, "dependencies"))
+            for (var keys = Object.keys(message.dependencies), i = 0; i < keys.length; ++i)
+                writer.uint32(/* id 13, wireType 2 =*/106).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]).uint32(/* id 2, wireType 2 =*/18).string(message.dependencies[keys[i]]).ldelim();
+        if (message.devDependencies != null && Object.hasOwnProperty.call(message, "devDependencies"))
+            for (var keys = Object.keys(message.devDependencies), i = 0; i < keys.length; ++i)
+                writer.uint32(/* id 15, wireType 2 =*/122).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]).uint32(/* id 2, wireType 2 =*/18).string(message.devDependencies[keys[i]]).ldelim();
+        if (message.types != null && Object.hasOwnProperty.call(message, "types"))
+            writer.uint32(/* id 17, wireType 2 =*/138).string(message.types);
+        if (message.cliDependencies != null && message.cliDependencies.length)
+            for (var i = 0; i < message.cliDependencies.length; ++i)
+                writer.uint32(/* id 18, wireType 2 =*/146).string(message.cliDependencies[i]);
+        if (message.versionScheme != null && Object.hasOwnProperty.call(message, "versionScheme"))
+            writer.uint32(/* id 19, wireType 2 =*/154).string(message.versionScheme);
+        return writer;
+    };
+
+    /**
+     * Encodes the specified Package message, length delimited. Does not implicitly {@link Package.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof Package
+     * @static
+     * @param {IPackage} message Package message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    Package.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a Package message from the specified reader or buffer.
+     * @function decode
+     * @memberof Package
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {Package} Package
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    Package.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Package(), key, value;
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 1:
+                message.name = reader.string();
+                break;
+            case 2:
+                message.version = reader.string();
+                break;
+            case 19:
+                message.versionScheme = reader.string();
+                break;
+            case 3:
+                message.description = reader.string();
+                break;
+            case 4:
+                message.author = reader.string();
+                break;
+            case 5:
+                message.license = reader.string();
+                break;
+            case 6:
+                message.repository = $root.Package.Repository.decode(reader, reader.uint32());
+                break;
+            case 7:
+                message.bugs = reader.string();
+                break;
+            case 8:
+                message.homepage = reader.string();
+                break;
+            case 9:
+                if (!(message.keywords && message.keywords.length))
+                    message.keywords = [];
+                message.keywords.push(reader.string());
+                break;
+            case 10:
+                message.main = reader.string();
+                break;
+            case 11:
+                if (message.bin === $util.emptyObject)
+                    message.bin = {};
+                var end2 = reader.uint32() + reader.pos;
+                key = "";
+                value = "";
+                while (reader.pos < end2) {
+                    var tag2 = reader.uint32();
+                    switch (tag2 >>> 3) {
+                    case 1:
+                        key = reader.string();
+                        break;
+                    case 2:
+                        value = reader.string();
+                        break;
+                    default:
+                        reader.skipType(tag2 & 7);
+                        break;
+                    }
+                }
+                message.bin[key] = value;
+                break;
+            case 12:
+                if (message.scripts === $util.emptyObject)
+                    message.scripts = {};
+                var end2 = reader.uint32() + reader.pos;
+                key = "";
+                value = "";
+                while (reader.pos < end2) {
+                    var tag2 = reader.uint32();
+                    switch (tag2 >>> 3) {
+                    case 1:
+                        key = reader.string();
+                        break;
+                    case 2:
+                        value = reader.string();
+                        break;
+                    default:
+                        reader.skipType(tag2 & 7);
+                        break;
+                    }
+                }
+                message.scripts[key] = value;
+                break;
+            case 13:
+                if (message.dependencies === $util.emptyObject)
+                    message.dependencies = {};
+                var end2 = reader.uint32() + reader.pos;
+                key = "";
+                value = "";
+                while (reader.pos < end2) {
+                    var tag2 = reader.uint32();
+                    switch (tag2 >>> 3) {
+                    case 1:
+                        key = reader.string();
+                        break;
+                    case 2:
+                        value = reader.string();
+                        break;
+                    default:
+                        reader.skipType(tag2 & 7);
+                        break;
+                    }
+                }
+                message.dependencies[key] = value;
+                break;
+            case 15:
+                if (message.devDependencies === $util.emptyObject)
+                    message.devDependencies = {};
+                var end2 = reader.uint32() + reader.pos;
+                key = "";
+                value = "";
+                while (reader.pos < end2) {
+                    var tag2 = reader.uint32();
+                    switch (tag2 >>> 3) {
+                    case 1:
+                        key = reader.string();
+                        break;
+                    case 2:
+                        value = reader.string();
+                        break;
+                    default:
+                        reader.skipType(tag2 & 7);
+                        break;
+                    }
+                }
+                message.devDependencies[key] = value;
+                break;
+            case 17:
+                message.types = reader.string();
+                break;
+            case 18:
+                if (!(message.cliDependencies && message.cliDependencies.length))
+                    message.cliDependencies = [];
+                message.cliDependencies.push(reader.string());
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a Package message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof Package
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {Package} Package
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    Package.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a Package message.
+     * @function verify
+     * @memberof Package
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    Package.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.name != null && message.hasOwnProperty("name"))
+            if (!$util.isString(message.name))
+                return "name: string expected";
+        if (message.version != null && message.hasOwnProperty("version"))
+            if (!$util.isString(message.version))
+                return "version: string expected";
+        if (message.versionScheme != null && message.hasOwnProperty("versionScheme"))
+            if (!$util.isString(message.versionScheme))
+                return "versionScheme: string expected";
+        if (message.description != null && message.hasOwnProperty("description"))
+            if (!$util.isString(message.description))
+                return "description: string expected";
+        if (message.author != null && message.hasOwnProperty("author"))
+            if (!$util.isString(message.author))
+                return "author: string expected";
+        if (message.license != null && message.hasOwnProperty("license"))
+            if (!$util.isString(message.license))
+                return "license: string expected";
+        if (message.repository != null && message.hasOwnProperty("repository")) {
+            var error = $root.Package.Repository.verify(message.repository);
+            if (error)
+                return "repository." + error;
+        }
+        if (message.bugs != null && message.hasOwnProperty("bugs"))
+            if (!$util.isString(message.bugs))
+                return "bugs: string expected";
+        if (message.homepage != null && message.hasOwnProperty("homepage"))
+            if (!$util.isString(message.homepage))
+                return "homepage: string expected";
+        if (message.keywords != null && message.hasOwnProperty("keywords")) {
+            if (!Array.isArray(message.keywords))
+                return "keywords: array expected";
+            for (var i = 0; i < message.keywords.length; ++i)
+                if (!$util.isString(message.keywords[i]))
+                    return "keywords: string[] expected";
+        }
+        if (message.main != null && message.hasOwnProperty("main"))
+            if (!$util.isString(message.main))
+                return "main: string expected";
+        if (message.bin != null && message.hasOwnProperty("bin")) {
+            if (!$util.isObject(message.bin))
+                return "bin: object expected";
+            var key = Object.keys(message.bin);
+            for (var i = 0; i < key.length; ++i)
+                if (!$util.isString(message.bin[key[i]]))
+                    return "bin: string{k:string} expected";
+        }
+        if (message.scripts != null && message.hasOwnProperty("scripts")) {
+            if (!$util.isObject(message.scripts))
+                return "scripts: object expected";
+            var key = Object.keys(message.scripts);
+            for (var i = 0; i < key.length; ++i)
+                if (!$util.isString(message.scripts[key[i]]))
+                    return "scripts: string{k:string} expected";
+        }
+        if (message.dependencies != null && message.hasOwnProperty("dependencies")) {
+            if (!$util.isObject(message.dependencies))
+                return "dependencies: object expected";
+            var key = Object.keys(message.dependencies);
+            for (var i = 0; i < key.length; ++i)
+                if (!$util.isString(message.dependencies[key[i]]))
+                    return "dependencies: string{k:string} expected";
+        }
+        if (message.devDependencies != null && message.hasOwnProperty("devDependencies")) {
+            if (!$util.isObject(message.devDependencies))
+                return "devDependencies: object expected";
+            var key = Object.keys(message.devDependencies);
+            for (var i = 0; i < key.length; ++i)
+                if (!$util.isString(message.devDependencies[key[i]]))
+                    return "devDependencies: string{k:string} expected";
+        }
+        if (message.types != null && message.hasOwnProperty("types"))
+            if (!$util.isString(message.types))
+                return "types: string expected";
+        if (message.cliDependencies != null && message.hasOwnProperty("cliDependencies")) {
+            if (!Array.isArray(message.cliDependencies))
+                return "cliDependencies: array expected";
+            for (var i = 0; i < message.cliDependencies.length; ++i)
+                if (!$util.isString(message.cliDependencies[i]))
+                    return "cliDependencies: string[] expected";
+        }
+        return null;
+    };
+
+    /**
+     * Creates a Package message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof Package
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {Package} Package
+     */
+    Package.fromObject = function fromObject(object) {
+        if (object instanceof $root.Package)
+            return object;
+        var message = new $root.Package();
+        if (object.name != null)
+            message.name = String(object.name);
+        if (object.version != null)
+            message.version = String(object.version);
+        if (object.versionScheme != null)
+            message.versionScheme = String(object.versionScheme);
+        if (object.description != null)
+            message.description = String(object.description);
+        if (object.author != null)
+            message.author = String(object.author);
+        if (object.license != null)
+            message.license = String(object.license);
+        if (object.repository != null) {
+            if (typeof object.repository !== "object")
+                throw TypeError(".Package.repository: object expected");
+            message.repository = $root.Package.Repository.fromObject(object.repository);
+        }
+        if (object.bugs != null)
+            message.bugs = String(object.bugs);
+        if (object.homepage != null)
+            message.homepage = String(object.homepage);
+        if (object.keywords) {
+            if (!Array.isArray(object.keywords))
+                throw TypeError(".Package.keywords: array expected");
+            message.keywords = [];
+            for (var i = 0; i < object.keywords.length; ++i)
+                message.keywords[i] = String(object.keywords[i]);
+        }
+        if (object.main != null)
+            message.main = String(object.main);
+        if (object.bin) {
+            if (typeof object.bin !== "object")
+                throw TypeError(".Package.bin: object expected");
+            message.bin = {};
+            for (var keys = Object.keys(object.bin), i = 0; i < keys.length; ++i)
+                message.bin[keys[i]] = String(object.bin[keys[i]]);
+        }
+        if (object.scripts) {
+            if (typeof object.scripts !== "object")
+                throw TypeError(".Package.scripts: object expected");
+            message.scripts = {};
+            for (var keys = Object.keys(object.scripts), i = 0; i < keys.length; ++i)
+                message.scripts[keys[i]] = String(object.scripts[keys[i]]);
+        }
+        if (object.dependencies) {
+            if (typeof object.dependencies !== "object")
+                throw TypeError(".Package.dependencies: object expected");
+            message.dependencies = {};
+            for (var keys = Object.keys(object.dependencies), i = 0; i < keys.length; ++i)
+                message.dependencies[keys[i]] = String(object.dependencies[keys[i]]);
+        }
+        if (object.devDependencies) {
+            if (typeof object.devDependencies !== "object")
+                throw TypeError(".Package.devDependencies: object expected");
+            message.devDependencies = {};
+            for (var keys = Object.keys(object.devDependencies), i = 0; i < keys.length; ++i)
+                message.devDependencies[keys[i]] = String(object.devDependencies[keys[i]]);
+        }
+        if (object.types != null)
+            message.types = String(object.types);
+        if (object.cliDependencies) {
+            if (!Array.isArray(object.cliDependencies))
+                throw TypeError(".Package.cliDependencies: array expected");
+            message.cliDependencies = [];
+            for (var i = 0; i < object.cliDependencies.length; ++i)
+                message.cliDependencies[i] = String(object.cliDependencies[i]);
+        }
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a Package message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof Package
+     * @static
+     * @param {Package} message Package
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    Package.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        var object = {};
+        if (options.arrays || options.defaults) {
+            object.keywords = [];
+            object.cliDependencies = [];
+        }
+        if (options.objects || options.defaults) {
+            object.bin = {};
+            object.scripts = {};
+            object.dependencies = {};
+            object.devDependencies = {};
+        }
+        if (options.defaults) {
+            object.name = "";
+            object.version = "";
+            object.description = "";
+            object.author = "";
+            object.license = "";
+            object.repository = null;
+            object.bugs = "";
+            object.homepage = "";
+            object.main = "";
+            object.types = "";
+            object.versionScheme = "";
+        }
+        if (message.name != null && message.hasOwnProperty("name"))
+            object.name = message.name;
+        if (message.version != null && message.hasOwnProperty("version"))
+            object.version = message.version;
+        if (message.description != null && message.hasOwnProperty("description"))
+            object.description = message.description;
+        if (message.author != null && message.hasOwnProperty("author"))
+            object.author = message.author;
+        if (message.license != null && message.hasOwnProperty("license"))
+            object.license = message.license;
+        if (message.repository != null && message.hasOwnProperty("repository"))
+            object.repository = $root.Package.Repository.toObject(message.repository, options);
+        if (message.bugs != null && message.hasOwnProperty("bugs"))
+            object.bugs = message.bugs;
+        if (message.homepage != null && message.hasOwnProperty("homepage"))
+            object.homepage = message.homepage;
+        if (message.keywords && message.keywords.length) {
+            object.keywords = [];
+            for (var j = 0; j < message.keywords.length; ++j)
+                object.keywords[j] = message.keywords[j];
+        }
+        if (message.main != null && message.hasOwnProperty("main"))
+            object.main = message.main;
+        var keys2;
+        if (message.bin && (keys2 = Object.keys(message.bin)).length) {
+            object.bin = {};
+            for (var j = 0; j < keys2.length; ++j)
+                object.bin[keys2[j]] = message.bin[keys2[j]];
+        }
+        if (message.scripts && (keys2 = Object.keys(message.scripts)).length) {
+            object.scripts = {};
+            for (var j = 0; j < keys2.length; ++j)
+                object.scripts[keys2[j]] = message.scripts[keys2[j]];
+        }
+        if (message.dependencies && (keys2 = Object.keys(message.dependencies)).length) {
+            object.dependencies = {};
+            for (var j = 0; j < keys2.length; ++j)
+                object.dependencies[keys2[j]] = message.dependencies[keys2[j]];
+        }
+        if (message.devDependencies && (keys2 = Object.keys(message.devDependencies)).length) {
+            object.devDependencies = {};
+            for (var j = 0; j < keys2.length; ++j)
+                object.devDependencies[keys2[j]] = message.devDependencies[keys2[j]];
+        }
+        if (message.types != null && message.hasOwnProperty("types"))
+            object.types = message.types;
+        if (message.cliDependencies && message.cliDependencies.length) {
+            object.cliDependencies = [];
+            for (var j = 0; j < message.cliDependencies.length; ++j)
+                object.cliDependencies[j] = message.cliDependencies[j];
+        }
+        if (message.versionScheme != null && message.hasOwnProperty("versionScheme"))
+            object.versionScheme = message.versionScheme;
+        return object;
+    };
+
+    /**
+     * Converts this Package to JSON.
+     * @function toJSON
+     * @memberof Package
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    Package.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    /**
+     * Gets the default type url for Package
+     * @function getTypeUrl
+     * @memberof Package
+     * @static
+     * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+     * @returns {string} The default type url
+     */
+    Package.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+        if (typeUrlPrefix === undefined) {
+            typeUrlPrefix = "type.googleapis.com";
+        }
+        return typeUrlPrefix + "/Package";
+    };
+
+    Package.Repository = (function() {
+
+        /**
+         * Properties of a Repository.
+         * @memberof Package
+         * @interface IRepository
+         * @property {string|null} [type] Repository type
+         * @property {string|null} [url] Repository url
+         */
+
+        /**
+         * Constructs a new Repository.
+         * @memberof Package
+         * @classdesc Represents a Repository.
+         * @implements IRepository
+         * @constructor
+         * @param {Package.IRepository=} [properties] Properties to set
+         */
+        function Repository(properties) {
+            if (properties)
+                for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                    if (properties[keys[i]] != null)
+                        this[keys[i]] = properties[keys[i]];
+        }
+
+        /**
+         * Repository type.
+         * @member {string} type
+         * @memberof Package.Repository
+         * @instance
+         */
+        Repository.prototype.type = "";
+
+        /**
+         * Repository url.
+         * @member {string} url
+         * @memberof Package.Repository
+         * @instance
+         */
+        Repository.prototype.url = "";
+
+        /**
+         * Creates a new Repository instance using the specified properties.
+         * @function create
+         * @memberof Package.Repository
+         * @static
+         * @param {Package.IRepository=} [properties] Properties to set
+         * @returns {Package.Repository} Repository instance
+         */
+        Repository.create = function create(properties) {
+            return new Repository(properties);
+        };
+
+        /**
+         * Encodes the specified Repository message. Does not implicitly {@link Package.Repository.verify|verify} messages.
+         * @function encode
+         * @memberof Package.Repository
+         * @static
+         * @param {Package.IRepository} message Repository message or plain object to encode
+         * @param {$protobuf.Writer} [writer] Writer to encode to
+         * @returns {$protobuf.Writer} Writer
+         */
+        Repository.encode = function encode(message, writer) {
+            if (!writer)
+                writer = $Writer.create();
+            if (message.type != null && Object.hasOwnProperty.call(message, "type"))
+                writer.uint32(/* id 1, wireType 2 =*/10).string(message.type);
+            if (message.url != null && Object.hasOwnProperty.call(message, "url"))
+                writer.uint32(/* id 2, wireType 2 =*/18).string(message.url);
+            return writer;
+        };
+
+        /**
+         * Encodes the specified Repository message, length delimited. Does not implicitly {@link Package.Repository.verify|verify} messages.
+         * @function encodeDelimited
+         * @memberof Package.Repository
+         * @static
+         * @param {Package.IRepository} message Repository message or plain object to encode
+         * @param {$protobuf.Writer} [writer] Writer to encode to
+         * @returns {$protobuf.Writer} Writer
+         */
+        Repository.encodeDelimited = function encodeDelimited(message, writer) {
+            return this.encode(message, writer).ldelim();
+        };
+
+        /**
+         * Decodes a Repository message from the specified reader or buffer.
+         * @function decode
+         * @memberof Package.Repository
+         * @static
+         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+         * @param {number} [length] Message length if known beforehand
+         * @returns {Package.Repository} Repository
+         * @throws {Error} If the payload is not a reader or valid buffer
+         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+         */
+        Repository.decode = function decode(reader, length) {
+            if (!(reader instanceof $Reader))
+                reader = $Reader.create(reader);
+            var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Package.Repository();
+            while (reader.pos < end) {
+                var tag = reader.uint32();
+                switch (tag >>> 3) {
+                case 1:
+                    message.type = reader.string();
+                    break;
+                case 2:
+                    message.url = reader.string();
+                    break;
+                default:
+                    reader.skipType(tag & 7);
+                    break;
+                }
+            }
+            return message;
+        };
+
+        /**
+         * Decodes a Repository message from the specified reader or buffer, length delimited.
+         * @function decodeDelimited
+         * @memberof Package.Repository
+         * @static
+         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+         * @returns {Package.Repository} Repository
+         * @throws {Error} If the payload is not a reader or valid buffer
+         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+         */
+        Repository.decodeDelimited = function decodeDelimited(reader) {
+            if (!(reader instanceof $Reader))
+                reader = new $Reader(reader);
+            return this.decode(reader, reader.uint32());
+        };
+
+        /**
+         * Verifies a Repository message.
+         * @function verify
+         * @memberof Package.Repository
+         * @static
+         * @param {Object.<string,*>} message Plain object to verify
+         * @returns {string|null} `null` if valid, otherwise the reason why it is not
+         */
+        Repository.verify = function verify(message) {
+            if (typeof message !== "object" || message === null)
+                return "object expected";
+            if (message.type != null && message.hasOwnProperty("type"))
+                if (!$util.isString(message.type))
+                    return "type: string expected";
+            if (message.url != null && message.hasOwnProperty("url"))
+                if (!$util.isString(message.url))
+                    return "url: string expected";
+            return null;
+        };
+
+        /**
+         * Creates a Repository message from a plain object. Also converts values to their respective internal types.
+         * @function fromObject
+         * @memberof Package.Repository
+         * @static
+         * @param {Object.<string,*>} object Plain object
+         * @returns {Package.Repository} Repository
+         */
+        Repository.fromObject = function fromObject(object) {
+            if (object instanceof $root.Package.Repository)
+                return object;
+            var message = new $root.Package.Repository();
+            if (object.type != null)
+                message.type = String(object.type);
+            if (object.url != null)
+                message.url = String(object.url);
+            return message;
+        };
+
+        /**
+         * Creates a plain object from a Repository message. Also converts values to other types if specified.
+         * @function toObject
+         * @memberof Package.Repository
+         * @static
+         * @param {Package.Repository} message Repository
+         * @param {$protobuf.IConversionOptions} [options] Conversion options
+         * @returns {Object.<string,*>} Plain object
+         */
+        Repository.toObject = function toObject(message, options) {
+            if (!options)
+                options = {};
+            var object = {};
+            if (options.defaults) {
+                object.type = "";
+                object.url = "";
+            }
+            if (message.type != null && message.hasOwnProperty("type"))
+                object.type = message.type;
+            if (message.url != null && message.hasOwnProperty("url"))
+                object.url = message.url;
+            return object;
+        };
+
+        /**
+         * Converts this Repository to JSON.
+         * @function toJSON
+         * @memberof Package.Repository
+         * @instance
+         * @returns {Object.<string,*>} JSON object
+         */
+        Repository.prototype.toJSON = function toJSON() {
+            return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+        };
+
+        /**
+         * Gets the default type url for Repository
+         * @function getTypeUrl
+         * @memberof Package.Repository
+         * @static
+         * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+         * @returns {string} The default type url
+         */
+        Repository.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+            if (typeUrlPrefix === undefined) {
+                typeUrlPrefix = "type.googleapis.com";
+            }
+            return typeUrlPrefix + "/Package.Repository";
+        };
+
+        return Repository;
+    })();
+
+    return Package;
+})();
+
+module.exports = $root;
diff --git a/tests/data/package.proto b/tests/data/package.proto
new file mode 100644
index 0000000..cf441c5
--- /dev/null
+++ b/tests/data/package.proto
@@ -0,0 +1,29 @@
+syntax = "proto3";
+
+message Package {
+    string name = 1;
+    string version = 2;
+    string versionScheme = 19;
+    string description = 3;
+    string author = 4;
+    string license = 5;
+
+    message Repository {
+        string type = 1;
+        string url = 2;
+    }
+
+    Repository repository = 6;
+    string bugs = 7;
+    string homepage = 8;
+    repeated string keywords = 9;
+    string main = 10;
+    map<string, string> bin = 11;
+    map<string, string> scripts = 12;
+    map<string, string> dependencies = 13;
+    // map<string, string> optionalDependencies = 14;
+    map<string, string> devDependencies = 15;
+    // map<string, bool>   browser = 16;
+    string types = 17;
+    repeated string cliDependencies = 18;
+}
diff --git a/tests/data/rpc-es6.d.ts b/tests/data/rpc-es6.d.ts
new file mode 100644
index 0000000..5cebb4c
--- /dev/null
+++ b/tests/data/rpc-es6.d.ts
@@ -0,0 +1,50 @@
+import * as $protobuf from "../..";
+export class MyService extends $protobuf.rpc.Service {
+    constructor(rpcImpl: $protobuf.RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean);
+    public static create(rpcImpl: $protobuf.RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean): MyService;
+    public myMethod(request: IMyRequest, callback: MyService.MyMethodCallback): void;
+    public myMethod(request: IMyRequest): Promise<MyResponse>;
+}
+
+export namespace MyService {
+
+    type MyMethodCallback = (error: (Error|null), response?: MyResponse) => void;
+}
+
+export interface IMyRequest {
+    path?: (string|null);
+}
+
+export class MyRequest implements IMyRequest {
+    constructor(properties?: IMyRequest);
+    public path: string;
+    public static create(properties?: IMyRequest): MyRequest;
+    public static encode(message: IMyRequest, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: IMyRequest, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): MyRequest;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): MyRequest;
+    public static verify(message: { [k: string]: any }): (string|null);
+    public static fromObject(object: { [k: string]: any }): MyRequest;
+    public static toObject(message: MyRequest, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public toJSON(): { [k: string]: any };
+    public static getTypeUrl(typeUrlPrefix?: string): string;
+}
+
+export interface IMyResponse {
+    status?: (number|null);
+}
+
+export class MyResponse implements IMyResponse {
+    constructor(properties?: IMyResponse);
+    public status: number;
+    public static create(properties?: IMyResponse): MyResponse;
+    public static encode(message: IMyResponse, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: IMyResponse, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): MyResponse;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): MyResponse;
+    public static verify(message: { [k: string]: any }): (string|null);
+    public static fromObject(object: { [k: string]: any }): MyResponse;
+    public static toObject(message: MyResponse, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public toJSON(): { [k: string]: any };
+    public static getTypeUrl(typeUrlPrefix?: string): string;
+}
diff --git a/tests/data/rpc-es6.js b/tests/data/rpc-es6.js
new file mode 100644
index 0000000..71f4ac6
--- /dev/null
+++ b/tests/data/rpc-es6.js
@@ -0,0 +1,482 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+import * as $protobuf from "../../minimal";
+
+// Common aliases
+const $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+// Exported root namespace
+const $root = $protobuf.roots.test_rpc || ($protobuf.roots.test_rpc = {});
+
+export const MyService = $root.MyService = (() => {
+
+    /**
+     * Constructs a new MyService service.
+     * @exports MyService
+     * @classdesc Represents a MyService
+     * @extends $protobuf.rpc.Service
+     * @constructor
+     * @param {$protobuf.RPCImpl} rpcImpl RPC implementation
+     * @param {boolean} [requestDelimited=false] Whether requests are length-delimited
+     * @param {boolean} [responseDelimited=false] Whether responses are length-delimited
+     */
+    function MyService(rpcImpl, requestDelimited, responseDelimited) {
+        $protobuf.rpc.Service.call(this, rpcImpl, requestDelimited, responseDelimited);
+    }
+
+    (MyService.prototype = Object.create($protobuf.rpc.Service.prototype)).constructor = MyService;
+
+    /**
+     * Creates new MyService service using the specified rpc implementation.
+     * @function create
+     * @memberof MyService
+     * @static
+     * @param {$protobuf.RPCImpl} rpcImpl RPC implementation
+     * @param {boolean} [requestDelimited=false] Whether requests are length-delimited
+     * @param {boolean} [responseDelimited=false] Whether responses are length-delimited
+     * @returns {MyService} RPC service. Useful where requests and/or responses are streamed.
+     */
+    MyService.create = function create(rpcImpl, requestDelimited, responseDelimited) {
+        return new this(rpcImpl, requestDelimited, responseDelimited);
+    };
+
+    /**
+     * Callback as used by {@link MyService#myMethod}.
+     * @memberof MyService
+     * @typedef MyMethodCallback
+     * @type {function}
+     * @param {Error|null} error Error, if any
+     * @param {MyResponse} [response] MyResponse
+     */
+
+    /**
+     * Calls MyMethod.
+     * @function myMethod
+     * @memberof MyService
+     * @instance
+     * @param {IMyRequest} request MyRequest message or plain object
+     * @param {MyService.MyMethodCallback} callback Node-style callback called with the error, if any, and MyResponse
+     * @returns {undefined}
+     * @variation 1
+     */
+    Object.defineProperty(MyService.prototype.myMethod = function myMethod(request, callback) {
+        return this.rpcCall(myMethod, $root.MyRequest, $root.MyResponse, request, callback);
+    }, "name", { value: "MyMethod" });
+
+    /**
+     * Calls MyMethod.
+     * @function myMethod
+     * @memberof MyService
+     * @instance
+     * @param {IMyRequest} request MyRequest message or plain object
+     * @returns {Promise<MyResponse>} Promise
+     * @variation 2
+     */
+
+    return MyService;
+})();
+
+export const MyRequest = $root.MyRequest = (() => {
+
+    /**
+     * Properties of a MyRequest.
+     * @exports IMyRequest
+     * @interface IMyRequest
+     * @property {string|null} [path] MyRequest path
+     */
+
+    /**
+     * Constructs a new MyRequest.
+     * @exports MyRequest
+     * @classdesc Represents a MyRequest.
+     * @implements IMyRequest
+     * @constructor
+     * @param {IMyRequest=} [properties] Properties to set
+     */
+    function MyRequest(properties) {
+        if (properties)
+            for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * MyRequest path.
+     * @member {string} path
+     * @memberof MyRequest
+     * @instance
+     */
+    MyRequest.prototype.path = "";
+
+    /**
+     * Creates a new MyRequest instance using the specified properties.
+     * @function create
+     * @memberof MyRequest
+     * @static
+     * @param {IMyRequest=} [properties] Properties to set
+     * @returns {MyRequest} MyRequest instance
+     */
+    MyRequest.create = function create(properties) {
+        return new MyRequest(properties);
+    };
+
+    /**
+     * Encodes the specified MyRequest message. Does not implicitly {@link MyRequest.verify|verify} messages.
+     * @function encode
+     * @memberof MyRequest
+     * @static
+     * @param {IMyRequest} message MyRequest message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    MyRequest.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.path != null && Object.hasOwnProperty.call(message, "path"))
+            writer.uint32(/* id 1, wireType 2 =*/10).string(message.path);
+        return writer;
+    };
+
+    /**
+     * Encodes the specified MyRequest message, length delimited. Does not implicitly {@link MyRequest.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof MyRequest
+     * @static
+     * @param {IMyRequest} message MyRequest message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    MyRequest.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a MyRequest message from the specified reader or buffer.
+     * @function decode
+     * @memberof MyRequest
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {MyRequest} MyRequest
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    MyRequest.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        let end = length === undefined ? reader.len : reader.pos + length, message = new $root.MyRequest();
+        while (reader.pos < end) {
+            let tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 1:
+                message.path = reader.string();
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a MyRequest message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof MyRequest
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {MyRequest} MyRequest
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    MyRequest.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a MyRequest message.
+     * @function verify
+     * @memberof MyRequest
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    MyRequest.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.path != null && message.hasOwnProperty("path"))
+            if (!$util.isString(message.path))
+                return "path: string expected";
+        return null;
+    };
+
+    /**
+     * Creates a MyRequest message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof MyRequest
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {MyRequest} MyRequest
+     */
+    MyRequest.fromObject = function fromObject(object) {
+        if (object instanceof $root.MyRequest)
+            return object;
+        let message = new $root.MyRequest();
+        if (object.path != null)
+            message.path = String(object.path);
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a MyRequest message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof MyRequest
+     * @static
+     * @param {MyRequest} message MyRequest
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    MyRequest.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        let object = {};
+        if (options.defaults)
+            object.path = "";
+        if (message.path != null && message.hasOwnProperty("path"))
+            object.path = message.path;
+        return object;
+    };
+
+    /**
+     * Converts this MyRequest to JSON.
+     * @function toJSON
+     * @memberof MyRequest
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    MyRequest.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    /**
+     * Gets the default type url for MyRequest
+     * @function getTypeUrl
+     * @memberof MyRequest
+     * @static
+     * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+     * @returns {string} The default type url
+     */
+    MyRequest.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+        if (typeUrlPrefix === undefined) {
+            typeUrlPrefix = "type.googleapis.com";
+        }
+        return typeUrlPrefix + "/MyRequest";
+    };
+
+    return MyRequest;
+})();
+
+export const MyResponse = $root.MyResponse = (() => {
+
+    /**
+     * Properties of a MyResponse.
+     * @exports IMyResponse
+     * @interface IMyResponse
+     * @property {number|null} [status] MyResponse status
+     */
+
+    /**
+     * Constructs a new MyResponse.
+     * @exports MyResponse
+     * @classdesc Represents a MyResponse.
+     * @implements IMyResponse
+     * @constructor
+     * @param {IMyResponse=} [properties] Properties to set
+     */
+    function MyResponse(properties) {
+        if (properties)
+            for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * MyResponse status.
+     * @member {number} status
+     * @memberof MyResponse
+     * @instance
+     */
+    MyResponse.prototype.status = 0;
+
+    /**
+     * Creates a new MyResponse instance using the specified properties.
+     * @function create
+     * @memberof MyResponse
+     * @static
+     * @param {IMyResponse=} [properties] Properties to set
+     * @returns {MyResponse} MyResponse instance
+     */
+    MyResponse.create = function create(properties) {
+        return new MyResponse(properties);
+    };
+
+    /**
+     * Encodes the specified MyResponse message. Does not implicitly {@link MyResponse.verify|verify} messages.
+     * @function encode
+     * @memberof MyResponse
+     * @static
+     * @param {IMyResponse} message MyResponse message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    MyResponse.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.status != null && Object.hasOwnProperty.call(message, "status"))
+            writer.uint32(/* id 2, wireType 0 =*/16).int32(message.status);
+        return writer;
+    };
+
+    /**
+     * Encodes the specified MyResponse message, length delimited. Does not implicitly {@link MyResponse.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof MyResponse
+     * @static
+     * @param {IMyResponse} message MyResponse message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    MyResponse.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a MyResponse message from the specified reader or buffer.
+     * @function decode
+     * @memberof MyResponse
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {MyResponse} MyResponse
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    MyResponse.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        let end = length === undefined ? reader.len : reader.pos + length, message = new $root.MyResponse();
+        while (reader.pos < end) {
+            let tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 2:
+                message.status = reader.int32();
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a MyResponse message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof MyResponse
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {MyResponse} MyResponse
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    MyResponse.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a MyResponse message.
+     * @function verify
+     * @memberof MyResponse
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    MyResponse.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.status != null && message.hasOwnProperty("status"))
+            if (!$util.isInteger(message.status))
+                return "status: integer expected";
+        return null;
+    };
+
+    /**
+     * Creates a MyResponse message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof MyResponse
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {MyResponse} MyResponse
+     */
+    MyResponse.fromObject = function fromObject(object) {
+        if (object instanceof $root.MyResponse)
+            return object;
+        let message = new $root.MyResponse();
+        if (object.status != null)
+            message.status = object.status | 0;
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a MyResponse message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof MyResponse
+     * @static
+     * @param {MyResponse} message MyResponse
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    MyResponse.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        let object = {};
+        if (options.defaults)
+            object.status = 0;
+        if (message.status != null && message.hasOwnProperty("status"))
+            object.status = message.status;
+        return object;
+    };
+
+    /**
+     * Converts this MyResponse to JSON.
+     * @function toJSON
+     * @memberof MyResponse
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    MyResponse.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    /**
+     * Gets the default type url for MyResponse
+     * @function getTypeUrl
+     * @memberof MyResponse
+     * @static
+     * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+     * @returns {string} The default type url
+     */
+    MyResponse.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+        if (typeUrlPrefix === undefined) {
+            typeUrlPrefix = "type.googleapis.com";
+        }
+        return typeUrlPrefix + "/MyResponse";
+    };
+
+    return MyResponse;
+})();
+
+export { $root as default };
diff --git a/tests/data/rpc-reserved.d.ts b/tests/data/rpc-reserved.d.ts
new file mode 100644
index 0000000..cf2455b
--- /dev/null
+++ b/tests/data/rpc-reserved.d.ts
@@ -0,0 +1,50 @@
+import * as $protobuf from "../..";
+export class MyService extends $protobuf.rpc.Service {
+    constructor(rpcImpl: $protobuf.RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean);
+    public static create(rpcImpl: $protobuf.RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean): MyService;
+    public delete(request: IMyRequest, callback: MyService.DeleteCallback): void;
+    public delete(request: IMyRequest): Promise<MyResponse>;
+}
+
+export namespace MyService {
+
+    type DeleteCallback = (error: (Error|null), response?: MyResponse) => void;
+}
+
+export interface IMyRequest {
+    path?: (string|null);
+}
+
+export class MyRequest implements IMyRequest {
+    constructor(properties?: IMyRequest);
+    public path: string;
+    public static create(properties?: IMyRequest): MyRequest;
+    public static encode(message: IMyRequest, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: IMyRequest, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): MyRequest;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): MyRequest;
+    public static verify(message: { [k: string]: any }): (string|null);
+    public static fromObject(object: { [k: string]: any }): MyRequest;
+    public static toObject(message: MyRequest, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public toJSON(): { [k: string]: any };
+    public static getTypeUrl(typeUrlPrefix?: string): string;
+}
+
+export interface IMyResponse {
+    status?: (number|null);
+}
+
+export class MyResponse implements IMyResponse {
+    constructor(properties?: IMyResponse);
+    public status: number;
+    public static create(properties?: IMyResponse): MyResponse;
+    public static encode(message: IMyResponse, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: IMyResponse, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): MyResponse;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): MyResponse;
+    public static verify(message: { [k: string]: any }): (string|null);
+    public static fromObject(object: { [k: string]: any }): MyResponse;
+    public static toObject(message: MyResponse, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public toJSON(): { [k: string]: any };
+    public static getTypeUrl(typeUrlPrefix?: string): string;
+}
diff --git a/tests/data/rpc-reserved.js b/tests/data/rpc-reserved.js
new file mode 100644
index 0000000..d3f7683
--- /dev/null
+++ b/tests/data/rpc-reserved.js
@@ -0,0 +1,484 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+"use strict";
+
+var $protobuf = require("../../minimal");
+
+// Common aliases
+var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+// Exported root namespace
+var $root = $protobuf.roots["test_rpc-reserved"] || ($protobuf.roots["test_rpc-reserved"] = {});
+
+$root.MyService = (function() {
+
+    /**
+     * Constructs a new MyService service.
+     * @exports MyService
+     * @classdesc Represents a MyService
+     * @extends $protobuf.rpc.Service
+     * @constructor
+     * @param {$protobuf.RPCImpl} rpcImpl RPC implementation
+     * @param {boolean} [requestDelimited=false] Whether requests are length-delimited
+     * @param {boolean} [responseDelimited=false] Whether responses are length-delimited
+     */
+    function MyService(rpcImpl, requestDelimited, responseDelimited) {
+        $protobuf.rpc.Service.call(this, rpcImpl, requestDelimited, responseDelimited);
+    }
+
+    (MyService.prototype = Object.create($protobuf.rpc.Service.prototype)).constructor = MyService;
+
+    /**
+     * Creates new MyService service using the specified rpc implementation.
+     * @function create
+     * @memberof MyService
+     * @static
+     * @param {$protobuf.RPCImpl} rpcImpl RPC implementation
+     * @param {boolean} [requestDelimited=false] Whether requests are length-delimited
+     * @param {boolean} [responseDelimited=false] Whether responses are length-delimited
+     * @returns {MyService} RPC service. Useful where requests and/or responses are streamed.
+     */
+    MyService.create = function create(rpcImpl, requestDelimited, responseDelimited) {
+        return new this(rpcImpl, requestDelimited, responseDelimited);
+    };
+
+    /**
+     * Callback as used by {@link MyService#delete_}.
+     * @memberof MyService
+     * @typedef DeleteCallback
+     * @type {function}
+     * @param {Error|null} error Error, if any
+     * @param {MyResponse} [response] MyResponse
+     */
+
+    /**
+     * Calls Delete.
+     * @function delete
+     * @memberof MyService
+     * @instance
+     * @param {IMyRequest} request MyRequest message or plain object
+     * @param {MyService.DeleteCallback} callback Node-style callback called with the error, if any, and MyResponse
+     * @returns {undefined}
+     * @variation 1
+     */
+    Object.defineProperty(MyService.prototype["delete"] = function delete_(request, callback) {
+        return this.rpcCall(delete_, $root.MyRequest, $root.MyResponse, request, callback);
+    }, "name", { value: "Delete" });
+
+    /**
+     * Calls Delete.
+     * @function delete
+     * @memberof MyService
+     * @instance
+     * @param {IMyRequest} request MyRequest message or plain object
+     * @returns {Promise<MyResponse>} Promise
+     * @variation 2
+     */
+
+    return MyService;
+})();
+
+$root.MyRequest = (function() {
+
+    /**
+     * Properties of a MyRequest.
+     * @exports IMyRequest
+     * @interface IMyRequest
+     * @property {string|null} [path] MyRequest path
+     */
+
+    /**
+     * Constructs a new MyRequest.
+     * @exports MyRequest
+     * @classdesc Represents a MyRequest.
+     * @implements IMyRequest
+     * @constructor
+     * @param {IMyRequest=} [properties] Properties to set
+     */
+    function MyRequest(properties) {
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * MyRequest path.
+     * @member {string} path
+     * @memberof MyRequest
+     * @instance
+     */
+    MyRequest.prototype.path = "";
+
+    /**
+     * Creates a new MyRequest instance using the specified properties.
+     * @function create
+     * @memberof MyRequest
+     * @static
+     * @param {IMyRequest=} [properties] Properties to set
+     * @returns {MyRequest} MyRequest instance
+     */
+    MyRequest.create = function create(properties) {
+        return new MyRequest(properties);
+    };
+
+    /**
+     * Encodes the specified MyRequest message. Does not implicitly {@link MyRequest.verify|verify} messages.
+     * @function encode
+     * @memberof MyRequest
+     * @static
+     * @param {IMyRequest} message MyRequest message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    MyRequest.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.path != null && Object.hasOwnProperty.call(message, "path"))
+            writer.uint32(/* id 1, wireType 2 =*/10).string(message.path);
+        return writer;
+    };
+
+    /**
+     * Encodes the specified MyRequest message, length delimited. Does not implicitly {@link MyRequest.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof MyRequest
+     * @static
+     * @param {IMyRequest} message MyRequest message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    MyRequest.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a MyRequest message from the specified reader or buffer.
+     * @function decode
+     * @memberof MyRequest
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {MyRequest} MyRequest
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    MyRequest.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.MyRequest();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 1:
+                message.path = reader.string();
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a MyRequest message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof MyRequest
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {MyRequest} MyRequest
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    MyRequest.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a MyRequest message.
+     * @function verify
+     * @memberof MyRequest
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    MyRequest.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.path != null && message.hasOwnProperty("path"))
+            if (!$util.isString(message.path))
+                return "path: string expected";
+        return null;
+    };
+
+    /**
+     * Creates a MyRequest message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof MyRequest
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {MyRequest} MyRequest
+     */
+    MyRequest.fromObject = function fromObject(object) {
+        if (object instanceof $root.MyRequest)
+            return object;
+        var message = new $root.MyRequest();
+        if (object.path != null)
+            message.path = String(object.path);
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a MyRequest message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof MyRequest
+     * @static
+     * @param {MyRequest} message MyRequest
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    MyRequest.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        var object = {};
+        if (options.defaults)
+            object.path = "";
+        if (message.path != null && message.hasOwnProperty("path"))
+            object.path = message.path;
+        return object;
+    };
+
+    /**
+     * Converts this MyRequest to JSON.
+     * @function toJSON
+     * @memberof MyRequest
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    MyRequest.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    /**
+     * Gets the default type url for MyRequest
+     * @function getTypeUrl
+     * @memberof MyRequest
+     * @static
+     * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+     * @returns {string} The default type url
+     */
+    MyRequest.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+        if (typeUrlPrefix === undefined) {
+            typeUrlPrefix = "type.googleapis.com";
+        }
+        return typeUrlPrefix + "/MyRequest";
+    };
+
+    return MyRequest;
+})();
+
+$root.MyResponse = (function() {
+
+    /**
+     * Properties of a MyResponse.
+     * @exports IMyResponse
+     * @interface IMyResponse
+     * @property {number|null} [status] MyResponse status
+     */
+
+    /**
+     * Constructs a new MyResponse.
+     * @exports MyResponse
+     * @classdesc Represents a MyResponse.
+     * @implements IMyResponse
+     * @constructor
+     * @param {IMyResponse=} [properties] Properties to set
+     */
+    function MyResponse(properties) {
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * MyResponse status.
+     * @member {number} status
+     * @memberof MyResponse
+     * @instance
+     */
+    MyResponse.prototype.status = 0;
+
+    /**
+     * Creates a new MyResponse instance using the specified properties.
+     * @function create
+     * @memberof MyResponse
+     * @static
+     * @param {IMyResponse=} [properties] Properties to set
+     * @returns {MyResponse} MyResponse instance
+     */
+    MyResponse.create = function create(properties) {
+        return new MyResponse(properties);
+    };
+
+    /**
+     * Encodes the specified MyResponse message. Does not implicitly {@link MyResponse.verify|verify} messages.
+     * @function encode
+     * @memberof MyResponse
+     * @static
+     * @param {IMyResponse} message MyResponse message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    MyResponse.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.status != null && Object.hasOwnProperty.call(message, "status"))
+            writer.uint32(/* id 2, wireType 0 =*/16).int32(message.status);
+        return writer;
+    };
+
+    /**
+     * Encodes the specified MyResponse message, length delimited. Does not implicitly {@link MyResponse.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof MyResponse
+     * @static
+     * @param {IMyResponse} message MyResponse message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    MyResponse.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a MyResponse message from the specified reader or buffer.
+     * @function decode
+     * @memberof MyResponse
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {MyResponse} MyResponse
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    MyResponse.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.MyResponse();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 2:
+                message.status = reader.int32();
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a MyResponse message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof MyResponse
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {MyResponse} MyResponse
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    MyResponse.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a MyResponse message.
+     * @function verify
+     * @memberof MyResponse
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    MyResponse.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.status != null && message.hasOwnProperty("status"))
+            if (!$util.isInteger(message.status))
+                return "status: integer expected";
+        return null;
+    };
+
+    /**
+     * Creates a MyResponse message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof MyResponse
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {MyResponse} MyResponse
+     */
+    MyResponse.fromObject = function fromObject(object) {
+        if (object instanceof $root.MyResponse)
+            return object;
+        var message = new $root.MyResponse();
+        if (object.status != null)
+            message.status = object.status | 0;
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a MyResponse message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof MyResponse
+     * @static
+     * @param {MyResponse} message MyResponse
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    MyResponse.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        var object = {};
+        if (options.defaults)
+            object.status = 0;
+        if (message.status != null && message.hasOwnProperty("status"))
+            object.status = message.status;
+        return object;
+    };
+
+    /**
+     * Converts this MyResponse to JSON.
+     * @function toJSON
+     * @memberof MyResponse
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    MyResponse.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    /**
+     * Gets the default type url for MyResponse
+     * @function getTypeUrl
+     * @memberof MyResponse
+     * @static
+     * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+     * @returns {string} The default type url
+     */
+    MyResponse.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+        if (typeUrlPrefix === undefined) {
+            typeUrlPrefix = "type.googleapis.com";
+        }
+        return typeUrlPrefix + "/MyResponse";
+    };
+
+    return MyResponse;
+})();
+
+module.exports = $root;
diff --git a/tests/data/rpc-reserved.proto b/tests/data/rpc-reserved.proto
new file mode 100644
index 0000000..17193f9
--- /dev/null
+++ b/tests/data/rpc-reserved.proto
@@ -0,0 +1,13 @@
+syntax = "proto3";
+
+service MyService {
+  rpc Delete (MyRequest) returns (MyResponse);
+}
+
+message MyRequest {
+  string path = 1;
+}
+
+message MyResponse {
+  int32 status = 2;
+}
diff --git a/tests/data/rpc.d.ts b/tests/data/rpc.d.ts
new file mode 100644
index 0000000..5cebb4c
--- /dev/null
+++ b/tests/data/rpc.d.ts
@@ -0,0 +1,50 @@
+import * as $protobuf from "../..";
+export class MyService extends $protobuf.rpc.Service {
+    constructor(rpcImpl: $protobuf.RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean);
+    public static create(rpcImpl: $protobuf.RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean): MyService;
+    public myMethod(request: IMyRequest, callback: MyService.MyMethodCallback): void;
+    public myMethod(request: IMyRequest): Promise<MyResponse>;
+}
+
+export namespace MyService {
+
+    type MyMethodCallback = (error: (Error|null), response?: MyResponse) => void;
+}
+
+export interface IMyRequest {
+    path?: (string|null);
+}
+
+export class MyRequest implements IMyRequest {
+    constructor(properties?: IMyRequest);
+    public path: string;
+    public static create(properties?: IMyRequest): MyRequest;
+    public static encode(message: IMyRequest, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: IMyRequest, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): MyRequest;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): MyRequest;
+    public static verify(message: { [k: string]: any }): (string|null);
+    public static fromObject(object: { [k: string]: any }): MyRequest;
+    public static toObject(message: MyRequest, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public toJSON(): { [k: string]: any };
+    public static getTypeUrl(typeUrlPrefix?: string): string;
+}
+
+export interface IMyResponse {
+    status?: (number|null);
+}
+
+export class MyResponse implements IMyResponse {
+    constructor(properties?: IMyResponse);
+    public status: number;
+    public static create(properties?: IMyResponse): MyResponse;
+    public static encode(message: IMyResponse, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: IMyResponse, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): MyResponse;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): MyResponse;
+    public static verify(message: { [k: string]: any }): (string|null);
+    public static fromObject(object: { [k: string]: any }): MyResponse;
+    public static toObject(message: MyResponse, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public toJSON(): { [k: string]: any };
+    public static getTypeUrl(typeUrlPrefix?: string): string;
+}
diff --git a/tests/data/rpc.js b/tests/data/rpc.js
new file mode 100644
index 0000000..c102c1a
--- /dev/null
+++ b/tests/data/rpc.js
@@ -0,0 +1,484 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+"use strict";
+
+var $protobuf = require("../../minimal");
+
+// Common aliases
+var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+// Exported root namespace
+var $root = $protobuf.roots.test_rpc || ($protobuf.roots.test_rpc = {});
+
+$root.MyService = (function() {
+
+    /**
+     * Constructs a new MyService service.
+     * @exports MyService
+     * @classdesc Represents a MyService
+     * @extends $protobuf.rpc.Service
+     * @constructor
+     * @param {$protobuf.RPCImpl} rpcImpl RPC implementation
+     * @param {boolean} [requestDelimited=false] Whether requests are length-delimited
+     * @param {boolean} [responseDelimited=false] Whether responses are length-delimited
+     */
+    function MyService(rpcImpl, requestDelimited, responseDelimited) {
+        $protobuf.rpc.Service.call(this, rpcImpl, requestDelimited, responseDelimited);
+    }
+
+    (MyService.prototype = Object.create($protobuf.rpc.Service.prototype)).constructor = MyService;
+
+    /**
+     * Creates new MyService service using the specified rpc implementation.
+     * @function create
+     * @memberof MyService
+     * @static
+     * @param {$protobuf.RPCImpl} rpcImpl RPC implementation
+     * @param {boolean} [requestDelimited=false] Whether requests are length-delimited
+     * @param {boolean} [responseDelimited=false] Whether responses are length-delimited
+     * @returns {MyService} RPC service. Useful where requests and/or responses are streamed.
+     */
+    MyService.create = function create(rpcImpl, requestDelimited, responseDelimited) {
+        return new this(rpcImpl, requestDelimited, responseDelimited);
+    };
+
+    /**
+     * Callback as used by {@link MyService#myMethod}.
+     * @memberof MyService
+     * @typedef MyMethodCallback
+     * @type {function}
+     * @param {Error|null} error Error, if any
+     * @param {MyResponse} [response] MyResponse
+     */
+
+    /**
+     * Calls MyMethod.
+     * @function myMethod
+     * @memberof MyService
+     * @instance
+     * @param {IMyRequest} request MyRequest message or plain object
+     * @param {MyService.MyMethodCallback} callback Node-style callback called with the error, if any, and MyResponse
+     * @returns {undefined}
+     * @variation 1
+     */
+    Object.defineProperty(MyService.prototype.myMethod = function myMethod(request, callback) {
+        return this.rpcCall(myMethod, $root.MyRequest, $root.MyResponse, request, callback);
+    }, "name", { value: "MyMethod" });
+
+    /**
+     * Calls MyMethod.
+     * @function myMethod
+     * @memberof MyService
+     * @instance
+     * @param {IMyRequest} request MyRequest message or plain object
+     * @returns {Promise<MyResponse>} Promise
+     * @variation 2
+     */
+
+    return MyService;
+})();
+
+$root.MyRequest = (function() {
+
+    /**
+     * Properties of a MyRequest.
+     * @exports IMyRequest
+     * @interface IMyRequest
+     * @property {string|null} [path] MyRequest path
+     */
+
+    /**
+     * Constructs a new MyRequest.
+     * @exports MyRequest
+     * @classdesc Represents a MyRequest.
+     * @implements IMyRequest
+     * @constructor
+     * @param {IMyRequest=} [properties] Properties to set
+     */
+    function MyRequest(properties) {
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * MyRequest path.
+     * @member {string} path
+     * @memberof MyRequest
+     * @instance
+     */
+    MyRequest.prototype.path = "";
+
+    /**
+     * Creates a new MyRequest instance using the specified properties.
+     * @function create
+     * @memberof MyRequest
+     * @static
+     * @param {IMyRequest=} [properties] Properties to set
+     * @returns {MyRequest} MyRequest instance
+     */
+    MyRequest.create = function create(properties) {
+        return new MyRequest(properties);
+    };
+
+    /**
+     * Encodes the specified MyRequest message. Does not implicitly {@link MyRequest.verify|verify} messages.
+     * @function encode
+     * @memberof MyRequest
+     * @static
+     * @param {IMyRequest} message MyRequest message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    MyRequest.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.path != null && Object.hasOwnProperty.call(message, "path"))
+            writer.uint32(/* id 1, wireType 2 =*/10).string(message.path);
+        return writer;
+    };
+
+    /**
+     * Encodes the specified MyRequest message, length delimited. Does not implicitly {@link MyRequest.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof MyRequest
+     * @static
+     * @param {IMyRequest} message MyRequest message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    MyRequest.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a MyRequest message from the specified reader or buffer.
+     * @function decode
+     * @memberof MyRequest
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {MyRequest} MyRequest
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    MyRequest.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.MyRequest();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 1:
+                message.path = reader.string();
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a MyRequest message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof MyRequest
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {MyRequest} MyRequest
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    MyRequest.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a MyRequest message.
+     * @function verify
+     * @memberof MyRequest
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    MyRequest.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.path != null && message.hasOwnProperty("path"))
+            if (!$util.isString(message.path))
+                return "path: string expected";
+        return null;
+    };
+
+    /**
+     * Creates a MyRequest message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof MyRequest
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {MyRequest} MyRequest
+     */
+    MyRequest.fromObject = function fromObject(object) {
+        if (object instanceof $root.MyRequest)
+            return object;
+        var message = new $root.MyRequest();
+        if (object.path != null)
+            message.path = String(object.path);
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a MyRequest message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof MyRequest
+     * @static
+     * @param {MyRequest} message MyRequest
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    MyRequest.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        var object = {};
+        if (options.defaults)
+            object.path = "";
+        if (message.path != null && message.hasOwnProperty("path"))
+            object.path = message.path;
+        return object;
+    };
+
+    /**
+     * Converts this MyRequest to JSON.
+     * @function toJSON
+     * @memberof MyRequest
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    MyRequest.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    /**
+     * Gets the default type url for MyRequest
+     * @function getTypeUrl
+     * @memberof MyRequest
+     * @static
+     * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+     * @returns {string} The default type url
+     */
+    MyRequest.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+        if (typeUrlPrefix === undefined) {
+            typeUrlPrefix = "type.googleapis.com";
+        }
+        return typeUrlPrefix + "/MyRequest";
+    };
+
+    return MyRequest;
+})();
+
+$root.MyResponse = (function() {
+
+    /**
+     * Properties of a MyResponse.
+     * @exports IMyResponse
+     * @interface IMyResponse
+     * @property {number|null} [status] MyResponse status
+     */
+
+    /**
+     * Constructs a new MyResponse.
+     * @exports MyResponse
+     * @classdesc Represents a MyResponse.
+     * @implements IMyResponse
+     * @constructor
+     * @param {IMyResponse=} [properties] Properties to set
+     */
+    function MyResponse(properties) {
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * MyResponse status.
+     * @member {number} status
+     * @memberof MyResponse
+     * @instance
+     */
+    MyResponse.prototype.status = 0;
+
+    /**
+     * Creates a new MyResponse instance using the specified properties.
+     * @function create
+     * @memberof MyResponse
+     * @static
+     * @param {IMyResponse=} [properties] Properties to set
+     * @returns {MyResponse} MyResponse instance
+     */
+    MyResponse.create = function create(properties) {
+        return new MyResponse(properties);
+    };
+
+    /**
+     * Encodes the specified MyResponse message. Does not implicitly {@link MyResponse.verify|verify} messages.
+     * @function encode
+     * @memberof MyResponse
+     * @static
+     * @param {IMyResponse} message MyResponse message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    MyResponse.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.status != null && Object.hasOwnProperty.call(message, "status"))
+            writer.uint32(/* id 2, wireType 0 =*/16).int32(message.status);
+        return writer;
+    };
+
+    /**
+     * Encodes the specified MyResponse message, length delimited. Does not implicitly {@link MyResponse.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof MyResponse
+     * @static
+     * @param {IMyResponse} message MyResponse message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    MyResponse.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a MyResponse message from the specified reader or buffer.
+     * @function decode
+     * @memberof MyResponse
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {MyResponse} MyResponse
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    MyResponse.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.MyResponse();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 2:
+                message.status = reader.int32();
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a MyResponse message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof MyResponse
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {MyResponse} MyResponse
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    MyResponse.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a MyResponse message.
+     * @function verify
+     * @memberof MyResponse
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    MyResponse.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.status != null && message.hasOwnProperty("status"))
+            if (!$util.isInteger(message.status))
+                return "status: integer expected";
+        return null;
+    };
+
+    /**
+     * Creates a MyResponse message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof MyResponse
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {MyResponse} MyResponse
+     */
+    MyResponse.fromObject = function fromObject(object) {
+        if (object instanceof $root.MyResponse)
+            return object;
+        var message = new $root.MyResponse();
+        if (object.status != null)
+            message.status = object.status | 0;
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a MyResponse message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof MyResponse
+     * @static
+     * @param {MyResponse} message MyResponse
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    MyResponse.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        var object = {};
+        if (options.defaults)
+            object.status = 0;
+        if (message.status != null && message.hasOwnProperty("status"))
+            object.status = message.status;
+        return object;
+    };
+
+    /**
+     * Converts this MyResponse to JSON.
+     * @function toJSON
+     * @memberof MyResponse
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    MyResponse.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    /**
+     * Gets the default type url for MyResponse
+     * @function getTypeUrl
+     * @memberof MyResponse
+     * @static
+     * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+     * @returns {string} The default type url
+     */
+    MyResponse.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+        if (typeUrlPrefix === undefined) {
+            typeUrlPrefix = "type.googleapis.com";
+        }
+        return typeUrlPrefix + "/MyResponse";
+    };
+
+    return MyResponse;
+})();
+
+module.exports = $root;
diff --git a/tests/data/rpc.proto b/tests/data/rpc.proto
new file mode 100644
index 0000000..a9841c0
--- /dev/null
+++ b/tests/data/rpc.proto
@@ -0,0 +1,13 @@
+syntax = "proto3";
+
+service MyService {
+    rpc MyMethod (MyRequest) returns (MyResponse);
+}
+
+message MyRequest {
+    string path = 1;
+}
+
+message MyResponse {
+    int32 status = 2;
+}
diff --git a/tests/data/rpc.ts b/tests/data/rpc.ts
new file mode 100644
index 0000000..ac755d1
--- /dev/null
+++ b/tests/data/rpc.ts
@@ -0,0 +1 @@
+import * as test from "./rpc.js";
diff --git a/tests/data/test.d.ts b/tests/data/test.d.ts
new file mode 100644
index 0000000..51c86c0
--- /dev/null
+++ b/tests/data/test.d.ts
@@ -0,0 +1,1502 @@
+import * as $protobuf from "../..";
+import Long from "long";
+
+export namespace jspb {
+
+    namespace test {
+
+        interface IEmpty {
+        }
+
+        class Empty implements IEmpty {
+            constructor(properties?: jspb.test.IEmpty);
+            public static create(properties?: jspb.test.IEmpty): jspb.test.Empty;
+            public static encode(message: jspb.test.IEmpty, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.IEmpty, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.Empty;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.Empty;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.Empty;
+            public static toObject(message: jspb.test.Empty, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        enum OuterEnum {
+            FOO = 1,
+            BAR = 2
+        }
+
+        interface IEnumContainer {
+            outerEnum?: (jspb.test.OuterEnum|null);
+        }
+
+        class EnumContainer implements IEnumContainer {
+            constructor(properties?: jspb.test.IEnumContainer);
+            public outerEnum: jspb.test.OuterEnum;
+            public static create(properties?: jspb.test.IEnumContainer): jspb.test.EnumContainer;
+            public static encode(message: jspb.test.IEnumContainer, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.IEnumContainer, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.EnumContainer;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.EnumContainer;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.EnumContainer;
+            public static toObject(message: jspb.test.EnumContainer, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface ISimple1 {
+            aString: string;
+            aRepeatedString?: (string[]|null);
+            aBoolean?: (boolean|null);
+        }
+
+        class Simple1 implements ISimple1 {
+            constructor(properties?: jspb.test.ISimple1);
+            public aString: string;
+            public aRepeatedString: string[];
+            public aBoolean: boolean;
+            public static create(properties?: jspb.test.ISimple1): jspb.test.Simple1;
+            public static encode(message: jspb.test.ISimple1, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.ISimple1, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.Simple1;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.Simple1;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.Simple1;
+            public static toObject(message: jspb.test.Simple1, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface ISimple2 {
+            aString: string;
+            aRepeatedString?: (string[]|null);
+        }
+
+        class Simple2 implements ISimple2 {
+            constructor(properties?: jspb.test.ISimple2);
+            public aString: string;
+            public aRepeatedString: string[];
+            public static create(properties?: jspb.test.ISimple2): jspb.test.Simple2;
+            public static encode(message: jspb.test.ISimple2, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.ISimple2, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.Simple2;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.Simple2;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.Simple2;
+            public static toObject(message: jspb.test.Simple2, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface ISpecialCases {
+            normal: string;
+            "default": string;
+            "function": string;
+            "var": string;
+        }
+
+        class SpecialCases implements ISpecialCases {
+            constructor(properties?: jspb.test.ISpecialCases);
+            public normal: string;
+            public default: string;
+            public function: string;
+            public var: string;
+            public static create(properties?: jspb.test.ISpecialCases): jspb.test.SpecialCases;
+            public static encode(message: jspb.test.ISpecialCases, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.ISpecialCases, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.SpecialCases;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.SpecialCases;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.SpecialCases;
+            public static toObject(message: jspb.test.SpecialCases, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IOptionalFields {
+            aString?: (string|null);
+            aBool: boolean;
+            aNestedMessage?: (jspb.test.OptionalFields.INested|null);
+            aRepeatedMessage?: (jspb.test.OptionalFields.INested[]|null);
+            aRepeatedString?: (string[]|null);
+        }
+
+        class OptionalFields implements IOptionalFields {
+            constructor(properties?: jspb.test.IOptionalFields);
+            public aString: string;
+            public aBool: boolean;
+            public aNestedMessage?: (jspb.test.OptionalFields.INested|null);
+            public aRepeatedMessage: jspb.test.OptionalFields.INested[];
+            public aRepeatedString: string[];
+            public static create(properties?: jspb.test.IOptionalFields): jspb.test.OptionalFields;
+            public static encode(message: jspb.test.IOptionalFields, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.IOptionalFields, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.OptionalFields;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.OptionalFields;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.OptionalFields;
+            public static toObject(message: jspb.test.OptionalFields, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace OptionalFields {
+
+            interface INested {
+                anInt?: (number|null);
+            }
+
+            class Nested implements INested {
+                constructor(properties?: jspb.test.OptionalFields.INested);
+                public anInt: number;
+                public static create(properties?: jspb.test.OptionalFields.INested): jspb.test.OptionalFields.Nested;
+                public static encode(message: jspb.test.OptionalFields.INested, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static encodeDelimited(message: jspb.test.OptionalFields.INested, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.OptionalFields.Nested;
+                public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.OptionalFields.Nested;
+                public static verify(message: { [k: string]: any }): (string|null);
+                public static fromObject(object: { [k: string]: any }): jspb.test.OptionalFields.Nested;
+                public static toObject(message: jspb.test.OptionalFields.Nested, options?: $protobuf.IConversionOptions): { [k: string]: any };
+                public toJSON(): { [k: string]: any };
+                public static getTypeUrl(typeUrlPrefix?: string): string;
+            }
+        }
+
+        interface IHasExtensions {
+            str1?: (string|null);
+            str2?: (string|null);
+            str3?: (string|null);
+            ".jspb.test.IsExtension.extField"?: (jspb.test.IIsExtension|null);
+            ".jspb.test.IndirectExtension.simple"?: (jspb.test.ISimple1|null);
+            ".jspb.test.IndirectExtension.str"?: (string|null);
+            ".jspb.test.IndirectExtension.repeatedStr"?: (string[]|null);
+            ".jspb.test.IndirectExtension.repeatedSimple"?: (jspb.test.ISimple1[]|null);
+            ".jspb.test.simple1"?: (jspb.test.ISimple1|null);
+        }
+
+        class HasExtensions implements IHasExtensions {
+            constructor(properties?: jspb.test.IHasExtensions);
+            public str1: string;
+            public str2: string;
+            public str3: string;
+            public static create(properties?: jspb.test.IHasExtensions): jspb.test.HasExtensions;
+            public static encode(message: jspb.test.IHasExtensions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.IHasExtensions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.HasExtensions;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.HasExtensions;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.HasExtensions;
+            public static toObject(message: jspb.test.HasExtensions, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IComplex {
+            aString: string;
+            anOutOfOrderBool: boolean;
+            aNestedMessage?: (jspb.test.Complex.INested|null);
+            aRepeatedMessage?: (jspb.test.Complex.INested[]|null);
+            aRepeatedString?: (string[]|null);
+        }
+
+        class Complex implements IComplex {
+            constructor(properties?: jspb.test.IComplex);
+            public aString: string;
+            public anOutOfOrderBool: boolean;
+            public aNestedMessage?: (jspb.test.Complex.INested|null);
+            public aRepeatedMessage: jspb.test.Complex.INested[];
+            public aRepeatedString: string[];
+            public static create(properties?: jspb.test.IComplex): jspb.test.Complex;
+            public static encode(message: jspb.test.IComplex, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.IComplex, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.Complex;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.Complex;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.Complex;
+            public static toObject(message: jspb.test.Complex, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace Complex {
+
+            interface INested {
+                anInt: number;
+            }
+
+            class Nested implements INested {
+                constructor(properties?: jspb.test.Complex.INested);
+                public anInt: number;
+                public static create(properties?: jspb.test.Complex.INested): jspb.test.Complex.Nested;
+                public static encode(message: jspb.test.Complex.INested, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static encodeDelimited(message: jspb.test.Complex.INested, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.Complex.Nested;
+                public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.Complex.Nested;
+                public static verify(message: { [k: string]: any }): (string|null);
+                public static fromObject(object: { [k: string]: any }): jspb.test.Complex.Nested;
+                public static toObject(message: jspb.test.Complex.Nested, options?: $protobuf.IConversionOptions): { [k: string]: any };
+                public toJSON(): { [k: string]: any };
+                public static getTypeUrl(typeUrlPrefix?: string): string;
+            }
+        }
+
+        interface IOuterMessage {
+        }
+
+        class OuterMessage implements IOuterMessage {
+            constructor(properties?: jspb.test.IOuterMessage);
+            public static create(properties?: jspb.test.IOuterMessage): jspb.test.OuterMessage;
+            public static encode(message: jspb.test.IOuterMessage, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.IOuterMessage, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.OuterMessage;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.OuterMessage;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.OuterMessage;
+            public static toObject(message: jspb.test.OuterMessage, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace OuterMessage {
+
+            interface IComplex {
+                innerComplexField?: (number|null);
+            }
+
+            class Complex implements IComplex {
+                constructor(properties?: jspb.test.OuterMessage.IComplex);
+                public innerComplexField: number;
+                public static create(properties?: jspb.test.OuterMessage.IComplex): jspb.test.OuterMessage.Complex;
+                public static encode(message: jspb.test.OuterMessage.IComplex, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static encodeDelimited(message: jspb.test.OuterMessage.IComplex, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.OuterMessage.Complex;
+                public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.OuterMessage.Complex;
+                public static verify(message: { [k: string]: any }): (string|null);
+                public static fromObject(object: { [k: string]: any }): jspb.test.OuterMessage.Complex;
+                public static toObject(message: jspb.test.OuterMessage.Complex, options?: $protobuf.IConversionOptions): { [k: string]: any };
+                public toJSON(): { [k: string]: any };
+                public static getTypeUrl(typeUrlPrefix?: string): string;
+            }
+        }
+
+        interface IIsExtension {
+            ext1?: (string|null);
+        }
+
+        class IsExtension implements IIsExtension {
+            constructor(properties?: jspb.test.IIsExtension);
+            public ext1: string;
+            public static create(properties?: jspb.test.IIsExtension): jspb.test.IsExtension;
+            public static encode(message: jspb.test.IIsExtension, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.IIsExtension, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.IsExtension;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.IsExtension;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.IsExtension;
+            public static toObject(message: jspb.test.IsExtension, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IIndirectExtension {
+        }
+
+        class IndirectExtension implements IIndirectExtension {
+            constructor(properties?: jspb.test.IIndirectExtension);
+            public static create(properties?: jspb.test.IIndirectExtension): jspb.test.IndirectExtension;
+            public static encode(message: jspb.test.IIndirectExtension, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.IIndirectExtension, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.IndirectExtension;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.IndirectExtension;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.IndirectExtension;
+            public static toObject(message: jspb.test.IndirectExtension, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IDefaultValues {
+            stringField?: (string|null);
+            boolField?: (boolean|null);
+            intField?: (number|Long|null);
+            enumField?: (jspb.test.DefaultValues.Enum|null);
+            emptyField?: (string|null);
+            bytesField?: (Uint8Array|null);
+        }
+
+        class DefaultValues implements IDefaultValues {
+            constructor(properties?: jspb.test.IDefaultValues);
+            public stringField: string;
+            public boolField: boolean;
+            public intField: (number|Long);
+            public enumField: jspb.test.DefaultValues.Enum;
+            public emptyField: string;
+            public bytesField: Uint8Array;
+            public static create(properties?: jspb.test.IDefaultValues): jspb.test.DefaultValues;
+            public static encode(message: jspb.test.IDefaultValues, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.IDefaultValues, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.DefaultValues;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.DefaultValues;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.DefaultValues;
+            public static toObject(message: jspb.test.DefaultValues, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace DefaultValues {
+
+            enum Enum {
+                E1 = 13,
+                E2 = 77
+            }
+        }
+
+        interface IFloatingPointFields {
+            optionalFloatField?: (number|null);
+            requiredFloatField: number;
+            repeatedFloatField?: (number[]|null);
+            defaultFloatField?: (number|null);
+            optionalDoubleField?: (number|null);
+            requiredDoubleField: number;
+            repeatedDoubleField?: (number[]|null);
+            defaultDoubleField?: (number|null);
+        }
+
+        class FloatingPointFields implements IFloatingPointFields {
+            constructor(properties?: jspb.test.IFloatingPointFields);
+            public optionalFloatField: number;
+            public requiredFloatField: number;
+            public repeatedFloatField: number[];
+            public defaultFloatField: number;
+            public optionalDoubleField: number;
+            public requiredDoubleField: number;
+            public repeatedDoubleField: number[];
+            public defaultDoubleField: number;
+            public static create(properties?: jspb.test.IFloatingPointFields): jspb.test.FloatingPointFields;
+            public static encode(message: jspb.test.IFloatingPointFields, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.IFloatingPointFields, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.FloatingPointFields;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.FloatingPointFields;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.FloatingPointFields;
+            public static toObject(message: jspb.test.FloatingPointFields, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface ITestClone {
+            str?: (string|null);
+            simple1?: (jspb.test.ISimple1|null);
+            simple2?: (jspb.test.ISimple1[]|null);
+            bytesField?: (Uint8Array|null);
+            unused?: (string|null);
+            ".jspb.test.CloneExtension.extField"?: (jspb.test.ICloneExtension|null);
+        }
+
+        class TestClone implements ITestClone {
+            constructor(properties?: jspb.test.ITestClone);
+            public str: string;
+            public simple1?: (jspb.test.ISimple1|null);
+            public simple2: jspb.test.ISimple1[];
+            public bytesField: Uint8Array;
+            public unused: string;
+            public static create(properties?: jspb.test.ITestClone): jspb.test.TestClone;
+            public static encode(message: jspb.test.ITestClone, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.ITestClone, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.TestClone;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.TestClone;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.TestClone;
+            public static toObject(message: jspb.test.TestClone, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface ICloneExtension {
+            ext?: (string|null);
+        }
+
+        class CloneExtension implements ICloneExtension {
+            constructor(properties?: jspb.test.ICloneExtension);
+            public ext: string;
+            public static create(properties?: jspb.test.ICloneExtension): jspb.test.CloneExtension;
+            public static encode(message: jspb.test.ICloneExtension, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.ICloneExtension, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.CloneExtension;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.CloneExtension;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.CloneExtension;
+            public static toObject(message: jspb.test.CloneExtension, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface ITestGroup {
+            repeatedGroup?: (jspb.test.TestGroup.IRepeatedGroup[]|null);
+            requiredGroup: jspb.test.TestGroup.IRequiredGroup;
+            optionalGroup?: (jspb.test.TestGroup.IOptionalGroup|null);
+            id?: (string|null);
+            requiredSimple: jspb.test.ISimple2;
+            optionalSimple?: (jspb.test.ISimple2|null);
+        }
+
+        class TestGroup implements ITestGroup {
+            constructor(properties?: jspb.test.ITestGroup);
+            public repeatedGroup: jspb.test.TestGroup.IRepeatedGroup[];
+            public requiredGroup: jspb.test.TestGroup.IRequiredGroup;
+            public optionalGroup?: (jspb.test.TestGroup.IOptionalGroup|null);
+            public id: string;
+            public requiredSimple: jspb.test.ISimple2;
+            public optionalSimple?: (jspb.test.ISimple2|null);
+            public static create(properties?: jspb.test.ITestGroup): jspb.test.TestGroup;
+            public static encode(message: jspb.test.ITestGroup, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.ITestGroup, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.TestGroup;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.TestGroup;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.TestGroup;
+            public static toObject(message: jspb.test.TestGroup, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace TestGroup {
+
+            interface IRepeatedGroup {
+                id: string;
+                someBool?: (boolean[]|null);
+            }
+
+            class RepeatedGroup implements IRepeatedGroup {
+                constructor(properties?: jspb.test.TestGroup.IRepeatedGroup);
+                public id: string;
+                public someBool: boolean[];
+                public static create(properties?: jspb.test.TestGroup.IRepeatedGroup): jspb.test.TestGroup.RepeatedGroup;
+                public static encode(message: jspb.test.TestGroup.IRepeatedGroup, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static encodeDelimited(message: jspb.test.TestGroup.IRepeatedGroup, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.TestGroup.RepeatedGroup;
+                public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.TestGroup.RepeatedGroup;
+                public static verify(message: { [k: string]: any }): (string|null);
+                public static fromObject(object: { [k: string]: any }): jspb.test.TestGroup.RepeatedGroup;
+                public static toObject(message: jspb.test.TestGroup.RepeatedGroup, options?: $protobuf.IConversionOptions): { [k: string]: any };
+                public toJSON(): { [k: string]: any };
+                public static getTypeUrl(typeUrlPrefix?: string): string;
+            }
+
+            interface IRequiredGroup {
+                id: string;
+            }
+
+            class RequiredGroup implements IRequiredGroup {
+                constructor(properties?: jspb.test.TestGroup.IRequiredGroup);
+                public id: string;
+                public static create(properties?: jspb.test.TestGroup.IRequiredGroup): jspb.test.TestGroup.RequiredGroup;
+                public static encode(message: jspb.test.TestGroup.IRequiredGroup, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static encodeDelimited(message: jspb.test.TestGroup.IRequiredGroup, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.TestGroup.RequiredGroup;
+                public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.TestGroup.RequiredGroup;
+                public static verify(message: { [k: string]: any }): (string|null);
+                public static fromObject(object: { [k: string]: any }): jspb.test.TestGroup.RequiredGroup;
+                public static toObject(message: jspb.test.TestGroup.RequiredGroup, options?: $protobuf.IConversionOptions): { [k: string]: any };
+                public toJSON(): { [k: string]: any };
+                public static getTypeUrl(typeUrlPrefix?: string): string;
+            }
+
+            interface IOptionalGroup {
+                id: string;
+            }
+
+            class OptionalGroup implements IOptionalGroup {
+                constructor(properties?: jspb.test.TestGroup.IOptionalGroup);
+                public id: string;
+                public static create(properties?: jspb.test.TestGroup.IOptionalGroup): jspb.test.TestGroup.OptionalGroup;
+                public static encode(message: jspb.test.TestGroup.IOptionalGroup, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static encodeDelimited(message: jspb.test.TestGroup.IOptionalGroup, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.TestGroup.OptionalGroup;
+                public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.TestGroup.OptionalGroup;
+                public static verify(message: { [k: string]: any }): (string|null);
+                public static fromObject(object: { [k: string]: any }): jspb.test.TestGroup.OptionalGroup;
+                public static toObject(message: jspb.test.TestGroup.OptionalGroup, options?: $protobuf.IConversionOptions): { [k: string]: any };
+                public toJSON(): { [k: string]: any };
+                public static getTypeUrl(typeUrlPrefix?: string): string;
+            }
+        }
+
+        interface ITestGroup1 {
+            group?: (jspb.test.TestGroup.IRepeatedGroup|null);
+        }
+
+        class TestGroup1 implements ITestGroup1 {
+            constructor(properties?: jspb.test.ITestGroup1);
+            public group?: (jspb.test.TestGroup.IRepeatedGroup|null);
+            public static create(properties?: jspb.test.ITestGroup1): jspb.test.TestGroup1;
+            public static encode(message: jspb.test.ITestGroup1, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.ITestGroup1, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.TestGroup1;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.TestGroup1;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.TestGroup1;
+            public static toObject(message: jspb.test.TestGroup1, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface ITestReservedNames {
+            extension?: (number|null);
+            ".jspb.test.TestReservedNamesExtension.foo"?: (number|null);
+        }
+
+        class TestReservedNames implements ITestReservedNames {
+            constructor(properties?: jspb.test.ITestReservedNames);
+            public extension: number;
+            public static create(properties?: jspb.test.ITestReservedNames): jspb.test.TestReservedNames;
+            public static encode(message: jspb.test.ITestReservedNames, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.ITestReservedNames, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.TestReservedNames;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.TestReservedNames;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.TestReservedNames;
+            public static toObject(message: jspb.test.TestReservedNames, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface ITestReservedNamesExtension {
+        }
+
+        class TestReservedNamesExtension implements ITestReservedNamesExtension {
+            constructor(properties?: jspb.test.ITestReservedNamesExtension);
+            public static create(properties?: jspb.test.ITestReservedNamesExtension): jspb.test.TestReservedNamesExtension;
+            public static encode(message: jspb.test.ITestReservedNamesExtension, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.ITestReservedNamesExtension, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.TestReservedNamesExtension;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.TestReservedNamesExtension;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.TestReservedNamesExtension;
+            public static toObject(message: jspb.test.TestReservedNamesExtension, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface ITestMessageWithOneof {
+            pone?: (string|null);
+            pthree?: (string|null);
+            rone?: (jspb.test.ITestMessageWithOneof|null);
+            rtwo?: (string|null);
+            normalField?: (boolean|null);
+            repeatedField?: (string[]|null);
+            aone?: (number|null);
+            atwo?: (number|null);
+            bone?: (number|null);
+            btwo?: (number|null);
+        }
+
+        class TestMessageWithOneof implements ITestMessageWithOneof {
+            constructor(properties?: jspb.test.ITestMessageWithOneof);
+            public pone?: (string|null);
+            public pthree?: (string|null);
+            public rone?: (jspb.test.ITestMessageWithOneof|null);
+            public rtwo?: (string|null);
+            public normalField: boolean;
+            public repeatedField: string[];
+            public aone?: (number|null);
+            public atwo?: (number|null);
+            public bone?: (number|null);
+            public btwo?: (number|null);
+            public partialOneof?: ("pone"|"pthree");
+            public recursiveOneof?: ("rone"|"rtwo");
+            public defaultOneofA?: ("aone"|"atwo");
+            public defaultOneofB?: ("bone"|"btwo");
+            public static create(properties?: jspb.test.ITestMessageWithOneof): jspb.test.TestMessageWithOneof;
+            public static encode(message: jspb.test.ITestMessageWithOneof, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.ITestMessageWithOneof, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.TestMessageWithOneof;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.TestMessageWithOneof;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.TestMessageWithOneof;
+            public static toObject(message: jspb.test.TestMessageWithOneof, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface ITestEndsWithBytes {
+            value?: (number|null);
+            data?: (Uint8Array|null);
+        }
+
+        class TestEndsWithBytes implements ITestEndsWithBytes {
+            constructor(properties?: jspb.test.ITestEndsWithBytes);
+            public value: number;
+            public data: Uint8Array;
+            public static create(properties?: jspb.test.ITestEndsWithBytes): jspb.test.TestEndsWithBytes;
+            public static encode(message: jspb.test.ITestEndsWithBytes, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.ITestEndsWithBytes, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.TestEndsWithBytes;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.TestEndsWithBytes;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.TestEndsWithBytes;
+            public static toObject(message: jspb.test.TestEndsWithBytes, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface ITestMapFieldsNoBinary {
+            mapStringString?: ({ [k: string]: string }|null);
+            mapStringInt32?: ({ [k: string]: number }|null);
+            mapStringInt64?: ({ [k: string]: (number|Long) }|null);
+            mapStringBool?: ({ [k: string]: boolean }|null);
+            mapStringDouble?: ({ [k: string]: number }|null);
+            mapStringEnum?: ({ [k: string]: jspb.test.MapValueEnumNoBinary }|null);
+            mapStringMsg?: ({ [k: string]: jspb.test.IMapValueMessageNoBinary }|null);
+            mapInt32String?: ({ [k: string]: string }|null);
+            mapInt64String?: ({ [k: string]: string }|null);
+            mapBoolString?: ({ [k: string]: string }|null);
+            testMapFields?: (jspb.test.ITestMapFieldsNoBinary|null);
+            mapStringTestmapfields?: ({ [k: string]: jspb.test.ITestMapFieldsNoBinary }|null);
+        }
+
+        class TestMapFieldsNoBinary implements ITestMapFieldsNoBinary {
+            constructor(properties?: jspb.test.ITestMapFieldsNoBinary);
+            public mapStringString: { [k: string]: string };
+            public mapStringInt32: { [k: string]: number };
+            public mapStringInt64: { [k: string]: (number|Long) };
+            public mapStringBool: { [k: string]: boolean };
+            public mapStringDouble: { [k: string]: number };
+            public mapStringEnum: { [k: string]: jspb.test.MapValueEnumNoBinary };
+            public mapStringMsg: { [k: string]: jspb.test.IMapValueMessageNoBinary };
+            public mapInt32String: { [k: string]: string };
+            public mapInt64String: { [k: string]: string };
+            public mapBoolString: { [k: string]: string };
+            public testMapFields?: (jspb.test.ITestMapFieldsNoBinary|null);
+            public mapStringTestmapfields: { [k: string]: jspb.test.ITestMapFieldsNoBinary };
+            public static create(properties?: jspb.test.ITestMapFieldsNoBinary): jspb.test.TestMapFieldsNoBinary;
+            public static encode(message: jspb.test.ITestMapFieldsNoBinary, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.ITestMapFieldsNoBinary, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.TestMapFieldsNoBinary;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.TestMapFieldsNoBinary;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.TestMapFieldsNoBinary;
+            public static toObject(message: jspb.test.TestMapFieldsNoBinary, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        enum MapValueEnumNoBinary {
+            MAP_VALUE_FOO_NOBINARY = 0,
+            MAP_VALUE_BAR_NOBINARY = 1,
+            MAP_VALUE_BAZ_NOBINARY = 2
+        }
+
+        interface IMapValueMessageNoBinary {
+            foo?: (number|null);
+        }
+
+        class MapValueMessageNoBinary implements IMapValueMessageNoBinary {
+            constructor(properties?: jspb.test.IMapValueMessageNoBinary);
+            public foo: number;
+            public static create(properties?: jspb.test.IMapValueMessageNoBinary): jspb.test.MapValueMessageNoBinary;
+            public static encode(message: jspb.test.IMapValueMessageNoBinary, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.IMapValueMessageNoBinary, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.MapValueMessageNoBinary;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.MapValueMessageNoBinary;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.MapValueMessageNoBinary;
+            public static toObject(message: jspb.test.MapValueMessageNoBinary, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IDeeply {
+        }
+
+        class Deeply implements IDeeply {
+            constructor(properties?: jspb.test.IDeeply);
+            public static create(properties?: jspb.test.IDeeply): jspb.test.Deeply;
+            public static encode(message: jspb.test.IDeeply, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: jspb.test.IDeeply, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.Deeply;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.Deeply;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): jspb.test.Deeply;
+            public static toObject(message: jspb.test.Deeply, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace Deeply {
+
+            interface INested {
+            }
+
+            class Nested implements INested {
+                constructor(properties?: jspb.test.Deeply.INested);
+                public static create(properties?: jspb.test.Deeply.INested): jspb.test.Deeply.Nested;
+                public static encode(message: jspb.test.Deeply.INested, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static encodeDelimited(message: jspb.test.Deeply.INested, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.Deeply.Nested;
+                public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.Deeply.Nested;
+                public static verify(message: { [k: string]: any }): (string|null);
+                public static fromObject(object: { [k: string]: any }): jspb.test.Deeply.Nested;
+                public static toObject(message: jspb.test.Deeply.Nested, options?: $protobuf.IConversionOptions): { [k: string]: any };
+                public toJSON(): { [k: string]: any };
+                public static getTypeUrl(typeUrlPrefix?: string): string;
+            }
+
+            namespace Nested {
+
+                interface IMessage {
+                    count?: (number|null);
+                }
+
+                class Message implements IMessage {
+                    constructor(properties?: jspb.test.Deeply.Nested.IMessage);
+                    public count: number;
+                    public static create(properties?: jspb.test.Deeply.Nested.IMessage): jspb.test.Deeply.Nested.Message;
+                    public static encode(message: jspb.test.Deeply.Nested.IMessage, writer?: $protobuf.Writer): $protobuf.Writer;
+                    public static encodeDelimited(message: jspb.test.Deeply.Nested.IMessage, writer?: $protobuf.Writer): $protobuf.Writer;
+                    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): jspb.test.Deeply.Nested.Message;
+                    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): jspb.test.Deeply.Nested.Message;
+                    public static verify(message: { [k: string]: any }): (string|null);
+                    public static fromObject(object: { [k: string]: any }): jspb.test.Deeply.Nested.Message;
+                    public static toObject(message: jspb.test.Deeply.Nested.Message, options?: $protobuf.IConversionOptions): { [k: string]: any };
+                    public toJSON(): { [k: string]: any };
+                    public static getTypeUrl(typeUrlPrefix?: string): string;
+                }
+            }
+        }
+    }
+}
+
+export namespace google {
+
+    namespace protobuf {
+
+        interface IFileDescriptorSet {
+            file?: (google.protobuf.IFileDescriptorProto[]|null);
+        }
+
+        class FileDescriptorSet implements IFileDescriptorSet {
+            constructor(properties?: google.protobuf.IFileDescriptorSet);
+            public file: google.protobuf.IFileDescriptorProto[];
+            public static create(properties?: google.protobuf.IFileDescriptorSet): google.protobuf.FileDescriptorSet;
+            public static encode(message: google.protobuf.IFileDescriptorSet, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IFileDescriptorSet, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.FileDescriptorSet;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.FileDescriptorSet;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.FileDescriptorSet;
+            public static toObject(message: google.protobuf.FileDescriptorSet, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IFileDescriptorProto {
+            name?: (string|null);
+            "package"?: (string|null);
+            dependency?: (string[]|null);
+            publicDependency?: (number[]|null);
+            weakDependency?: (number[]|null);
+            messageType?: (google.protobuf.IDescriptorProto[]|null);
+            enumType?: (google.protobuf.IEnumDescriptorProto[]|null);
+            service?: (google.protobuf.IServiceDescriptorProto[]|null);
+            extension?: (google.protobuf.IFieldDescriptorProto[]|null);
+            options?: (google.protobuf.IFileOptions|null);
+            sourceCodeInfo?: (google.protobuf.ISourceCodeInfo|null);
+            syntax?: (string|null);
+        }
+
+        class FileDescriptorProto implements IFileDescriptorProto {
+            constructor(properties?: google.protobuf.IFileDescriptorProto);
+            public name: string;
+            public package: string;
+            public dependency: string[];
+            public publicDependency: number[];
+            public weakDependency: number[];
+            public messageType: google.protobuf.IDescriptorProto[];
+            public enumType: google.protobuf.IEnumDescriptorProto[];
+            public service: google.protobuf.IServiceDescriptorProto[];
+            public extension: google.protobuf.IFieldDescriptorProto[];
+            public options?: (google.protobuf.IFileOptions|null);
+            public sourceCodeInfo?: (google.protobuf.ISourceCodeInfo|null);
+            public syntax: string;
+            public static create(properties?: google.protobuf.IFileDescriptorProto): google.protobuf.FileDescriptorProto;
+            public static encode(message: google.protobuf.IFileDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IFileDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.FileDescriptorProto;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.FileDescriptorProto;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.FileDescriptorProto;
+            public static toObject(message: google.protobuf.FileDescriptorProto, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IDescriptorProto {
+            name?: (string|null);
+            field?: (google.protobuf.IFieldDescriptorProto[]|null);
+            extension?: (google.protobuf.IFieldDescriptorProto[]|null);
+            nestedType?: (google.protobuf.IDescriptorProto[]|null);
+            enumType?: (google.protobuf.IEnumDescriptorProto[]|null);
+            extensionRange?: (google.protobuf.DescriptorProto.IExtensionRange[]|null);
+            oneofDecl?: (google.protobuf.IOneofDescriptorProto[]|null);
+            options?: (google.protobuf.IMessageOptions|null);
+            reservedRange?: (google.protobuf.DescriptorProto.IReservedRange[]|null);
+            reservedName?: (string[]|null);
+        }
+
+        class DescriptorProto implements IDescriptorProto {
+            constructor(properties?: google.protobuf.IDescriptorProto);
+            public name: string;
+            public field: google.protobuf.IFieldDescriptorProto[];
+            public extension: google.protobuf.IFieldDescriptorProto[];
+            public nestedType: google.protobuf.IDescriptorProto[];
+            public enumType: google.protobuf.IEnumDescriptorProto[];
+            public extensionRange: google.protobuf.DescriptorProto.IExtensionRange[];
+            public oneofDecl: google.protobuf.IOneofDescriptorProto[];
+            public options?: (google.protobuf.IMessageOptions|null);
+            public reservedRange: google.protobuf.DescriptorProto.IReservedRange[];
+            public reservedName: string[];
+            public static create(properties?: google.protobuf.IDescriptorProto): google.protobuf.DescriptorProto;
+            public static encode(message: google.protobuf.IDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.DescriptorProto;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.DescriptorProto;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.DescriptorProto;
+            public static toObject(message: google.protobuf.DescriptorProto, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace DescriptorProto {
+
+            interface IExtensionRange {
+                start?: (number|null);
+                end?: (number|null);
+            }
+
+            class ExtensionRange implements IExtensionRange {
+                constructor(properties?: google.protobuf.DescriptorProto.IExtensionRange);
+                public start: number;
+                public end: number;
+                public static create(properties?: google.protobuf.DescriptorProto.IExtensionRange): google.protobuf.DescriptorProto.ExtensionRange;
+                public static encode(message: google.protobuf.DescriptorProto.IExtensionRange, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static encodeDelimited(message: google.protobuf.DescriptorProto.IExtensionRange, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.DescriptorProto.ExtensionRange;
+                public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.DescriptorProto.ExtensionRange;
+                public static verify(message: { [k: string]: any }): (string|null);
+                public static fromObject(object: { [k: string]: any }): google.protobuf.DescriptorProto.ExtensionRange;
+                public static toObject(message: google.protobuf.DescriptorProto.ExtensionRange, options?: $protobuf.IConversionOptions): { [k: string]: any };
+                public toJSON(): { [k: string]: any };
+                public static getTypeUrl(typeUrlPrefix?: string): string;
+            }
+
+            interface IReservedRange {
+                start?: (number|null);
+                end?: (number|null);
+            }
+
+            class ReservedRange implements IReservedRange {
+                constructor(properties?: google.protobuf.DescriptorProto.IReservedRange);
+                public start: number;
+                public end: number;
+                public static create(properties?: google.protobuf.DescriptorProto.IReservedRange): google.protobuf.DescriptorProto.ReservedRange;
+                public static encode(message: google.protobuf.DescriptorProto.IReservedRange, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static encodeDelimited(message: google.protobuf.DescriptorProto.IReservedRange, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.DescriptorProto.ReservedRange;
+                public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.DescriptorProto.ReservedRange;
+                public static verify(message: { [k: string]: any }): (string|null);
+                public static fromObject(object: { [k: string]: any }): google.protobuf.DescriptorProto.ReservedRange;
+                public static toObject(message: google.protobuf.DescriptorProto.ReservedRange, options?: $protobuf.IConversionOptions): { [k: string]: any };
+                public toJSON(): { [k: string]: any };
+                public static getTypeUrl(typeUrlPrefix?: string): string;
+            }
+        }
+
+        interface IFieldDescriptorProto {
+            name?: (string|null);
+            number?: (number|null);
+            label?: (google.protobuf.FieldDescriptorProto.Label|null);
+            type?: (google.protobuf.FieldDescriptorProto.Type|null);
+            typeName?: (string|null);
+            extendee?: (string|null);
+            defaultValue?: (string|null);
+            oneofIndex?: (number|null);
+            jsonName?: (string|null);
+            options?: (google.protobuf.IFieldOptions|null);
+        }
+
+        class FieldDescriptorProto implements IFieldDescriptorProto {
+            constructor(properties?: google.protobuf.IFieldDescriptorProto);
+            public name: string;
+            public number: number;
+            public label: google.protobuf.FieldDescriptorProto.Label;
+            public type: google.protobuf.FieldDescriptorProto.Type;
+            public typeName: string;
+            public extendee: string;
+            public defaultValue: string;
+            public oneofIndex: number;
+            public jsonName: string;
+            public options?: (google.protobuf.IFieldOptions|null);
+            public static create(properties?: google.protobuf.IFieldDescriptorProto): google.protobuf.FieldDescriptorProto;
+            public static encode(message: google.protobuf.IFieldDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IFieldDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.FieldDescriptorProto;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.FieldDescriptorProto;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.FieldDescriptorProto;
+            public static toObject(message: google.protobuf.FieldDescriptorProto, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace FieldDescriptorProto {
+
+            enum Type {
+                TYPE_DOUBLE = 1,
+                TYPE_FLOAT = 2,
+                TYPE_INT64 = 3,
+                TYPE_UINT64 = 4,
+                TYPE_INT32 = 5,
+                TYPE_FIXED64 = 6,
+                TYPE_FIXED32 = 7,
+                TYPE_BOOL = 8,
+                TYPE_STRING = 9,
+                TYPE_GROUP = 10,
+                TYPE_MESSAGE = 11,
+                TYPE_BYTES = 12,
+                TYPE_UINT32 = 13,
+                TYPE_ENUM = 14,
+                TYPE_SFIXED32 = 15,
+                TYPE_SFIXED64 = 16,
+                TYPE_SINT32 = 17,
+                TYPE_SINT64 = 18
+            }
+
+            enum Label {
+                LABEL_OPTIONAL = 1,
+                LABEL_REQUIRED = 2,
+                LABEL_REPEATED = 3
+            }
+        }
+
+        interface IOneofDescriptorProto {
+            name?: (string|null);
+            options?: (google.protobuf.IOneofOptions|null);
+        }
+
+        class OneofDescriptorProto implements IOneofDescriptorProto {
+            constructor(properties?: google.protobuf.IOneofDescriptorProto);
+            public name: string;
+            public options?: (google.protobuf.IOneofOptions|null);
+            public static create(properties?: google.protobuf.IOneofDescriptorProto): google.protobuf.OneofDescriptorProto;
+            public static encode(message: google.protobuf.IOneofDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IOneofDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.OneofDescriptorProto;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.OneofDescriptorProto;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.OneofDescriptorProto;
+            public static toObject(message: google.protobuf.OneofDescriptorProto, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IEnumDescriptorProto {
+            name?: (string|null);
+            value?: (google.protobuf.IEnumValueDescriptorProto[]|null);
+            options?: (google.protobuf.IEnumOptions|null);
+        }
+
+        class EnumDescriptorProto implements IEnumDescriptorProto {
+            constructor(properties?: google.protobuf.IEnumDescriptorProto);
+            public name: string;
+            public value: google.protobuf.IEnumValueDescriptorProto[];
+            public options?: (google.protobuf.IEnumOptions|null);
+            public static create(properties?: google.protobuf.IEnumDescriptorProto): google.protobuf.EnumDescriptorProto;
+            public static encode(message: google.protobuf.IEnumDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IEnumDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.EnumDescriptorProto;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.EnumDescriptorProto;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.EnumDescriptorProto;
+            public static toObject(message: google.protobuf.EnumDescriptorProto, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IEnumValueDescriptorProto {
+            name?: (string|null);
+            number?: (number|null);
+            options?: (google.protobuf.IEnumValueOptions|null);
+        }
+
+        class EnumValueDescriptorProto implements IEnumValueDescriptorProto {
+            constructor(properties?: google.protobuf.IEnumValueDescriptorProto);
+            public name: string;
+            public number: number;
+            public options?: (google.protobuf.IEnumValueOptions|null);
+            public static create(properties?: google.protobuf.IEnumValueDescriptorProto): google.protobuf.EnumValueDescriptorProto;
+            public static encode(message: google.protobuf.IEnumValueDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IEnumValueDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.EnumValueDescriptorProto;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.EnumValueDescriptorProto;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.EnumValueDescriptorProto;
+            public static toObject(message: google.protobuf.EnumValueDescriptorProto, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IServiceDescriptorProto {
+            name?: (string|null);
+            method?: (google.protobuf.IMethodDescriptorProto[]|null);
+            options?: (google.protobuf.IServiceOptions|null);
+        }
+
+        class ServiceDescriptorProto implements IServiceDescriptorProto {
+            constructor(properties?: google.protobuf.IServiceDescriptorProto);
+            public name: string;
+            public method: google.protobuf.IMethodDescriptorProto[];
+            public options?: (google.protobuf.IServiceOptions|null);
+            public static create(properties?: google.protobuf.IServiceDescriptorProto): google.protobuf.ServiceDescriptorProto;
+            public static encode(message: google.protobuf.IServiceDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IServiceDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.ServiceDescriptorProto;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.ServiceDescriptorProto;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.ServiceDescriptorProto;
+            public static toObject(message: google.protobuf.ServiceDescriptorProto, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IMethodDescriptorProto {
+            name?: (string|null);
+            inputType?: (string|null);
+            outputType?: (string|null);
+            options?: (google.protobuf.IMethodOptions|null);
+            clientStreaming?: (boolean|null);
+            serverStreaming?: (boolean|null);
+        }
+
+        class MethodDescriptorProto implements IMethodDescriptorProto {
+            constructor(properties?: google.protobuf.IMethodDescriptorProto);
+            public name: string;
+            public inputType: string;
+            public outputType: string;
+            public options?: (google.protobuf.IMethodOptions|null);
+            public clientStreaming: boolean;
+            public serverStreaming: boolean;
+            public static create(properties?: google.protobuf.IMethodDescriptorProto): google.protobuf.MethodDescriptorProto;
+            public static encode(message: google.protobuf.IMethodDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IMethodDescriptorProto, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.MethodDescriptorProto;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.MethodDescriptorProto;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.MethodDescriptorProto;
+            public static toObject(message: google.protobuf.MethodDescriptorProto, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IFileOptions {
+            javaPackage?: (string|null);
+            javaOuterClassname?: (string|null);
+            javaMultipleFiles?: (boolean|null);
+            javaGenerateEqualsAndHash?: (boolean|null);
+            javaStringCheckUtf8?: (boolean|null);
+            optimizeFor?: (google.protobuf.FileOptions.OptimizeMode|null);
+            goPackage?: (string|null);
+            ccGenericServices?: (boolean|null);
+            javaGenericServices?: (boolean|null);
+            pyGenericServices?: (boolean|null);
+            deprecated?: (boolean|null);
+            ccEnableArenas?: (boolean|null);
+            objcClassPrefix?: (string|null);
+            csharpNamespace?: (string|null);
+            uninterpretedOption?: (google.protobuf.IUninterpretedOption[]|null);
+        }
+
+        class FileOptions implements IFileOptions {
+            constructor(properties?: google.protobuf.IFileOptions);
+            public javaPackage: string;
+            public javaOuterClassname: string;
+            public javaMultipleFiles: boolean;
+            public javaGenerateEqualsAndHash: boolean;
+            public javaStringCheckUtf8: boolean;
+            public optimizeFor: google.protobuf.FileOptions.OptimizeMode;
+            public goPackage: string;
+            public ccGenericServices: boolean;
+            public javaGenericServices: boolean;
+            public pyGenericServices: boolean;
+            public deprecated: boolean;
+            public ccEnableArenas: boolean;
+            public objcClassPrefix: string;
+            public csharpNamespace: string;
+            public uninterpretedOption: google.protobuf.IUninterpretedOption[];
+            public static create(properties?: google.protobuf.IFileOptions): google.protobuf.FileOptions;
+            public static encode(message: google.protobuf.IFileOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IFileOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.FileOptions;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.FileOptions;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.FileOptions;
+            public static toObject(message: google.protobuf.FileOptions, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace FileOptions {
+
+            enum OptimizeMode {
+                SPEED = 1,
+                CODE_SIZE = 2,
+                LITE_RUNTIME = 3
+            }
+        }
+
+        interface IMessageOptions {
+            messageSetWireFormat?: (boolean|null);
+            noStandardDescriptorAccessor?: (boolean|null);
+            deprecated?: (boolean|null);
+            mapEntry?: (boolean|null);
+            uninterpretedOption?: (google.protobuf.IUninterpretedOption[]|null);
+        }
+
+        class MessageOptions implements IMessageOptions {
+            constructor(properties?: google.protobuf.IMessageOptions);
+            public messageSetWireFormat: boolean;
+            public noStandardDescriptorAccessor: boolean;
+            public deprecated: boolean;
+            public mapEntry: boolean;
+            public uninterpretedOption: google.protobuf.IUninterpretedOption[];
+            public static create(properties?: google.protobuf.IMessageOptions): google.protobuf.MessageOptions;
+            public static encode(message: google.protobuf.IMessageOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IMessageOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.MessageOptions;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.MessageOptions;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.MessageOptions;
+            public static toObject(message: google.protobuf.MessageOptions, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IFieldOptions {
+            ctype?: (google.protobuf.FieldOptions.CType|null);
+            packed?: (boolean|null);
+            jstype?: (google.protobuf.FieldOptions.JSType|null);
+            lazy?: (boolean|null);
+            deprecated?: (boolean|null);
+            weak?: (boolean|null);
+            uninterpretedOption?: (google.protobuf.IUninterpretedOption[]|null);
+        }
+
+        class FieldOptions implements IFieldOptions {
+            constructor(properties?: google.protobuf.IFieldOptions);
+            public ctype: google.protobuf.FieldOptions.CType;
+            public packed: boolean;
+            public jstype: google.protobuf.FieldOptions.JSType;
+            public lazy: boolean;
+            public deprecated: boolean;
+            public weak: boolean;
+            public uninterpretedOption: google.protobuf.IUninterpretedOption[];
+            public static create(properties?: google.protobuf.IFieldOptions): google.protobuf.FieldOptions;
+            public static encode(message: google.protobuf.IFieldOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IFieldOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.FieldOptions;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.FieldOptions;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.FieldOptions;
+            public static toObject(message: google.protobuf.FieldOptions, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace FieldOptions {
+
+            enum CType {
+                STRING = 0,
+                CORD = 1,
+                STRING_PIECE = 2
+            }
+
+            enum JSType {
+                JS_NORMAL = 0,
+                JS_STRING = 1,
+                JS_NUMBER = 2
+            }
+        }
+
+        interface IOneofOptions {
+            uninterpretedOption?: (google.protobuf.IUninterpretedOption[]|null);
+        }
+
+        class OneofOptions implements IOneofOptions {
+            constructor(properties?: google.protobuf.IOneofOptions);
+            public uninterpretedOption: google.protobuf.IUninterpretedOption[];
+            public static create(properties?: google.protobuf.IOneofOptions): google.protobuf.OneofOptions;
+            public static encode(message: google.protobuf.IOneofOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IOneofOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.OneofOptions;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.OneofOptions;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.OneofOptions;
+            public static toObject(message: google.protobuf.OneofOptions, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IEnumOptions {
+            allowAlias?: (boolean|null);
+            deprecated?: (boolean|null);
+            uninterpretedOption?: (google.protobuf.IUninterpretedOption[]|null);
+            ".jspb.test.IsExtension.simpleOption"?: (string|null);
+        }
+
+        class EnumOptions implements IEnumOptions {
+            constructor(properties?: google.protobuf.IEnumOptions);
+            public allowAlias: boolean;
+            public deprecated: boolean;
+            public uninterpretedOption: google.protobuf.IUninterpretedOption[];
+            public static create(properties?: google.protobuf.IEnumOptions): google.protobuf.EnumOptions;
+            public static encode(message: google.protobuf.IEnumOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IEnumOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.EnumOptions;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.EnumOptions;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.EnumOptions;
+            public static toObject(message: google.protobuf.EnumOptions, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IEnumValueOptions {
+            deprecated?: (boolean|null);
+            uninterpretedOption?: (google.protobuf.IUninterpretedOption[]|null);
+        }
+
+        class EnumValueOptions implements IEnumValueOptions {
+            constructor(properties?: google.protobuf.IEnumValueOptions);
+            public deprecated: boolean;
+            public uninterpretedOption: google.protobuf.IUninterpretedOption[];
+            public static create(properties?: google.protobuf.IEnumValueOptions): google.protobuf.EnumValueOptions;
+            public static encode(message: google.protobuf.IEnumValueOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IEnumValueOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.EnumValueOptions;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.EnumValueOptions;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.EnumValueOptions;
+            public static toObject(message: google.protobuf.EnumValueOptions, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IServiceOptions {
+            deprecated?: (boolean|null);
+            uninterpretedOption?: (google.protobuf.IUninterpretedOption[]|null);
+        }
+
+        class ServiceOptions implements IServiceOptions {
+            constructor(properties?: google.protobuf.IServiceOptions);
+            public deprecated: boolean;
+            public uninterpretedOption: google.protobuf.IUninterpretedOption[];
+            public static create(properties?: google.protobuf.IServiceOptions): google.protobuf.ServiceOptions;
+            public static encode(message: google.protobuf.IServiceOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IServiceOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.ServiceOptions;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.ServiceOptions;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.ServiceOptions;
+            public static toObject(message: google.protobuf.ServiceOptions, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        interface IMethodOptions {
+            deprecated?: (boolean|null);
+            idempotencyLevel?: (google.protobuf.MethodOptions.IdempotencyLevel|null);
+            uninterpretedOption?: (google.protobuf.IUninterpretedOption[]|null);
+        }
+
+        class MethodOptions implements IMethodOptions {
+            constructor(properties?: google.protobuf.IMethodOptions);
+            public deprecated: boolean;
+            public idempotencyLevel: google.protobuf.MethodOptions.IdempotencyLevel;
+            public uninterpretedOption: google.protobuf.IUninterpretedOption[];
+            public static create(properties?: google.protobuf.IMethodOptions): google.protobuf.MethodOptions;
+            public static encode(message: google.protobuf.IMethodOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IMethodOptions, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.MethodOptions;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.MethodOptions;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.MethodOptions;
+            public static toObject(message: google.protobuf.MethodOptions, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace MethodOptions {
+
+            enum IdempotencyLevel {
+                IDEMPOTENCY_UNKNOWN = 0,
+                NO_SIDE_EFFECTS = 1,
+                IDEMPOTENT = 2
+            }
+        }
+
+        interface IUninterpretedOption {
+            name?: (google.protobuf.UninterpretedOption.INamePart[]|null);
+            identifierValue?: (string|null);
+            positiveIntValue?: (number|Long|null);
+            negativeIntValue?: (number|Long|null);
+            doubleValue?: (number|null);
+            stringValue?: (Uint8Array|null);
+            aggregateValue?: (string|null);
+        }
+
+        class UninterpretedOption implements IUninterpretedOption {
+            constructor(properties?: google.protobuf.IUninterpretedOption);
+            public name: google.protobuf.UninterpretedOption.INamePart[];
+            public identifierValue: string;
+            public positiveIntValue: (number|Long);
+            public negativeIntValue: (number|Long);
+            public doubleValue: number;
+            public stringValue: Uint8Array;
+            public aggregateValue: string;
+            public static create(properties?: google.protobuf.IUninterpretedOption): google.protobuf.UninterpretedOption;
+            public static encode(message: google.protobuf.IUninterpretedOption, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IUninterpretedOption, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.UninterpretedOption;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.UninterpretedOption;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.UninterpretedOption;
+            public static toObject(message: google.protobuf.UninterpretedOption, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace UninterpretedOption {
+
+            interface INamePart {
+                namePart: string;
+                isExtension: boolean;
+            }
+
+            class NamePart implements INamePart {
+                constructor(properties?: google.protobuf.UninterpretedOption.INamePart);
+                public namePart: string;
+                public isExtension: boolean;
+                public static create(properties?: google.protobuf.UninterpretedOption.INamePart): google.protobuf.UninterpretedOption.NamePart;
+                public static encode(message: google.protobuf.UninterpretedOption.INamePart, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static encodeDelimited(message: google.protobuf.UninterpretedOption.INamePart, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.UninterpretedOption.NamePart;
+                public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.UninterpretedOption.NamePart;
+                public static verify(message: { [k: string]: any }): (string|null);
+                public static fromObject(object: { [k: string]: any }): google.protobuf.UninterpretedOption.NamePart;
+                public static toObject(message: google.protobuf.UninterpretedOption.NamePart, options?: $protobuf.IConversionOptions): { [k: string]: any };
+                public toJSON(): { [k: string]: any };
+                public static getTypeUrl(typeUrlPrefix?: string): string;
+            }
+        }
+
+        interface ISourceCodeInfo {
+            location?: (google.protobuf.SourceCodeInfo.ILocation[]|null);
+        }
+
+        class SourceCodeInfo implements ISourceCodeInfo {
+            constructor(properties?: google.protobuf.ISourceCodeInfo);
+            public location: google.protobuf.SourceCodeInfo.ILocation[];
+            public static create(properties?: google.protobuf.ISourceCodeInfo): google.protobuf.SourceCodeInfo;
+            public static encode(message: google.protobuf.ISourceCodeInfo, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.ISourceCodeInfo, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.SourceCodeInfo;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.SourceCodeInfo;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.SourceCodeInfo;
+            public static toObject(message: google.protobuf.SourceCodeInfo, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace SourceCodeInfo {
+
+            interface ILocation {
+                path?: (number[]|null);
+                span?: (number[]|null);
+                leadingComments?: (string|null);
+                trailingComments?: (string|null);
+                leadingDetachedComments?: (string[]|null);
+            }
+
+            class Location implements ILocation {
+                constructor(properties?: google.protobuf.SourceCodeInfo.ILocation);
+                public path: number[];
+                public span: number[];
+                public leadingComments: string;
+                public trailingComments: string;
+                public leadingDetachedComments: string[];
+                public static create(properties?: google.protobuf.SourceCodeInfo.ILocation): google.protobuf.SourceCodeInfo.Location;
+                public static encode(message: google.protobuf.SourceCodeInfo.ILocation, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static encodeDelimited(message: google.protobuf.SourceCodeInfo.ILocation, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.SourceCodeInfo.Location;
+                public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.SourceCodeInfo.Location;
+                public static verify(message: { [k: string]: any }): (string|null);
+                public static fromObject(object: { [k: string]: any }): google.protobuf.SourceCodeInfo.Location;
+                public static toObject(message: google.protobuf.SourceCodeInfo.Location, options?: $protobuf.IConversionOptions): { [k: string]: any };
+                public toJSON(): { [k: string]: any };
+                public static getTypeUrl(typeUrlPrefix?: string): string;
+            }
+        }
+
+        interface IGeneratedCodeInfo {
+            annotation?: (google.protobuf.GeneratedCodeInfo.IAnnotation[]|null);
+        }
+
+        class GeneratedCodeInfo implements IGeneratedCodeInfo {
+            constructor(properties?: google.protobuf.IGeneratedCodeInfo);
+            public annotation: google.protobuf.GeneratedCodeInfo.IAnnotation[];
+            public static create(properties?: google.protobuf.IGeneratedCodeInfo): google.protobuf.GeneratedCodeInfo;
+            public static encode(message: google.protobuf.IGeneratedCodeInfo, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static encodeDelimited(message: google.protobuf.IGeneratedCodeInfo, writer?: $protobuf.Writer): $protobuf.Writer;
+            public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.GeneratedCodeInfo;
+            public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.GeneratedCodeInfo;
+            public static verify(message: { [k: string]: any }): (string|null);
+            public static fromObject(object: { [k: string]: any }): google.protobuf.GeneratedCodeInfo;
+            public static toObject(message: google.protobuf.GeneratedCodeInfo, options?: $protobuf.IConversionOptions): { [k: string]: any };
+            public toJSON(): { [k: string]: any };
+            public static getTypeUrl(typeUrlPrefix?: string): string;
+        }
+
+        namespace GeneratedCodeInfo {
+
+            interface IAnnotation {
+                path?: (number[]|null);
+                sourceFile?: (string|null);
+                begin?: (number|null);
+                end?: (number|null);
+            }
+
+            class Annotation implements IAnnotation {
+                constructor(properties?: google.protobuf.GeneratedCodeInfo.IAnnotation);
+                public path: number[];
+                public sourceFile: string;
+                public begin: number;
+                public end: number;
+                public static create(properties?: google.protobuf.GeneratedCodeInfo.IAnnotation): google.protobuf.GeneratedCodeInfo.Annotation;
+                public static encode(message: google.protobuf.GeneratedCodeInfo.IAnnotation, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static encodeDelimited(message: google.protobuf.GeneratedCodeInfo.IAnnotation, writer?: $protobuf.Writer): $protobuf.Writer;
+                public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.GeneratedCodeInfo.Annotation;
+                public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.GeneratedCodeInfo.Annotation;
+                public static verify(message: { [k: string]: any }): (string|null);
+                public static fromObject(object: { [k: string]: any }): google.protobuf.GeneratedCodeInfo.Annotation;
+                public static toObject(message: google.protobuf.GeneratedCodeInfo.Annotation, options?: $protobuf.IConversionOptions): { [k: string]: any };
+                public toJSON(): { [k: string]: any };
+                public static getTypeUrl(typeUrlPrefix?: string): string;
+            }
+        }
+    }
+}
diff --git a/tests/data/test.js b/tests/data/test.js
new file mode 100644
index 0000000..5e014f0
--- /dev/null
+++ b/tests/data/test.js
@@ -0,0 +1,16936 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+"use strict";
+
+var $protobuf = require("../../minimal");
+
+// Common aliases
+var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+// Exported root namespace
+var $root = $protobuf.roots.test_test || ($protobuf.roots.test_test = {});
+
+$root.jspb = (function() {
+
+    /**
+     * Namespace jspb.
+     * @exports jspb
+     * @namespace
+     */
+    var jspb = {};
+
+    jspb.test = (function() {
+
+        /**
+         * Namespace test.
+         * @memberof jspb
+         * @namespace
+         */
+        var test = {};
+
+        test.Empty = (function() {
+
+            /**
+             * Properties of an Empty.
+             * @memberof jspb.test
+             * @interface IEmpty
+             */
+
+            /**
+             * Constructs a new Empty.
+             * @memberof jspb.test
+             * @classdesc Represents an Empty.
+             * @implements IEmpty
+             * @constructor
+             * @param {jspb.test.IEmpty=} [properties] Properties to set
+             */
+            function Empty(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * Creates a new Empty instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.Empty
+             * @static
+             * @param {jspb.test.IEmpty=} [properties] Properties to set
+             * @returns {jspb.test.Empty} Empty instance
+             */
+            Empty.create = function create(properties) {
+                return new Empty(properties);
+            };
+
+            /**
+             * Encodes the specified Empty message. Does not implicitly {@link jspb.test.Empty.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.Empty
+             * @static
+             * @param {jspb.test.IEmpty} message Empty message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Empty.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified Empty message, length delimited. Does not implicitly {@link jspb.test.Empty.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.Empty
+             * @static
+             * @param {jspb.test.IEmpty} message Empty message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Empty.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes an Empty message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.Empty
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.Empty} Empty
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Empty.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.Empty();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes an Empty message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.Empty
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.Empty} Empty
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Empty.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies an Empty message.
+             * @function verify
+             * @memberof jspb.test.Empty
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            Empty.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                return null;
+            };
+
+            /**
+             * Creates an Empty message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.Empty
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.Empty} Empty
+             */
+            Empty.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.Empty)
+                    return object;
+                return new $root.jspb.test.Empty();
+            };
+
+            /**
+             * Creates a plain object from an Empty message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.Empty
+             * @static
+             * @param {jspb.test.Empty} message Empty
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            Empty.toObject = function toObject() {
+                return {};
+            };
+
+            /**
+             * Converts this Empty to JSON.
+             * @function toJSON
+             * @memberof jspb.test.Empty
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            Empty.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for Empty
+             * @function getTypeUrl
+             * @memberof jspb.test.Empty
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            Empty.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.Empty";
+            };
+
+            return Empty;
+        })();
+
+        /**
+         * OuterEnum enum.
+         * @name jspb.test.OuterEnum
+         * @enum {number}
+         * @property {number} FOO=1 FOO value
+         * @property {number} BAR=2 BAR value
+         */
+        test.OuterEnum = (function() {
+            var valuesById = {}, values = Object.create(valuesById);
+            values[valuesById[1] = "FOO"] = 1;
+            values[valuesById[2] = "BAR"] = 2;
+            return values;
+        })();
+
+        test.EnumContainer = (function() {
+
+            /**
+             * Properties of an EnumContainer.
+             * @memberof jspb.test
+             * @interface IEnumContainer
+             * @property {jspb.test.OuterEnum|null} [outerEnum] EnumContainer outerEnum
+             */
+
+            /**
+             * Constructs a new EnumContainer.
+             * @memberof jspb.test
+             * @classdesc Represents an EnumContainer.
+             * @implements IEnumContainer
+             * @constructor
+             * @param {jspb.test.IEnumContainer=} [properties] Properties to set
+             */
+            function EnumContainer(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * EnumContainer outerEnum.
+             * @member {jspb.test.OuterEnum} outerEnum
+             * @memberof jspb.test.EnumContainer
+             * @instance
+             */
+            EnumContainer.prototype.outerEnum = 1;
+
+            /**
+             * Creates a new EnumContainer instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.EnumContainer
+             * @static
+             * @param {jspb.test.IEnumContainer=} [properties] Properties to set
+             * @returns {jspb.test.EnumContainer} EnumContainer instance
+             */
+            EnumContainer.create = function create(properties) {
+                return new EnumContainer(properties);
+            };
+
+            /**
+             * Encodes the specified EnumContainer message. Does not implicitly {@link jspb.test.EnumContainer.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.EnumContainer
+             * @static
+             * @param {jspb.test.IEnumContainer} message EnumContainer message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            EnumContainer.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.outerEnum != null && Object.hasOwnProperty.call(message, "outerEnum"))
+                    writer.uint32(/* id 1, wireType 0 =*/8).int32(message.outerEnum);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified EnumContainer message, length delimited. Does not implicitly {@link jspb.test.EnumContainer.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.EnumContainer
+             * @static
+             * @param {jspb.test.IEnumContainer} message EnumContainer message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            EnumContainer.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes an EnumContainer message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.EnumContainer
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.EnumContainer} EnumContainer
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            EnumContainer.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.EnumContainer();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.outerEnum = reader.int32();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes an EnumContainer message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.EnumContainer
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.EnumContainer} EnumContainer
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            EnumContainer.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies an EnumContainer message.
+             * @function verify
+             * @memberof jspb.test.EnumContainer
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            EnumContainer.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.outerEnum != null && message.hasOwnProperty("outerEnum"))
+                    switch (message.outerEnum) {
+                    default:
+                        return "outerEnum: enum value expected";
+                    case 1:
+                    case 2:
+                        break;
+                    }
+                return null;
+            };
+
+            /**
+             * Creates an EnumContainer message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.EnumContainer
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.EnumContainer} EnumContainer
+             */
+            EnumContainer.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.EnumContainer)
+                    return object;
+                var message = new $root.jspb.test.EnumContainer();
+                switch (object.outerEnum) {
+                case "FOO":
+                case 1:
+                    message.outerEnum = 1;
+                    break;
+                case "BAR":
+                case 2:
+                    message.outerEnum = 2;
+                    break;
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from an EnumContainer message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.EnumContainer
+             * @static
+             * @param {jspb.test.EnumContainer} message EnumContainer
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            EnumContainer.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults)
+                    object.outerEnum = options.enums === String ? "FOO" : 1;
+                if (message.outerEnum != null && message.hasOwnProperty("outerEnum"))
+                    object.outerEnum = options.enums === String ? $root.jspb.test.OuterEnum[message.outerEnum] : message.outerEnum;
+                return object;
+            };
+
+            /**
+             * Converts this EnumContainer to JSON.
+             * @function toJSON
+             * @memberof jspb.test.EnumContainer
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            EnumContainer.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for EnumContainer
+             * @function getTypeUrl
+             * @memberof jspb.test.EnumContainer
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            EnumContainer.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.EnumContainer";
+            };
+
+            return EnumContainer;
+        })();
+
+        test.Simple1 = (function() {
+
+            /**
+             * Properties of a Simple1.
+             * @memberof jspb.test
+             * @interface ISimple1
+             * @property {string} aString Simple1 aString
+             * @property {Array.<string>|null} [aRepeatedString] Simple1 aRepeatedString
+             * @property {boolean|null} [aBoolean] Simple1 aBoolean
+             */
+
+            /**
+             * Constructs a new Simple1.
+             * @memberof jspb.test
+             * @classdesc Represents a Simple1.
+             * @implements ISimple1
+             * @constructor
+             * @param {jspb.test.ISimple1=} [properties] Properties to set
+             */
+            function Simple1(properties) {
+                this.aRepeatedString = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * Simple1 aString.
+             * @member {string} aString
+             * @memberof jspb.test.Simple1
+             * @instance
+             */
+            Simple1.prototype.aString = "";
+
+            /**
+             * Simple1 aRepeatedString.
+             * @member {Array.<string>} aRepeatedString
+             * @memberof jspb.test.Simple1
+             * @instance
+             */
+            Simple1.prototype.aRepeatedString = $util.emptyArray;
+
+            /**
+             * Simple1 aBoolean.
+             * @member {boolean} aBoolean
+             * @memberof jspb.test.Simple1
+             * @instance
+             */
+            Simple1.prototype.aBoolean = false;
+
+            /**
+             * Creates a new Simple1 instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.Simple1
+             * @static
+             * @param {jspb.test.ISimple1=} [properties] Properties to set
+             * @returns {jspb.test.Simple1} Simple1 instance
+             */
+            Simple1.create = function create(properties) {
+                return new Simple1(properties);
+            };
+
+            /**
+             * Encodes the specified Simple1 message. Does not implicitly {@link jspb.test.Simple1.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.Simple1
+             * @static
+             * @param {jspb.test.ISimple1} message Simple1 message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Simple1.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                writer.uint32(/* id 1, wireType 2 =*/10).string(message.aString);
+                if (message.aRepeatedString != null && message.aRepeatedString.length)
+                    for (var i = 0; i < message.aRepeatedString.length; ++i)
+                        writer.uint32(/* id 2, wireType 2 =*/18).string(message.aRepeatedString[i]);
+                if (message.aBoolean != null && Object.hasOwnProperty.call(message, "aBoolean"))
+                    writer.uint32(/* id 3, wireType 0 =*/24).bool(message.aBoolean);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified Simple1 message, length delimited. Does not implicitly {@link jspb.test.Simple1.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.Simple1
+             * @static
+             * @param {jspb.test.ISimple1} message Simple1 message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Simple1.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a Simple1 message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.Simple1
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.Simple1} Simple1
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Simple1.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.Simple1();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.aString = reader.string();
+                        break;
+                    case 2:
+                        if (!(message.aRepeatedString && message.aRepeatedString.length))
+                            message.aRepeatedString = [];
+                        message.aRepeatedString.push(reader.string());
+                        break;
+                    case 3:
+                        message.aBoolean = reader.bool();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("aString"))
+                    throw $util.ProtocolError("missing required 'aString'", { instance: message });
+                return message;
+            };
+
+            /**
+             * Decodes a Simple1 message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.Simple1
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.Simple1} Simple1
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Simple1.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a Simple1 message.
+             * @function verify
+             * @memberof jspb.test.Simple1
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            Simple1.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (!$util.isString(message.aString))
+                    return "aString: string expected";
+                if (message.aRepeatedString != null && message.hasOwnProperty("aRepeatedString")) {
+                    if (!Array.isArray(message.aRepeatedString))
+                        return "aRepeatedString: array expected";
+                    for (var i = 0; i < message.aRepeatedString.length; ++i)
+                        if (!$util.isString(message.aRepeatedString[i]))
+                            return "aRepeatedString: string[] expected";
+                }
+                if (message.aBoolean != null && message.hasOwnProperty("aBoolean"))
+                    if (typeof message.aBoolean !== "boolean")
+                        return "aBoolean: boolean expected";
+                return null;
+            };
+
+            /**
+             * Creates a Simple1 message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.Simple1
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.Simple1} Simple1
+             */
+            Simple1.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.Simple1)
+                    return object;
+                var message = new $root.jspb.test.Simple1();
+                if (object.aString != null)
+                    message.aString = String(object.aString);
+                if (object.aRepeatedString) {
+                    if (!Array.isArray(object.aRepeatedString))
+                        throw TypeError(".jspb.test.Simple1.aRepeatedString: array expected");
+                    message.aRepeatedString = [];
+                    for (var i = 0; i < object.aRepeatedString.length; ++i)
+                        message.aRepeatedString[i] = String(object.aRepeatedString[i]);
+                }
+                if (object.aBoolean != null)
+                    message.aBoolean = Boolean(object.aBoolean);
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a Simple1 message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.Simple1
+             * @static
+             * @param {jspb.test.Simple1} message Simple1
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            Simple1.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.aRepeatedString = [];
+                if (options.defaults) {
+                    object.aString = "";
+                    object.aBoolean = false;
+                }
+                if (message.aString != null && message.hasOwnProperty("aString"))
+                    object.aString = message.aString;
+                if (message.aRepeatedString && message.aRepeatedString.length) {
+                    object.aRepeatedString = [];
+                    for (var j = 0; j < message.aRepeatedString.length; ++j)
+                        object.aRepeatedString[j] = message.aRepeatedString[j];
+                }
+                if (message.aBoolean != null && message.hasOwnProperty("aBoolean"))
+                    object.aBoolean = message.aBoolean;
+                return object;
+            };
+
+            /**
+             * Converts this Simple1 to JSON.
+             * @function toJSON
+             * @memberof jspb.test.Simple1
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            Simple1.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for Simple1
+             * @function getTypeUrl
+             * @memberof jspb.test.Simple1
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            Simple1.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.Simple1";
+            };
+
+            return Simple1;
+        })();
+
+        test.Simple2 = (function() {
+
+            /**
+             * Properties of a Simple2.
+             * @memberof jspb.test
+             * @interface ISimple2
+             * @property {string} aString Simple2 aString
+             * @property {Array.<string>|null} [aRepeatedString] Simple2 aRepeatedString
+             */
+
+            /**
+             * Constructs a new Simple2.
+             * @memberof jspb.test
+             * @classdesc Represents a Simple2.
+             * @implements ISimple2
+             * @constructor
+             * @param {jspb.test.ISimple2=} [properties] Properties to set
+             */
+            function Simple2(properties) {
+                this.aRepeatedString = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * Simple2 aString.
+             * @member {string} aString
+             * @memberof jspb.test.Simple2
+             * @instance
+             */
+            Simple2.prototype.aString = "";
+
+            /**
+             * Simple2 aRepeatedString.
+             * @member {Array.<string>} aRepeatedString
+             * @memberof jspb.test.Simple2
+             * @instance
+             */
+            Simple2.prototype.aRepeatedString = $util.emptyArray;
+
+            /**
+             * Creates a new Simple2 instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.Simple2
+             * @static
+             * @param {jspb.test.ISimple2=} [properties] Properties to set
+             * @returns {jspb.test.Simple2} Simple2 instance
+             */
+            Simple2.create = function create(properties) {
+                return new Simple2(properties);
+            };
+
+            /**
+             * Encodes the specified Simple2 message. Does not implicitly {@link jspb.test.Simple2.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.Simple2
+             * @static
+             * @param {jspb.test.ISimple2} message Simple2 message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Simple2.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                writer.uint32(/* id 1, wireType 2 =*/10).string(message.aString);
+                if (message.aRepeatedString != null && message.aRepeatedString.length)
+                    for (var i = 0; i < message.aRepeatedString.length; ++i)
+                        writer.uint32(/* id 2, wireType 2 =*/18).string(message.aRepeatedString[i]);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified Simple2 message, length delimited. Does not implicitly {@link jspb.test.Simple2.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.Simple2
+             * @static
+             * @param {jspb.test.ISimple2} message Simple2 message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Simple2.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a Simple2 message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.Simple2
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.Simple2} Simple2
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Simple2.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.Simple2();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.aString = reader.string();
+                        break;
+                    case 2:
+                        if (!(message.aRepeatedString && message.aRepeatedString.length))
+                            message.aRepeatedString = [];
+                        message.aRepeatedString.push(reader.string());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("aString"))
+                    throw $util.ProtocolError("missing required 'aString'", { instance: message });
+                return message;
+            };
+
+            /**
+             * Decodes a Simple2 message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.Simple2
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.Simple2} Simple2
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Simple2.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a Simple2 message.
+             * @function verify
+             * @memberof jspb.test.Simple2
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            Simple2.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (!$util.isString(message.aString))
+                    return "aString: string expected";
+                if (message.aRepeatedString != null && message.hasOwnProperty("aRepeatedString")) {
+                    if (!Array.isArray(message.aRepeatedString))
+                        return "aRepeatedString: array expected";
+                    for (var i = 0; i < message.aRepeatedString.length; ++i)
+                        if (!$util.isString(message.aRepeatedString[i]))
+                            return "aRepeatedString: string[] expected";
+                }
+                return null;
+            };
+
+            /**
+             * Creates a Simple2 message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.Simple2
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.Simple2} Simple2
+             */
+            Simple2.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.Simple2)
+                    return object;
+                var message = new $root.jspb.test.Simple2();
+                if (object.aString != null)
+                    message.aString = String(object.aString);
+                if (object.aRepeatedString) {
+                    if (!Array.isArray(object.aRepeatedString))
+                        throw TypeError(".jspb.test.Simple2.aRepeatedString: array expected");
+                    message.aRepeatedString = [];
+                    for (var i = 0; i < object.aRepeatedString.length; ++i)
+                        message.aRepeatedString[i] = String(object.aRepeatedString[i]);
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a Simple2 message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.Simple2
+             * @static
+             * @param {jspb.test.Simple2} message Simple2
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            Simple2.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.aRepeatedString = [];
+                if (options.defaults)
+                    object.aString = "";
+                if (message.aString != null && message.hasOwnProperty("aString"))
+                    object.aString = message.aString;
+                if (message.aRepeatedString && message.aRepeatedString.length) {
+                    object.aRepeatedString = [];
+                    for (var j = 0; j < message.aRepeatedString.length; ++j)
+                        object.aRepeatedString[j] = message.aRepeatedString[j];
+                }
+                return object;
+            };
+
+            /**
+             * Converts this Simple2 to JSON.
+             * @function toJSON
+             * @memberof jspb.test.Simple2
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            Simple2.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for Simple2
+             * @function getTypeUrl
+             * @memberof jspb.test.Simple2
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            Simple2.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.Simple2";
+            };
+
+            return Simple2;
+        })();
+
+        test.SpecialCases = (function() {
+
+            /**
+             * Properties of a SpecialCases.
+             * @memberof jspb.test
+             * @interface ISpecialCases
+             * @property {string} normal SpecialCases normal
+             * @property {string} "default" SpecialCases default
+             * @property {string} "function" SpecialCases function
+             * @property {string} "var" SpecialCases var
+             */
+
+            /**
+             * Constructs a new SpecialCases.
+             * @memberof jspb.test
+             * @classdesc Represents a SpecialCases.
+             * @implements ISpecialCases
+             * @constructor
+             * @param {jspb.test.ISpecialCases=} [properties] Properties to set
+             */
+            function SpecialCases(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * SpecialCases normal.
+             * @member {string} normal
+             * @memberof jspb.test.SpecialCases
+             * @instance
+             */
+            SpecialCases.prototype.normal = "";
+
+            /**
+             * SpecialCases default.
+             * @member {string} default
+             * @memberof jspb.test.SpecialCases
+             * @instance
+             */
+            SpecialCases.prototype["default"] = "";
+
+            /**
+             * SpecialCases function.
+             * @member {string} function
+             * @memberof jspb.test.SpecialCases
+             * @instance
+             */
+            SpecialCases.prototype["function"] = "";
+
+            /**
+             * SpecialCases var.
+             * @member {string} var
+             * @memberof jspb.test.SpecialCases
+             * @instance
+             */
+            SpecialCases.prototype["var"] = "";
+
+            /**
+             * Creates a new SpecialCases instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.SpecialCases
+             * @static
+             * @param {jspb.test.ISpecialCases=} [properties] Properties to set
+             * @returns {jspb.test.SpecialCases} SpecialCases instance
+             */
+            SpecialCases.create = function create(properties) {
+                return new SpecialCases(properties);
+            };
+
+            /**
+             * Encodes the specified SpecialCases message. Does not implicitly {@link jspb.test.SpecialCases.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.SpecialCases
+             * @static
+             * @param {jspb.test.ISpecialCases} message SpecialCases message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            SpecialCases.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                writer.uint32(/* id 1, wireType 2 =*/10).string(message.normal);
+                writer.uint32(/* id 2, wireType 2 =*/18).string(message["default"]);
+                writer.uint32(/* id 3, wireType 2 =*/26).string(message["function"]);
+                writer.uint32(/* id 4, wireType 2 =*/34).string(message["var"]);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified SpecialCases message, length delimited. Does not implicitly {@link jspb.test.SpecialCases.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.SpecialCases
+             * @static
+             * @param {jspb.test.ISpecialCases} message SpecialCases message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            SpecialCases.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a SpecialCases message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.SpecialCases
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.SpecialCases} SpecialCases
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            SpecialCases.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.SpecialCases();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.normal = reader.string();
+                        break;
+                    case 2:
+                        message["default"] = reader.string();
+                        break;
+                    case 3:
+                        message["function"] = reader.string();
+                        break;
+                    case 4:
+                        message["var"] = reader.string();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("normal"))
+                    throw $util.ProtocolError("missing required 'normal'", { instance: message });
+                if (!message.hasOwnProperty("default"))
+                    throw $util.ProtocolError("missing required 'default'", { instance: message });
+                if (!message.hasOwnProperty("function"))
+                    throw $util.ProtocolError("missing required 'function'", { instance: message });
+                if (!message.hasOwnProperty("var"))
+                    throw $util.ProtocolError("missing required 'var'", { instance: message });
+                return message;
+            };
+
+            /**
+             * Decodes a SpecialCases message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.SpecialCases
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.SpecialCases} SpecialCases
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            SpecialCases.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a SpecialCases message.
+             * @function verify
+             * @memberof jspb.test.SpecialCases
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            SpecialCases.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (!$util.isString(message.normal))
+                    return "normal: string expected";
+                if (!$util.isString(message["default"]))
+                    return "default: string expected";
+                if (!$util.isString(message["function"]))
+                    return "function: string expected";
+                if (!$util.isString(message["var"]))
+                    return "var: string expected";
+                return null;
+            };
+
+            /**
+             * Creates a SpecialCases message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.SpecialCases
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.SpecialCases} SpecialCases
+             */
+            SpecialCases.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.SpecialCases)
+                    return object;
+                var message = new $root.jspb.test.SpecialCases();
+                if (object.normal != null)
+                    message.normal = String(object.normal);
+                if (object["default"] != null)
+                    message["default"] = String(object["default"]);
+                if (object["function"] != null)
+                    message["function"] = String(object["function"]);
+                if (object["var"] != null)
+                    message["var"] = String(object["var"]);
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a SpecialCases message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.SpecialCases
+             * @static
+             * @param {jspb.test.SpecialCases} message SpecialCases
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            SpecialCases.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults) {
+                    object.normal = "";
+                    object["default"] = "";
+                    object["function"] = "";
+                    object["var"] = "";
+                }
+                if (message.normal != null && message.hasOwnProperty("normal"))
+                    object.normal = message.normal;
+                if (message["default"] != null && message.hasOwnProperty("default"))
+                    object["default"] = message["default"];
+                if (message["function"] != null && message.hasOwnProperty("function"))
+                    object["function"] = message["function"];
+                if (message["var"] != null && message.hasOwnProperty("var"))
+                    object["var"] = message["var"];
+                return object;
+            };
+
+            /**
+             * Converts this SpecialCases to JSON.
+             * @function toJSON
+             * @memberof jspb.test.SpecialCases
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            SpecialCases.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for SpecialCases
+             * @function getTypeUrl
+             * @memberof jspb.test.SpecialCases
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            SpecialCases.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.SpecialCases";
+            };
+
+            return SpecialCases;
+        })();
+
+        test.OptionalFields = (function() {
+
+            /**
+             * Properties of an OptionalFields.
+             * @memberof jspb.test
+             * @interface IOptionalFields
+             * @property {string|null} [aString] OptionalFields aString
+             * @property {boolean} aBool OptionalFields aBool
+             * @property {jspb.test.OptionalFields.INested|null} [aNestedMessage] OptionalFields aNestedMessage
+             * @property {Array.<jspb.test.OptionalFields.INested>|null} [aRepeatedMessage] OptionalFields aRepeatedMessage
+             * @property {Array.<string>|null} [aRepeatedString] OptionalFields aRepeatedString
+             */
+
+            /**
+             * Constructs a new OptionalFields.
+             * @memberof jspb.test
+             * @classdesc Represents an OptionalFields.
+             * @implements IOptionalFields
+             * @constructor
+             * @param {jspb.test.IOptionalFields=} [properties] Properties to set
+             */
+            function OptionalFields(properties) {
+                this.aRepeatedMessage = [];
+                this.aRepeatedString = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * OptionalFields aString.
+             * @member {string} aString
+             * @memberof jspb.test.OptionalFields
+             * @instance
+             */
+            OptionalFields.prototype.aString = "";
+
+            /**
+             * OptionalFields aBool.
+             * @member {boolean} aBool
+             * @memberof jspb.test.OptionalFields
+             * @instance
+             */
+            OptionalFields.prototype.aBool = false;
+
+            /**
+             * OptionalFields aNestedMessage.
+             * @member {jspb.test.OptionalFields.INested|null|undefined} aNestedMessage
+             * @memberof jspb.test.OptionalFields
+             * @instance
+             */
+            OptionalFields.prototype.aNestedMessage = null;
+
+            /**
+             * OptionalFields aRepeatedMessage.
+             * @member {Array.<jspb.test.OptionalFields.INested>} aRepeatedMessage
+             * @memberof jspb.test.OptionalFields
+             * @instance
+             */
+            OptionalFields.prototype.aRepeatedMessage = $util.emptyArray;
+
+            /**
+             * OptionalFields aRepeatedString.
+             * @member {Array.<string>} aRepeatedString
+             * @memberof jspb.test.OptionalFields
+             * @instance
+             */
+            OptionalFields.prototype.aRepeatedString = $util.emptyArray;
+
+            /**
+             * Creates a new OptionalFields instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.OptionalFields
+             * @static
+             * @param {jspb.test.IOptionalFields=} [properties] Properties to set
+             * @returns {jspb.test.OptionalFields} OptionalFields instance
+             */
+            OptionalFields.create = function create(properties) {
+                return new OptionalFields(properties);
+            };
+
+            /**
+             * Encodes the specified OptionalFields message. Does not implicitly {@link jspb.test.OptionalFields.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.OptionalFields
+             * @static
+             * @param {jspb.test.IOptionalFields} message OptionalFields message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            OptionalFields.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.aString != null && Object.hasOwnProperty.call(message, "aString"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.aString);
+                writer.uint32(/* id 2, wireType 0 =*/16).bool(message.aBool);
+                if (message.aNestedMessage != null && Object.hasOwnProperty.call(message, "aNestedMessage"))
+                    $root.jspb.test.OptionalFields.Nested.encode(message.aNestedMessage, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim();
+                if (message.aRepeatedMessage != null && message.aRepeatedMessage.length)
+                    for (var i = 0; i < message.aRepeatedMessage.length; ++i)
+                        $root.jspb.test.OptionalFields.Nested.encode(message.aRepeatedMessage[i], writer.uint32(/* id 4, wireType 2 =*/34).fork()).ldelim();
+                if (message.aRepeatedString != null && message.aRepeatedString.length)
+                    for (var i = 0; i < message.aRepeatedString.length; ++i)
+                        writer.uint32(/* id 5, wireType 2 =*/42).string(message.aRepeatedString[i]);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified OptionalFields message, length delimited. Does not implicitly {@link jspb.test.OptionalFields.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.OptionalFields
+             * @static
+             * @param {jspb.test.IOptionalFields} message OptionalFields message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            OptionalFields.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes an OptionalFields message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.OptionalFields
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.OptionalFields} OptionalFields
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            OptionalFields.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.OptionalFields();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.aString = reader.string();
+                        break;
+                    case 2:
+                        message.aBool = reader.bool();
+                        break;
+                    case 3:
+                        message.aNestedMessage = $root.jspb.test.OptionalFields.Nested.decode(reader, reader.uint32());
+                        break;
+                    case 4:
+                        if (!(message.aRepeatedMessage && message.aRepeatedMessage.length))
+                            message.aRepeatedMessage = [];
+                        message.aRepeatedMessage.push($root.jspb.test.OptionalFields.Nested.decode(reader, reader.uint32()));
+                        break;
+                    case 5:
+                        if (!(message.aRepeatedString && message.aRepeatedString.length))
+                            message.aRepeatedString = [];
+                        message.aRepeatedString.push(reader.string());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("aBool"))
+                    throw $util.ProtocolError("missing required 'aBool'", { instance: message });
+                return message;
+            };
+
+            /**
+             * Decodes an OptionalFields message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.OptionalFields
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.OptionalFields} OptionalFields
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            OptionalFields.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies an OptionalFields message.
+             * @function verify
+             * @memberof jspb.test.OptionalFields
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            OptionalFields.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.aString != null && message.hasOwnProperty("aString"))
+                    if (!$util.isString(message.aString))
+                        return "aString: string expected";
+                if (typeof message.aBool !== "boolean")
+                    return "aBool: boolean expected";
+                if (message.aNestedMessage != null && message.hasOwnProperty("aNestedMessage")) {
+                    var error = $root.jspb.test.OptionalFields.Nested.verify(message.aNestedMessage);
+                    if (error)
+                        return "aNestedMessage." + error;
+                }
+                if (message.aRepeatedMessage != null && message.hasOwnProperty("aRepeatedMessage")) {
+                    if (!Array.isArray(message.aRepeatedMessage))
+                        return "aRepeatedMessage: array expected";
+                    for (var i = 0; i < message.aRepeatedMessage.length; ++i) {
+                        var error = $root.jspb.test.OptionalFields.Nested.verify(message.aRepeatedMessage[i]);
+                        if (error)
+                            return "aRepeatedMessage." + error;
+                    }
+                }
+                if (message.aRepeatedString != null && message.hasOwnProperty("aRepeatedString")) {
+                    if (!Array.isArray(message.aRepeatedString))
+                        return "aRepeatedString: array expected";
+                    for (var i = 0; i < message.aRepeatedString.length; ++i)
+                        if (!$util.isString(message.aRepeatedString[i]))
+                            return "aRepeatedString: string[] expected";
+                }
+                return null;
+            };
+
+            /**
+             * Creates an OptionalFields message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.OptionalFields
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.OptionalFields} OptionalFields
+             */
+            OptionalFields.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.OptionalFields)
+                    return object;
+                var message = new $root.jspb.test.OptionalFields();
+                if (object.aString != null)
+                    message.aString = String(object.aString);
+                if (object.aBool != null)
+                    message.aBool = Boolean(object.aBool);
+                if (object.aNestedMessage != null) {
+                    if (typeof object.aNestedMessage !== "object")
+                        throw TypeError(".jspb.test.OptionalFields.aNestedMessage: object expected");
+                    message.aNestedMessage = $root.jspb.test.OptionalFields.Nested.fromObject(object.aNestedMessage);
+                }
+                if (object.aRepeatedMessage) {
+                    if (!Array.isArray(object.aRepeatedMessage))
+                        throw TypeError(".jspb.test.OptionalFields.aRepeatedMessage: array expected");
+                    message.aRepeatedMessage = [];
+                    for (var i = 0; i < object.aRepeatedMessage.length; ++i) {
+                        if (typeof object.aRepeatedMessage[i] !== "object")
+                            throw TypeError(".jspb.test.OptionalFields.aRepeatedMessage: object expected");
+                        message.aRepeatedMessage[i] = $root.jspb.test.OptionalFields.Nested.fromObject(object.aRepeatedMessage[i]);
+                    }
+                }
+                if (object.aRepeatedString) {
+                    if (!Array.isArray(object.aRepeatedString))
+                        throw TypeError(".jspb.test.OptionalFields.aRepeatedString: array expected");
+                    message.aRepeatedString = [];
+                    for (var i = 0; i < object.aRepeatedString.length; ++i)
+                        message.aRepeatedString[i] = String(object.aRepeatedString[i]);
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from an OptionalFields message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.OptionalFields
+             * @static
+             * @param {jspb.test.OptionalFields} message OptionalFields
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            OptionalFields.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults) {
+                    object.aRepeatedMessage = [];
+                    object.aRepeatedString = [];
+                }
+                if (options.defaults) {
+                    object.aString = "";
+                    object.aBool = false;
+                    object.aNestedMessage = null;
+                }
+                if (message.aString != null && message.hasOwnProperty("aString"))
+                    object.aString = message.aString;
+                if (message.aBool != null && message.hasOwnProperty("aBool"))
+                    object.aBool = message.aBool;
+                if (message.aNestedMessage != null && message.hasOwnProperty("aNestedMessage"))
+                    object.aNestedMessage = $root.jspb.test.OptionalFields.Nested.toObject(message.aNestedMessage, options);
+                if (message.aRepeatedMessage && message.aRepeatedMessage.length) {
+                    object.aRepeatedMessage = [];
+                    for (var j = 0; j < message.aRepeatedMessage.length; ++j)
+                        object.aRepeatedMessage[j] = $root.jspb.test.OptionalFields.Nested.toObject(message.aRepeatedMessage[j], options);
+                }
+                if (message.aRepeatedString && message.aRepeatedString.length) {
+                    object.aRepeatedString = [];
+                    for (var j = 0; j < message.aRepeatedString.length; ++j)
+                        object.aRepeatedString[j] = message.aRepeatedString[j];
+                }
+                return object;
+            };
+
+            /**
+             * Converts this OptionalFields to JSON.
+             * @function toJSON
+             * @memberof jspb.test.OptionalFields
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            OptionalFields.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for OptionalFields
+             * @function getTypeUrl
+             * @memberof jspb.test.OptionalFields
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            OptionalFields.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.OptionalFields";
+            };
+
+            OptionalFields.Nested = (function() {
+
+                /**
+                 * Properties of a Nested.
+                 * @memberof jspb.test.OptionalFields
+                 * @interface INested
+                 * @property {number|null} [anInt] Nested anInt
+                 */
+
+                /**
+                 * Constructs a new Nested.
+                 * @memberof jspb.test.OptionalFields
+                 * @classdesc Represents a Nested.
+                 * @implements INested
+                 * @constructor
+                 * @param {jspb.test.OptionalFields.INested=} [properties] Properties to set
+                 */
+                function Nested(properties) {
+                    if (properties)
+                        for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                            if (properties[keys[i]] != null)
+                                this[keys[i]] = properties[keys[i]];
+                }
+
+                /**
+                 * Nested anInt.
+                 * @member {number} anInt
+                 * @memberof jspb.test.OptionalFields.Nested
+                 * @instance
+                 */
+                Nested.prototype.anInt = 0;
+
+                /**
+                 * Creates a new Nested instance using the specified properties.
+                 * @function create
+                 * @memberof jspb.test.OptionalFields.Nested
+                 * @static
+                 * @param {jspb.test.OptionalFields.INested=} [properties] Properties to set
+                 * @returns {jspb.test.OptionalFields.Nested} Nested instance
+                 */
+                Nested.create = function create(properties) {
+                    return new Nested(properties);
+                };
+
+                /**
+                 * Encodes the specified Nested message. Does not implicitly {@link jspb.test.OptionalFields.Nested.verify|verify} messages.
+                 * @function encode
+                 * @memberof jspb.test.OptionalFields.Nested
+                 * @static
+                 * @param {jspb.test.OptionalFields.INested} message Nested message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                Nested.encode = function encode(message, writer) {
+                    if (!writer)
+                        writer = $Writer.create();
+                    if (message.anInt != null && Object.hasOwnProperty.call(message, "anInt"))
+                        writer.uint32(/* id 1, wireType 0 =*/8).int32(message.anInt);
+                    return writer;
+                };
+
+                /**
+                 * Encodes the specified Nested message, length delimited. Does not implicitly {@link jspb.test.OptionalFields.Nested.verify|verify} messages.
+                 * @function encodeDelimited
+                 * @memberof jspb.test.OptionalFields.Nested
+                 * @static
+                 * @param {jspb.test.OptionalFields.INested} message Nested message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                Nested.encodeDelimited = function encodeDelimited(message, writer) {
+                    return this.encode(message, writer).ldelim();
+                };
+
+                /**
+                 * Decodes a Nested message from the specified reader or buffer.
+                 * @function decode
+                 * @memberof jspb.test.OptionalFields.Nested
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @param {number} [length] Message length if known beforehand
+                 * @returns {jspb.test.OptionalFields.Nested} Nested
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                Nested.decode = function decode(reader, length) {
+                    if (!(reader instanceof $Reader))
+                        reader = $Reader.create(reader);
+                    var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.OptionalFields.Nested();
+                    while (reader.pos < end) {
+                        var tag = reader.uint32();
+                        switch (tag >>> 3) {
+                        case 1:
+                            message.anInt = reader.int32();
+                            break;
+                        default:
+                            reader.skipType(tag & 7);
+                            break;
+                        }
+                    }
+                    return message;
+                };
+
+                /**
+                 * Decodes a Nested message from the specified reader or buffer, length delimited.
+                 * @function decodeDelimited
+                 * @memberof jspb.test.OptionalFields.Nested
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @returns {jspb.test.OptionalFields.Nested} Nested
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                Nested.decodeDelimited = function decodeDelimited(reader) {
+                    if (!(reader instanceof $Reader))
+                        reader = new $Reader(reader);
+                    return this.decode(reader, reader.uint32());
+                };
+
+                /**
+                 * Verifies a Nested message.
+                 * @function verify
+                 * @memberof jspb.test.OptionalFields.Nested
+                 * @static
+                 * @param {Object.<string,*>} message Plain object to verify
+                 * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                 */
+                Nested.verify = function verify(message) {
+                    if (typeof message !== "object" || message === null)
+                        return "object expected";
+                    if (message.anInt != null && message.hasOwnProperty("anInt"))
+                        if (!$util.isInteger(message.anInt))
+                            return "anInt: integer expected";
+                    return null;
+                };
+
+                /**
+                 * Creates a Nested message from a plain object. Also converts values to their respective internal types.
+                 * @function fromObject
+                 * @memberof jspb.test.OptionalFields.Nested
+                 * @static
+                 * @param {Object.<string,*>} object Plain object
+                 * @returns {jspb.test.OptionalFields.Nested} Nested
+                 */
+                Nested.fromObject = function fromObject(object) {
+                    if (object instanceof $root.jspb.test.OptionalFields.Nested)
+                        return object;
+                    var message = new $root.jspb.test.OptionalFields.Nested();
+                    if (object.anInt != null)
+                        message.anInt = object.anInt | 0;
+                    return message;
+                };
+
+                /**
+                 * Creates a plain object from a Nested message. Also converts values to other types if specified.
+                 * @function toObject
+                 * @memberof jspb.test.OptionalFields.Nested
+                 * @static
+                 * @param {jspb.test.OptionalFields.Nested} message Nested
+                 * @param {$protobuf.IConversionOptions} [options] Conversion options
+                 * @returns {Object.<string,*>} Plain object
+                 */
+                Nested.toObject = function toObject(message, options) {
+                    if (!options)
+                        options = {};
+                    var object = {};
+                    if (options.defaults)
+                        object.anInt = 0;
+                    if (message.anInt != null && message.hasOwnProperty("anInt"))
+                        object.anInt = message.anInt;
+                    return object;
+                };
+
+                /**
+                 * Converts this Nested to JSON.
+                 * @function toJSON
+                 * @memberof jspb.test.OptionalFields.Nested
+                 * @instance
+                 * @returns {Object.<string,*>} JSON object
+                 */
+                Nested.prototype.toJSON = function toJSON() {
+                    return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                };
+
+                /**
+                 * Gets the default type url for Nested
+                 * @function getTypeUrl
+                 * @memberof jspb.test.OptionalFields.Nested
+                 * @static
+                 * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                 * @returns {string} The default type url
+                 */
+                Nested.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                    if (typeUrlPrefix === undefined) {
+                        typeUrlPrefix = "type.googleapis.com";
+                    }
+                    return typeUrlPrefix + "/jspb.test.OptionalFields.Nested";
+                };
+
+                return Nested;
+            })();
+
+            return OptionalFields;
+        })();
+
+        test.HasExtensions = (function() {
+
+            /**
+             * Properties of a HasExtensions.
+             * @memberof jspb.test
+             * @interface IHasExtensions
+             * @property {string|null} [str1] HasExtensions str1
+             * @property {string|null} [str2] HasExtensions str2
+             * @property {string|null} [str3] HasExtensions str3
+             * @property {jspb.test.IIsExtension|null} [".jspb.test.IsExtension.extField"] HasExtensions .jspb.test.IsExtension.extField
+             * @property {jspb.test.ISimple1|null} [".jspb.test.IndirectExtension.simple"] HasExtensions .jspb.test.IndirectExtension.simple
+             * @property {string|null} [".jspb.test.IndirectExtension.str"] HasExtensions .jspb.test.IndirectExtension.str
+             * @property {Array.<string>|null} [".jspb.test.IndirectExtension.repeatedStr"] HasExtensions .jspb.test.IndirectExtension.repeatedStr
+             * @property {Array.<jspb.test.ISimple1>|null} [".jspb.test.IndirectExtension.repeatedSimple"] HasExtensions .jspb.test.IndirectExtension.repeatedSimple
+             * @property {jspb.test.ISimple1|null} [".jspb.test.simple1"] HasExtensions .jspb.test.simple1
+             */
+
+            /**
+             * Constructs a new HasExtensions.
+             * @memberof jspb.test
+             * @classdesc Represents a HasExtensions.
+             * @implements IHasExtensions
+             * @constructor
+             * @param {jspb.test.IHasExtensions=} [properties] Properties to set
+             */
+            function HasExtensions(properties) {
+                this[".jspb.test.IndirectExtension.repeatedStr"] = [];
+                this[".jspb.test.IndirectExtension.repeatedSimple"] = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * HasExtensions str1.
+             * @member {string} str1
+             * @memberof jspb.test.HasExtensions
+             * @instance
+             */
+            HasExtensions.prototype.str1 = "";
+
+            /**
+             * HasExtensions str2.
+             * @member {string} str2
+             * @memberof jspb.test.HasExtensions
+             * @instance
+             */
+            HasExtensions.prototype.str2 = "";
+
+            /**
+             * HasExtensions str3.
+             * @member {string} str3
+             * @memberof jspb.test.HasExtensions
+             * @instance
+             */
+            HasExtensions.prototype.str3 = "";
+
+            /**
+             * HasExtensions .jspb.test.IsExtension.extField.
+             * @member {jspb.test.IIsExtension|null|undefined} .jspb.test.IsExtension.extField
+             * @memberof jspb.test.HasExtensions
+             * @instance
+             */
+            HasExtensions.prototype[".jspb.test.IsExtension.extField"] = null;
+
+            /**
+             * HasExtensions .jspb.test.IndirectExtension.simple.
+             * @member {jspb.test.ISimple1|null|undefined} .jspb.test.IndirectExtension.simple
+             * @memberof jspb.test.HasExtensions
+             * @instance
+             */
+            HasExtensions.prototype[".jspb.test.IndirectExtension.simple"] = null;
+
+            /**
+             * HasExtensions .jspb.test.IndirectExtension.str.
+             * @member {string} .jspb.test.IndirectExtension.str
+             * @memberof jspb.test.HasExtensions
+             * @instance
+             */
+            HasExtensions.prototype[".jspb.test.IndirectExtension.str"] = "";
+
+            /**
+             * HasExtensions .jspb.test.IndirectExtension.repeatedStr.
+             * @member {Array.<string>} .jspb.test.IndirectExtension.repeatedStr
+             * @memberof jspb.test.HasExtensions
+             * @instance
+             */
+            HasExtensions.prototype[".jspb.test.IndirectExtension.repeatedStr"] = $util.emptyArray;
+
+            /**
+             * HasExtensions .jspb.test.IndirectExtension.repeatedSimple.
+             * @member {Array.<jspb.test.ISimple1>} .jspb.test.IndirectExtension.repeatedSimple
+             * @memberof jspb.test.HasExtensions
+             * @instance
+             */
+            HasExtensions.prototype[".jspb.test.IndirectExtension.repeatedSimple"] = $util.emptyArray;
+
+            /**
+             * HasExtensions .jspb.test.simple1.
+             * @member {jspb.test.ISimple1|null|undefined} .jspb.test.simple1
+             * @memberof jspb.test.HasExtensions
+             * @instance
+             */
+            HasExtensions.prototype[".jspb.test.simple1"] = null;
+
+            /**
+             * Creates a new HasExtensions instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.HasExtensions
+             * @static
+             * @param {jspb.test.IHasExtensions=} [properties] Properties to set
+             * @returns {jspb.test.HasExtensions} HasExtensions instance
+             */
+            HasExtensions.create = function create(properties) {
+                return new HasExtensions(properties);
+            };
+
+            /**
+             * Encodes the specified HasExtensions message. Does not implicitly {@link jspb.test.HasExtensions.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.HasExtensions
+             * @static
+             * @param {jspb.test.IHasExtensions} message HasExtensions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            HasExtensions.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.str1 != null && Object.hasOwnProperty.call(message, "str1"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.str1);
+                if (message.str2 != null && Object.hasOwnProperty.call(message, "str2"))
+                    writer.uint32(/* id 2, wireType 2 =*/18).string(message.str2);
+                if (message.str3 != null && Object.hasOwnProperty.call(message, "str3"))
+                    writer.uint32(/* id 3, wireType 2 =*/26).string(message.str3);
+                if (message[".jspb.test.IsExtension.extField"] != null && Object.hasOwnProperty.call(message, ".jspb.test.IsExtension.extField"))
+                    $root.jspb.test.IsExtension.encode(message[".jspb.test.IsExtension.extField"], writer.uint32(/* id 100, wireType 2 =*/802).fork()).ldelim();
+                if (message[".jspb.test.IndirectExtension.simple"] != null && Object.hasOwnProperty.call(message, ".jspb.test.IndirectExtension.simple"))
+                    $root.jspb.test.Simple1.encode(message[".jspb.test.IndirectExtension.simple"], writer.uint32(/* id 101, wireType 2 =*/810).fork()).ldelim();
+                if (message[".jspb.test.IndirectExtension.str"] != null && Object.hasOwnProperty.call(message, ".jspb.test.IndirectExtension.str"))
+                    writer.uint32(/* id 102, wireType 2 =*/818).string(message[".jspb.test.IndirectExtension.str"]);
+                if (message[".jspb.test.IndirectExtension.repeatedStr"] != null && message[".jspb.test.IndirectExtension.repeatedStr"].length)
+                    for (var i = 0; i < message[".jspb.test.IndirectExtension.repeatedStr"].length; ++i)
+                        writer.uint32(/* id 103, wireType 2 =*/826).string(message[".jspb.test.IndirectExtension.repeatedStr"][i]);
+                if (message[".jspb.test.IndirectExtension.repeatedSimple"] != null && message[".jspb.test.IndirectExtension.repeatedSimple"].length)
+                    for (var i = 0; i < message[".jspb.test.IndirectExtension.repeatedSimple"].length; ++i)
+                        $root.jspb.test.Simple1.encode(message[".jspb.test.IndirectExtension.repeatedSimple"][i], writer.uint32(/* id 104, wireType 2 =*/834).fork()).ldelim();
+                if (message[".jspb.test.simple1"] != null && Object.hasOwnProperty.call(message, ".jspb.test.simple1"))
+                    $root.jspb.test.Simple1.encode(message[".jspb.test.simple1"], writer.uint32(/* id 105, wireType 2 =*/842).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified HasExtensions message, length delimited. Does not implicitly {@link jspb.test.HasExtensions.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.HasExtensions
+             * @static
+             * @param {jspb.test.IHasExtensions} message HasExtensions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            HasExtensions.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a HasExtensions message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.HasExtensions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.HasExtensions} HasExtensions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            HasExtensions.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.HasExtensions();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.str1 = reader.string();
+                        break;
+                    case 2:
+                        message.str2 = reader.string();
+                        break;
+                    case 3:
+                        message.str3 = reader.string();
+                        break;
+                    case 100:
+                        message[".jspb.test.IsExtension.extField"] = $root.jspb.test.IsExtension.decode(reader, reader.uint32());
+                        break;
+                    case 101:
+                        message[".jspb.test.IndirectExtension.simple"] = $root.jspb.test.Simple1.decode(reader, reader.uint32());
+                        break;
+                    case 102:
+                        message[".jspb.test.IndirectExtension.str"] = reader.string();
+                        break;
+                    case 103:
+                        if (!(message[".jspb.test.IndirectExtension.repeatedStr"] && message[".jspb.test.IndirectExtension.repeatedStr"].length))
+                            message[".jspb.test.IndirectExtension.repeatedStr"] = [];
+                        message[".jspb.test.IndirectExtension.repeatedStr"].push(reader.string());
+                        break;
+                    case 104:
+                        if (!(message[".jspb.test.IndirectExtension.repeatedSimple"] && message[".jspb.test.IndirectExtension.repeatedSimple"].length))
+                            message[".jspb.test.IndirectExtension.repeatedSimple"] = [];
+                        message[".jspb.test.IndirectExtension.repeatedSimple"].push($root.jspb.test.Simple1.decode(reader, reader.uint32()));
+                        break;
+                    case 105:
+                        message[".jspb.test.simple1"] = $root.jspb.test.Simple1.decode(reader, reader.uint32());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a HasExtensions message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.HasExtensions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.HasExtensions} HasExtensions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            HasExtensions.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a HasExtensions message.
+             * @function verify
+             * @memberof jspb.test.HasExtensions
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            HasExtensions.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.str1 != null && message.hasOwnProperty("str1"))
+                    if (!$util.isString(message.str1))
+                        return "str1: string expected";
+                if (message.str2 != null && message.hasOwnProperty("str2"))
+                    if (!$util.isString(message.str2))
+                        return "str2: string expected";
+                if (message.str3 != null && message.hasOwnProperty("str3"))
+                    if (!$util.isString(message.str3))
+                        return "str3: string expected";
+                if (message[".jspb.test.IsExtension.extField"] != null && message.hasOwnProperty(".jspb.test.IsExtension.extField")) {
+                    var error = $root.jspb.test.IsExtension.verify(message[".jspb.test.IsExtension.extField"]);
+                    if (error)
+                        return ".jspb.test.IsExtension.extField." + error;
+                }
+                if (message[".jspb.test.IndirectExtension.simple"] != null && message.hasOwnProperty(".jspb.test.IndirectExtension.simple")) {
+                    var error = $root.jspb.test.Simple1.verify(message[".jspb.test.IndirectExtension.simple"]);
+                    if (error)
+                        return ".jspb.test.IndirectExtension.simple." + error;
+                }
+                if (message[".jspb.test.IndirectExtension.str"] != null && message.hasOwnProperty(".jspb.test.IndirectExtension.str"))
+                    if (!$util.isString(message[".jspb.test.IndirectExtension.str"]))
+                        return ".jspb.test.IndirectExtension.str: string expected";
+                if (message[".jspb.test.IndirectExtension.repeatedStr"] != null && message.hasOwnProperty(".jspb.test.IndirectExtension.repeatedStr")) {
+                    if (!Array.isArray(message[".jspb.test.IndirectExtension.repeatedStr"]))
+                        return ".jspb.test.IndirectExtension.repeatedStr: array expected";
+                    for (var i = 0; i < message[".jspb.test.IndirectExtension.repeatedStr"].length; ++i)
+                        if (!$util.isString(message[".jspb.test.IndirectExtension.repeatedStr"][i]))
+                            return ".jspb.test.IndirectExtension.repeatedStr: string[] expected";
+                }
+                if (message[".jspb.test.IndirectExtension.repeatedSimple"] != null && message.hasOwnProperty(".jspb.test.IndirectExtension.repeatedSimple")) {
+                    if (!Array.isArray(message[".jspb.test.IndirectExtension.repeatedSimple"]))
+                        return ".jspb.test.IndirectExtension.repeatedSimple: array expected";
+                    for (var i = 0; i < message[".jspb.test.IndirectExtension.repeatedSimple"].length; ++i) {
+                        var error = $root.jspb.test.Simple1.verify(message[".jspb.test.IndirectExtension.repeatedSimple"][i]);
+                        if (error)
+                            return ".jspb.test.IndirectExtension.repeatedSimple." + error;
+                    }
+                }
+                if (message[".jspb.test.simple1"] != null && message.hasOwnProperty(".jspb.test.simple1")) {
+                    var error = $root.jspb.test.Simple1.verify(message[".jspb.test.simple1"]);
+                    if (error)
+                        return ".jspb.test.simple1." + error;
+                }
+                return null;
+            };
+
+            /**
+             * Creates a HasExtensions message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.HasExtensions
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.HasExtensions} HasExtensions
+             */
+            HasExtensions.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.HasExtensions)
+                    return object;
+                var message = new $root.jspb.test.HasExtensions();
+                if (object.str1 != null)
+                    message.str1 = String(object.str1);
+                if (object.str2 != null)
+                    message.str2 = String(object.str2);
+                if (object.str3 != null)
+                    message.str3 = String(object.str3);
+                if (object[".jspb.test.IsExtension.extField"] != null) {
+                    if (typeof object[".jspb.test.IsExtension.extField"] !== "object")
+                        throw TypeError(".jspb.test.HasExtensions..jspb.test.IsExtension.extField: object expected");
+                    message[".jspb.test.IsExtension.extField"] = $root.jspb.test.IsExtension.fromObject(object[".jspb.test.IsExtension.extField"]);
+                }
+                if (object[".jspb.test.IndirectExtension.simple"] != null) {
+                    if (typeof object[".jspb.test.IndirectExtension.simple"] !== "object")
+                        throw TypeError(".jspb.test.HasExtensions..jspb.test.IndirectExtension.simple: object expected");
+                    message[".jspb.test.IndirectExtension.simple"] = $root.jspb.test.Simple1.fromObject(object[".jspb.test.IndirectExtension.simple"]);
+                }
+                if (object[".jspb.test.IndirectExtension.str"] != null)
+                    message[".jspb.test.IndirectExtension.str"] = String(object[".jspb.test.IndirectExtension.str"]);
+                if (object[".jspb.test.IndirectExtension.repeatedStr"]) {
+                    if (!Array.isArray(object[".jspb.test.IndirectExtension.repeatedStr"]))
+                        throw TypeError(".jspb.test.HasExtensions..jspb.test.IndirectExtension.repeatedStr: array expected");
+                    message[".jspb.test.IndirectExtension.repeatedStr"] = [];
+                    for (var i = 0; i < object[".jspb.test.IndirectExtension.repeatedStr"].length; ++i)
+                        message[".jspb.test.IndirectExtension.repeatedStr"][i] = String(object[".jspb.test.IndirectExtension.repeatedStr"][i]);
+                }
+                if (object[".jspb.test.IndirectExtension.repeatedSimple"]) {
+                    if (!Array.isArray(object[".jspb.test.IndirectExtension.repeatedSimple"]))
+                        throw TypeError(".jspb.test.HasExtensions..jspb.test.IndirectExtension.repeatedSimple: array expected");
+                    message[".jspb.test.IndirectExtension.repeatedSimple"] = [];
+                    for (var i = 0; i < object[".jspb.test.IndirectExtension.repeatedSimple"].length; ++i) {
+                        if (typeof object[".jspb.test.IndirectExtension.repeatedSimple"][i] !== "object")
+                            throw TypeError(".jspb.test.HasExtensions..jspb.test.IndirectExtension.repeatedSimple: object expected");
+                        message[".jspb.test.IndirectExtension.repeatedSimple"][i] = $root.jspb.test.Simple1.fromObject(object[".jspb.test.IndirectExtension.repeatedSimple"][i]);
+                    }
+                }
+                if (object[".jspb.test.simple1"] != null) {
+                    if (typeof object[".jspb.test.simple1"] !== "object")
+                        throw TypeError(".jspb.test.HasExtensions..jspb.test.simple1: object expected");
+                    message[".jspb.test.simple1"] = $root.jspb.test.Simple1.fromObject(object[".jspb.test.simple1"]);
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a HasExtensions message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.HasExtensions
+             * @static
+             * @param {jspb.test.HasExtensions} message HasExtensions
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            HasExtensions.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults) {
+                    object[".jspb.test.IndirectExtension.repeatedStr"] = [];
+                    object[".jspb.test.IndirectExtension.repeatedSimple"] = [];
+                }
+                if (options.defaults) {
+                    object.str1 = "";
+                    object.str2 = "";
+                    object.str3 = "";
+                    object[".jspb.test.IsExtension.extField"] = null;
+                    object[".jspb.test.IndirectExtension.simple"] = null;
+                    object[".jspb.test.IndirectExtension.str"] = "";
+                    object[".jspb.test.simple1"] = null;
+                }
+                if (message.str1 != null && message.hasOwnProperty("str1"))
+                    object.str1 = message.str1;
+                if (message.str2 != null && message.hasOwnProperty("str2"))
+                    object.str2 = message.str2;
+                if (message.str3 != null && message.hasOwnProperty("str3"))
+                    object.str3 = message.str3;
+                if (message[".jspb.test.IsExtension.extField"] != null && message.hasOwnProperty(".jspb.test.IsExtension.extField"))
+                    object[".jspb.test.IsExtension.extField"] = $root.jspb.test.IsExtension.toObject(message[".jspb.test.IsExtension.extField"], options);
+                if (message[".jspb.test.IndirectExtension.simple"] != null && message.hasOwnProperty(".jspb.test.IndirectExtension.simple"))
+                    object[".jspb.test.IndirectExtension.simple"] = $root.jspb.test.Simple1.toObject(message[".jspb.test.IndirectExtension.simple"], options);
+                if (message[".jspb.test.IndirectExtension.str"] != null && message.hasOwnProperty(".jspb.test.IndirectExtension.str"))
+                    object[".jspb.test.IndirectExtension.str"] = message[".jspb.test.IndirectExtension.str"];
+                if (message[".jspb.test.IndirectExtension.repeatedStr"] && message[".jspb.test.IndirectExtension.repeatedStr"].length) {
+                    object[".jspb.test.IndirectExtension.repeatedStr"] = [];
+                    for (var j = 0; j < message[".jspb.test.IndirectExtension.repeatedStr"].length; ++j)
+                        object[".jspb.test.IndirectExtension.repeatedStr"][j] = message[".jspb.test.IndirectExtension.repeatedStr"][j];
+                }
+                if (message[".jspb.test.IndirectExtension.repeatedSimple"] && message[".jspb.test.IndirectExtension.repeatedSimple"].length) {
+                    object[".jspb.test.IndirectExtension.repeatedSimple"] = [];
+                    for (var j = 0; j < message[".jspb.test.IndirectExtension.repeatedSimple"].length; ++j)
+                        object[".jspb.test.IndirectExtension.repeatedSimple"][j] = $root.jspb.test.Simple1.toObject(message[".jspb.test.IndirectExtension.repeatedSimple"][j], options);
+                }
+                if (message[".jspb.test.simple1"] != null && message.hasOwnProperty(".jspb.test.simple1"))
+                    object[".jspb.test.simple1"] = $root.jspb.test.Simple1.toObject(message[".jspb.test.simple1"], options);
+                return object;
+            };
+
+            /**
+             * Converts this HasExtensions to JSON.
+             * @function toJSON
+             * @memberof jspb.test.HasExtensions
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            HasExtensions.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for HasExtensions
+             * @function getTypeUrl
+             * @memberof jspb.test.HasExtensions
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            HasExtensions.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.HasExtensions";
+            };
+
+            return HasExtensions;
+        })();
+
+        test.Complex = (function() {
+
+            /**
+             * Properties of a Complex.
+             * @memberof jspb.test
+             * @interface IComplex
+             * @property {string} aString Complex aString
+             * @property {boolean} anOutOfOrderBool Complex anOutOfOrderBool
+             * @property {jspb.test.Complex.INested|null} [aNestedMessage] Complex aNestedMessage
+             * @property {Array.<jspb.test.Complex.INested>|null} [aRepeatedMessage] Complex aRepeatedMessage
+             * @property {Array.<string>|null} [aRepeatedString] Complex aRepeatedString
+             */
+
+            /**
+             * Constructs a new Complex.
+             * @memberof jspb.test
+             * @classdesc Represents a Complex.
+             * @implements IComplex
+             * @constructor
+             * @param {jspb.test.IComplex=} [properties] Properties to set
+             */
+            function Complex(properties) {
+                this.aRepeatedMessage = [];
+                this.aRepeatedString = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * Complex aString.
+             * @member {string} aString
+             * @memberof jspb.test.Complex
+             * @instance
+             */
+            Complex.prototype.aString = "";
+
+            /**
+             * Complex anOutOfOrderBool.
+             * @member {boolean} anOutOfOrderBool
+             * @memberof jspb.test.Complex
+             * @instance
+             */
+            Complex.prototype.anOutOfOrderBool = false;
+
+            /**
+             * Complex aNestedMessage.
+             * @member {jspb.test.Complex.INested|null|undefined} aNestedMessage
+             * @memberof jspb.test.Complex
+             * @instance
+             */
+            Complex.prototype.aNestedMessage = null;
+
+            /**
+             * Complex aRepeatedMessage.
+             * @member {Array.<jspb.test.Complex.INested>} aRepeatedMessage
+             * @memberof jspb.test.Complex
+             * @instance
+             */
+            Complex.prototype.aRepeatedMessage = $util.emptyArray;
+
+            /**
+             * Complex aRepeatedString.
+             * @member {Array.<string>} aRepeatedString
+             * @memberof jspb.test.Complex
+             * @instance
+             */
+            Complex.prototype.aRepeatedString = $util.emptyArray;
+
+            /**
+             * Creates a new Complex instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.Complex
+             * @static
+             * @param {jspb.test.IComplex=} [properties] Properties to set
+             * @returns {jspb.test.Complex} Complex instance
+             */
+            Complex.create = function create(properties) {
+                return new Complex(properties);
+            };
+
+            /**
+             * Encodes the specified Complex message. Does not implicitly {@link jspb.test.Complex.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.Complex
+             * @static
+             * @param {jspb.test.IComplex} message Complex message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Complex.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                writer.uint32(/* id 1, wireType 2 =*/10).string(message.aString);
+                if (message.aNestedMessage != null && Object.hasOwnProperty.call(message, "aNestedMessage"))
+                    $root.jspb.test.Complex.Nested.encode(message.aNestedMessage, writer.uint32(/* id 4, wireType 2 =*/34).fork()).ldelim();
+                if (message.aRepeatedMessage != null && message.aRepeatedMessage.length)
+                    for (var i = 0; i < message.aRepeatedMessage.length; ++i)
+                        $root.jspb.test.Complex.Nested.encode(message.aRepeatedMessage[i], writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim();
+                if (message.aRepeatedString != null && message.aRepeatedString.length)
+                    for (var i = 0; i < message.aRepeatedString.length; ++i)
+                        writer.uint32(/* id 7, wireType 2 =*/58).string(message.aRepeatedString[i]);
+                writer.uint32(/* id 9, wireType 0 =*/72).bool(message.anOutOfOrderBool);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified Complex message, length delimited. Does not implicitly {@link jspb.test.Complex.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.Complex
+             * @static
+             * @param {jspb.test.IComplex} message Complex message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Complex.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a Complex message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.Complex
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.Complex} Complex
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Complex.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.Complex();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.aString = reader.string();
+                        break;
+                    case 9:
+                        message.anOutOfOrderBool = reader.bool();
+                        break;
+                    case 4:
+                        message.aNestedMessage = $root.jspb.test.Complex.Nested.decode(reader, reader.uint32());
+                        break;
+                    case 5:
+                        if (!(message.aRepeatedMessage && message.aRepeatedMessage.length))
+                            message.aRepeatedMessage = [];
+                        message.aRepeatedMessage.push($root.jspb.test.Complex.Nested.decode(reader, reader.uint32()));
+                        break;
+                    case 7:
+                        if (!(message.aRepeatedString && message.aRepeatedString.length))
+                            message.aRepeatedString = [];
+                        message.aRepeatedString.push(reader.string());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("aString"))
+                    throw $util.ProtocolError("missing required 'aString'", { instance: message });
+                if (!message.hasOwnProperty("anOutOfOrderBool"))
+                    throw $util.ProtocolError("missing required 'anOutOfOrderBool'", { instance: message });
+                return message;
+            };
+
+            /**
+             * Decodes a Complex message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.Complex
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.Complex} Complex
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Complex.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a Complex message.
+             * @function verify
+             * @memberof jspb.test.Complex
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            Complex.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (!$util.isString(message.aString))
+                    return "aString: string expected";
+                if (typeof message.anOutOfOrderBool !== "boolean")
+                    return "anOutOfOrderBool: boolean expected";
+                if (message.aNestedMessage != null && message.hasOwnProperty("aNestedMessage")) {
+                    var error = $root.jspb.test.Complex.Nested.verify(message.aNestedMessage);
+                    if (error)
+                        return "aNestedMessage." + error;
+                }
+                if (message.aRepeatedMessage != null && message.hasOwnProperty("aRepeatedMessage")) {
+                    if (!Array.isArray(message.aRepeatedMessage))
+                        return "aRepeatedMessage: array expected";
+                    for (var i = 0; i < message.aRepeatedMessage.length; ++i) {
+                        var error = $root.jspb.test.Complex.Nested.verify(message.aRepeatedMessage[i]);
+                        if (error)
+                            return "aRepeatedMessage." + error;
+                    }
+                }
+                if (message.aRepeatedString != null && message.hasOwnProperty("aRepeatedString")) {
+                    if (!Array.isArray(message.aRepeatedString))
+                        return "aRepeatedString: array expected";
+                    for (var i = 0; i < message.aRepeatedString.length; ++i)
+                        if (!$util.isString(message.aRepeatedString[i]))
+                            return "aRepeatedString: string[] expected";
+                }
+                return null;
+            };
+
+            /**
+             * Creates a Complex message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.Complex
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.Complex} Complex
+             */
+            Complex.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.Complex)
+                    return object;
+                var message = new $root.jspb.test.Complex();
+                if (object.aString != null)
+                    message.aString = String(object.aString);
+                if (object.anOutOfOrderBool != null)
+                    message.anOutOfOrderBool = Boolean(object.anOutOfOrderBool);
+                if (object.aNestedMessage != null) {
+                    if (typeof object.aNestedMessage !== "object")
+                        throw TypeError(".jspb.test.Complex.aNestedMessage: object expected");
+                    message.aNestedMessage = $root.jspb.test.Complex.Nested.fromObject(object.aNestedMessage);
+                }
+                if (object.aRepeatedMessage) {
+                    if (!Array.isArray(object.aRepeatedMessage))
+                        throw TypeError(".jspb.test.Complex.aRepeatedMessage: array expected");
+                    message.aRepeatedMessage = [];
+                    for (var i = 0; i < object.aRepeatedMessage.length; ++i) {
+                        if (typeof object.aRepeatedMessage[i] !== "object")
+                            throw TypeError(".jspb.test.Complex.aRepeatedMessage: object expected");
+                        message.aRepeatedMessage[i] = $root.jspb.test.Complex.Nested.fromObject(object.aRepeatedMessage[i]);
+                    }
+                }
+                if (object.aRepeatedString) {
+                    if (!Array.isArray(object.aRepeatedString))
+                        throw TypeError(".jspb.test.Complex.aRepeatedString: array expected");
+                    message.aRepeatedString = [];
+                    for (var i = 0; i < object.aRepeatedString.length; ++i)
+                        message.aRepeatedString[i] = String(object.aRepeatedString[i]);
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a Complex message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.Complex
+             * @static
+             * @param {jspb.test.Complex} message Complex
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            Complex.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults) {
+                    object.aRepeatedMessage = [];
+                    object.aRepeatedString = [];
+                }
+                if (options.defaults) {
+                    object.aString = "";
+                    object.aNestedMessage = null;
+                    object.anOutOfOrderBool = false;
+                }
+                if (message.aString != null && message.hasOwnProperty("aString"))
+                    object.aString = message.aString;
+                if (message.aNestedMessage != null && message.hasOwnProperty("aNestedMessage"))
+                    object.aNestedMessage = $root.jspb.test.Complex.Nested.toObject(message.aNestedMessage, options);
+                if (message.aRepeatedMessage && message.aRepeatedMessage.length) {
+                    object.aRepeatedMessage = [];
+                    for (var j = 0; j < message.aRepeatedMessage.length; ++j)
+                        object.aRepeatedMessage[j] = $root.jspb.test.Complex.Nested.toObject(message.aRepeatedMessage[j], options);
+                }
+                if (message.aRepeatedString && message.aRepeatedString.length) {
+                    object.aRepeatedString = [];
+                    for (var j = 0; j < message.aRepeatedString.length; ++j)
+                        object.aRepeatedString[j] = message.aRepeatedString[j];
+                }
+                if (message.anOutOfOrderBool != null && message.hasOwnProperty("anOutOfOrderBool"))
+                    object.anOutOfOrderBool = message.anOutOfOrderBool;
+                return object;
+            };
+
+            /**
+             * Converts this Complex to JSON.
+             * @function toJSON
+             * @memberof jspb.test.Complex
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            Complex.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for Complex
+             * @function getTypeUrl
+             * @memberof jspb.test.Complex
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            Complex.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.Complex";
+            };
+
+            Complex.Nested = (function() {
+
+                /**
+                 * Properties of a Nested.
+                 * @memberof jspb.test.Complex
+                 * @interface INested
+                 * @property {number} anInt Nested anInt
+                 */
+
+                /**
+                 * Constructs a new Nested.
+                 * @memberof jspb.test.Complex
+                 * @classdesc Represents a Nested.
+                 * @implements INested
+                 * @constructor
+                 * @param {jspb.test.Complex.INested=} [properties] Properties to set
+                 */
+                function Nested(properties) {
+                    if (properties)
+                        for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                            if (properties[keys[i]] != null)
+                                this[keys[i]] = properties[keys[i]];
+                }
+
+                /**
+                 * Nested anInt.
+                 * @member {number} anInt
+                 * @memberof jspb.test.Complex.Nested
+                 * @instance
+                 */
+                Nested.prototype.anInt = 0;
+
+                /**
+                 * Creates a new Nested instance using the specified properties.
+                 * @function create
+                 * @memberof jspb.test.Complex.Nested
+                 * @static
+                 * @param {jspb.test.Complex.INested=} [properties] Properties to set
+                 * @returns {jspb.test.Complex.Nested} Nested instance
+                 */
+                Nested.create = function create(properties) {
+                    return new Nested(properties);
+                };
+
+                /**
+                 * Encodes the specified Nested message. Does not implicitly {@link jspb.test.Complex.Nested.verify|verify} messages.
+                 * @function encode
+                 * @memberof jspb.test.Complex.Nested
+                 * @static
+                 * @param {jspb.test.Complex.INested} message Nested message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                Nested.encode = function encode(message, writer) {
+                    if (!writer)
+                        writer = $Writer.create();
+                    writer.uint32(/* id 2, wireType 0 =*/16).int32(message.anInt);
+                    return writer;
+                };
+
+                /**
+                 * Encodes the specified Nested message, length delimited. Does not implicitly {@link jspb.test.Complex.Nested.verify|verify} messages.
+                 * @function encodeDelimited
+                 * @memberof jspb.test.Complex.Nested
+                 * @static
+                 * @param {jspb.test.Complex.INested} message Nested message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                Nested.encodeDelimited = function encodeDelimited(message, writer) {
+                    return this.encode(message, writer).ldelim();
+                };
+
+                /**
+                 * Decodes a Nested message from the specified reader or buffer.
+                 * @function decode
+                 * @memberof jspb.test.Complex.Nested
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @param {number} [length] Message length if known beforehand
+                 * @returns {jspb.test.Complex.Nested} Nested
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                Nested.decode = function decode(reader, length) {
+                    if (!(reader instanceof $Reader))
+                        reader = $Reader.create(reader);
+                    var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.Complex.Nested();
+                    while (reader.pos < end) {
+                        var tag = reader.uint32();
+                        switch (tag >>> 3) {
+                        case 2:
+                            message.anInt = reader.int32();
+                            break;
+                        default:
+                            reader.skipType(tag & 7);
+                            break;
+                        }
+                    }
+                    if (!message.hasOwnProperty("anInt"))
+                        throw $util.ProtocolError("missing required 'anInt'", { instance: message });
+                    return message;
+                };
+
+                /**
+                 * Decodes a Nested message from the specified reader or buffer, length delimited.
+                 * @function decodeDelimited
+                 * @memberof jspb.test.Complex.Nested
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @returns {jspb.test.Complex.Nested} Nested
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                Nested.decodeDelimited = function decodeDelimited(reader) {
+                    if (!(reader instanceof $Reader))
+                        reader = new $Reader(reader);
+                    return this.decode(reader, reader.uint32());
+                };
+
+                /**
+                 * Verifies a Nested message.
+                 * @function verify
+                 * @memberof jspb.test.Complex.Nested
+                 * @static
+                 * @param {Object.<string,*>} message Plain object to verify
+                 * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                 */
+                Nested.verify = function verify(message) {
+                    if (typeof message !== "object" || message === null)
+                        return "object expected";
+                    if (!$util.isInteger(message.anInt))
+                        return "anInt: integer expected";
+                    return null;
+                };
+
+                /**
+                 * Creates a Nested message from a plain object. Also converts values to their respective internal types.
+                 * @function fromObject
+                 * @memberof jspb.test.Complex.Nested
+                 * @static
+                 * @param {Object.<string,*>} object Plain object
+                 * @returns {jspb.test.Complex.Nested} Nested
+                 */
+                Nested.fromObject = function fromObject(object) {
+                    if (object instanceof $root.jspb.test.Complex.Nested)
+                        return object;
+                    var message = new $root.jspb.test.Complex.Nested();
+                    if (object.anInt != null)
+                        message.anInt = object.anInt | 0;
+                    return message;
+                };
+
+                /**
+                 * Creates a plain object from a Nested message. Also converts values to other types if specified.
+                 * @function toObject
+                 * @memberof jspb.test.Complex.Nested
+                 * @static
+                 * @param {jspb.test.Complex.Nested} message Nested
+                 * @param {$protobuf.IConversionOptions} [options] Conversion options
+                 * @returns {Object.<string,*>} Plain object
+                 */
+                Nested.toObject = function toObject(message, options) {
+                    if (!options)
+                        options = {};
+                    var object = {};
+                    if (options.defaults)
+                        object.anInt = 0;
+                    if (message.anInt != null && message.hasOwnProperty("anInt"))
+                        object.anInt = message.anInt;
+                    return object;
+                };
+
+                /**
+                 * Converts this Nested to JSON.
+                 * @function toJSON
+                 * @memberof jspb.test.Complex.Nested
+                 * @instance
+                 * @returns {Object.<string,*>} JSON object
+                 */
+                Nested.prototype.toJSON = function toJSON() {
+                    return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                };
+
+                /**
+                 * Gets the default type url for Nested
+                 * @function getTypeUrl
+                 * @memberof jspb.test.Complex.Nested
+                 * @static
+                 * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                 * @returns {string} The default type url
+                 */
+                Nested.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                    if (typeUrlPrefix === undefined) {
+                        typeUrlPrefix = "type.googleapis.com";
+                    }
+                    return typeUrlPrefix + "/jspb.test.Complex.Nested";
+                };
+
+                return Nested;
+            })();
+
+            return Complex;
+        })();
+
+        test.OuterMessage = (function() {
+
+            /**
+             * Properties of an OuterMessage.
+             * @memberof jspb.test
+             * @interface IOuterMessage
+             */
+
+            /**
+             * Constructs a new OuterMessage.
+             * @memberof jspb.test
+             * @classdesc Represents an OuterMessage.
+             * @implements IOuterMessage
+             * @constructor
+             * @param {jspb.test.IOuterMessage=} [properties] Properties to set
+             */
+            function OuterMessage(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * Creates a new OuterMessage instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.OuterMessage
+             * @static
+             * @param {jspb.test.IOuterMessage=} [properties] Properties to set
+             * @returns {jspb.test.OuterMessage} OuterMessage instance
+             */
+            OuterMessage.create = function create(properties) {
+                return new OuterMessage(properties);
+            };
+
+            /**
+             * Encodes the specified OuterMessage message. Does not implicitly {@link jspb.test.OuterMessage.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.OuterMessage
+             * @static
+             * @param {jspb.test.IOuterMessage} message OuterMessage message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            OuterMessage.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified OuterMessage message, length delimited. Does not implicitly {@link jspb.test.OuterMessage.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.OuterMessage
+             * @static
+             * @param {jspb.test.IOuterMessage} message OuterMessage message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            OuterMessage.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes an OuterMessage message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.OuterMessage
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.OuterMessage} OuterMessage
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            OuterMessage.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.OuterMessage();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes an OuterMessage message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.OuterMessage
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.OuterMessage} OuterMessage
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            OuterMessage.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies an OuterMessage message.
+             * @function verify
+             * @memberof jspb.test.OuterMessage
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            OuterMessage.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                return null;
+            };
+
+            /**
+             * Creates an OuterMessage message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.OuterMessage
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.OuterMessage} OuterMessage
+             */
+            OuterMessage.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.OuterMessage)
+                    return object;
+                return new $root.jspb.test.OuterMessage();
+            };
+
+            /**
+             * Creates a plain object from an OuterMessage message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.OuterMessage
+             * @static
+             * @param {jspb.test.OuterMessage} message OuterMessage
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            OuterMessage.toObject = function toObject() {
+                return {};
+            };
+
+            /**
+             * Converts this OuterMessage to JSON.
+             * @function toJSON
+             * @memberof jspb.test.OuterMessage
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            OuterMessage.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for OuterMessage
+             * @function getTypeUrl
+             * @memberof jspb.test.OuterMessage
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            OuterMessage.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.OuterMessage";
+            };
+
+            OuterMessage.Complex = (function() {
+
+                /**
+                 * Properties of a Complex.
+                 * @memberof jspb.test.OuterMessage
+                 * @interface IComplex
+                 * @property {number|null} [innerComplexField] Complex innerComplexField
+                 */
+
+                /**
+                 * Constructs a new Complex.
+                 * @memberof jspb.test.OuterMessage
+                 * @classdesc Represents a Complex.
+                 * @implements IComplex
+                 * @constructor
+                 * @param {jspb.test.OuterMessage.IComplex=} [properties] Properties to set
+                 */
+                function Complex(properties) {
+                    if (properties)
+                        for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                            if (properties[keys[i]] != null)
+                                this[keys[i]] = properties[keys[i]];
+                }
+
+                /**
+                 * Complex innerComplexField.
+                 * @member {number} innerComplexField
+                 * @memberof jspb.test.OuterMessage.Complex
+                 * @instance
+                 */
+                Complex.prototype.innerComplexField = 0;
+
+                /**
+                 * Creates a new Complex instance using the specified properties.
+                 * @function create
+                 * @memberof jspb.test.OuterMessage.Complex
+                 * @static
+                 * @param {jspb.test.OuterMessage.IComplex=} [properties] Properties to set
+                 * @returns {jspb.test.OuterMessage.Complex} Complex instance
+                 */
+                Complex.create = function create(properties) {
+                    return new Complex(properties);
+                };
+
+                /**
+                 * Encodes the specified Complex message. Does not implicitly {@link jspb.test.OuterMessage.Complex.verify|verify} messages.
+                 * @function encode
+                 * @memberof jspb.test.OuterMessage.Complex
+                 * @static
+                 * @param {jspb.test.OuterMessage.IComplex} message Complex message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                Complex.encode = function encode(message, writer) {
+                    if (!writer)
+                        writer = $Writer.create();
+                    if (message.innerComplexField != null && Object.hasOwnProperty.call(message, "innerComplexField"))
+                        writer.uint32(/* id 1, wireType 0 =*/8).int32(message.innerComplexField);
+                    return writer;
+                };
+
+                /**
+                 * Encodes the specified Complex message, length delimited. Does not implicitly {@link jspb.test.OuterMessage.Complex.verify|verify} messages.
+                 * @function encodeDelimited
+                 * @memberof jspb.test.OuterMessage.Complex
+                 * @static
+                 * @param {jspb.test.OuterMessage.IComplex} message Complex message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                Complex.encodeDelimited = function encodeDelimited(message, writer) {
+                    return this.encode(message, writer).ldelim();
+                };
+
+                /**
+                 * Decodes a Complex message from the specified reader or buffer.
+                 * @function decode
+                 * @memberof jspb.test.OuterMessage.Complex
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @param {number} [length] Message length if known beforehand
+                 * @returns {jspb.test.OuterMessage.Complex} Complex
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                Complex.decode = function decode(reader, length) {
+                    if (!(reader instanceof $Reader))
+                        reader = $Reader.create(reader);
+                    var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.OuterMessage.Complex();
+                    while (reader.pos < end) {
+                        var tag = reader.uint32();
+                        switch (tag >>> 3) {
+                        case 1:
+                            message.innerComplexField = reader.int32();
+                            break;
+                        default:
+                            reader.skipType(tag & 7);
+                            break;
+                        }
+                    }
+                    return message;
+                };
+
+                /**
+                 * Decodes a Complex message from the specified reader or buffer, length delimited.
+                 * @function decodeDelimited
+                 * @memberof jspb.test.OuterMessage.Complex
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @returns {jspb.test.OuterMessage.Complex} Complex
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                Complex.decodeDelimited = function decodeDelimited(reader) {
+                    if (!(reader instanceof $Reader))
+                        reader = new $Reader(reader);
+                    return this.decode(reader, reader.uint32());
+                };
+
+                /**
+                 * Verifies a Complex message.
+                 * @function verify
+                 * @memberof jspb.test.OuterMessage.Complex
+                 * @static
+                 * @param {Object.<string,*>} message Plain object to verify
+                 * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                 */
+                Complex.verify = function verify(message) {
+                    if (typeof message !== "object" || message === null)
+                        return "object expected";
+                    if (message.innerComplexField != null && message.hasOwnProperty("innerComplexField"))
+                        if (!$util.isInteger(message.innerComplexField))
+                            return "innerComplexField: integer expected";
+                    return null;
+                };
+
+                /**
+                 * Creates a Complex message from a plain object. Also converts values to their respective internal types.
+                 * @function fromObject
+                 * @memberof jspb.test.OuterMessage.Complex
+                 * @static
+                 * @param {Object.<string,*>} object Plain object
+                 * @returns {jspb.test.OuterMessage.Complex} Complex
+                 */
+                Complex.fromObject = function fromObject(object) {
+                    if (object instanceof $root.jspb.test.OuterMessage.Complex)
+                        return object;
+                    var message = new $root.jspb.test.OuterMessage.Complex();
+                    if (object.innerComplexField != null)
+                        message.innerComplexField = object.innerComplexField | 0;
+                    return message;
+                };
+
+                /**
+                 * Creates a plain object from a Complex message. Also converts values to other types if specified.
+                 * @function toObject
+                 * @memberof jspb.test.OuterMessage.Complex
+                 * @static
+                 * @param {jspb.test.OuterMessage.Complex} message Complex
+                 * @param {$protobuf.IConversionOptions} [options] Conversion options
+                 * @returns {Object.<string,*>} Plain object
+                 */
+                Complex.toObject = function toObject(message, options) {
+                    if (!options)
+                        options = {};
+                    var object = {};
+                    if (options.defaults)
+                        object.innerComplexField = 0;
+                    if (message.innerComplexField != null && message.hasOwnProperty("innerComplexField"))
+                        object.innerComplexField = message.innerComplexField;
+                    return object;
+                };
+
+                /**
+                 * Converts this Complex to JSON.
+                 * @function toJSON
+                 * @memberof jspb.test.OuterMessage.Complex
+                 * @instance
+                 * @returns {Object.<string,*>} JSON object
+                 */
+                Complex.prototype.toJSON = function toJSON() {
+                    return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                };
+
+                /**
+                 * Gets the default type url for Complex
+                 * @function getTypeUrl
+                 * @memberof jspb.test.OuterMessage.Complex
+                 * @static
+                 * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                 * @returns {string} The default type url
+                 */
+                Complex.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                    if (typeUrlPrefix === undefined) {
+                        typeUrlPrefix = "type.googleapis.com";
+                    }
+                    return typeUrlPrefix + "/jspb.test.OuterMessage.Complex";
+                };
+
+                return Complex;
+            })();
+
+            return OuterMessage;
+        })();
+
+        test.IsExtension = (function() {
+
+            /**
+             * Properties of an IsExtension.
+             * @memberof jspb.test
+             * @interface IIsExtension
+             * @property {string|null} [ext1] IsExtension ext1
+             */
+
+            /**
+             * Constructs a new IsExtension.
+             * @memberof jspb.test
+             * @classdesc Represents an IsExtension.
+             * @implements IIsExtension
+             * @constructor
+             * @param {jspb.test.IIsExtension=} [properties] Properties to set
+             */
+            function IsExtension(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * IsExtension ext1.
+             * @member {string} ext1
+             * @memberof jspb.test.IsExtension
+             * @instance
+             */
+            IsExtension.prototype.ext1 = "";
+
+            /**
+             * Creates a new IsExtension instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.IsExtension
+             * @static
+             * @param {jspb.test.IIsExtension=} [properties] Properties to set
+             * @returns {jspb.test.IsExtension} IsExtension instance
+             */
+            IsExtension.create = function create(properties) {
+                return new IsExtension(properties);
+            };
+
+            /**
+             * Encodes the specified IsExtension message. Does not implicitly {@link jspb.test.IsExtension.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.IsExtension
+             * @static
+             * @param {jspb.test.IIsExtension} message IsExtension message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            IsExtension.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.ext1 != null && Object.hasOwnProperty.call(message, "ext1"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.ext1);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified IsExtension message, length delimited. Does not implicitly {@link jspb.test.IsExtension.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.IsExtension
+             * @static
+             * @param {jspb.test.IIsExtension} message IsExtension message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            IsExtension.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes an IsExtension message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.IsExtension
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.IsExtension} IsExtension
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            IsExtension.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.IsExtension();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.ext1 = reader.string();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes an IsExtension message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.IsExtension
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.IsExtension} IsExtension
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            IsExtension.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies an IsExtension message.
+             * @function verify
+             * @memberof jspb.test.IsExtension
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            IsExtension.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.ext1 != null && message.hasOwnProperty("ext1"))
+                    if (!$util.isString(message.ext1))
+                        return "ext1: string expected";
+                return null;
+            };
+
+            /**
+             * Creates an IsExtension message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.IsExtension
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.IsExtension} IsExtension
+             */
+            IsExtension.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.IsExtension)
+                    return object;
+                var message = new $root.jspb.test.IsExtension();
+                if (object.ext1 != null)
+                    message.ext1 = String(object.ext1);
+                return message;
+            };
+
+            /**
+             * Creates a plain object from an IsExtension message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.IsExtension
+             * @static
+             * @param {jspb.test.IsExtension} message IsExtension
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            IsExtension.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults)
+                    object.ext1 = "";
+                if (message.ext1 != null && message.hasOwnProperty("ext1"))
+                    object.ext1 = message.ext1;
+                return object;
+            };
+
+            /**
+             * Converts this IsExtension to JSON.
+             * @function toJSON
+             * @memberof jspb.test.IsExtension
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            IsExtension.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for IsExtension
+             * @function getTypeUrl
+             * @memberof jspb.test.IsExtension
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            IsExtension.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.IsExtension";
+            };
+
+            return IsExtension;
+        })();
+
+        test.IndirectExtension = (function() {
+
+            /**
+             * Properties of an IndirectExtension.
+             * @memberof jspb.test
+             * @interface IIndirectExtension
+             */
+
+            /**
+             * Constructs a new IndirectExtension.
+             * @memberof jspb.test
+             * @classdesc Represents an IndirectExtension.
+             * @implements IIndirectExtension
+             * @constructor
+             * @param {jspb.test.IIndirectExtension=} [properties] Properties to set
+             */
+            function IndirectExtension(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * Creates a new IndirectExtension instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.IndirectExtension
+             * @static
+             * @param {jspb.test.IIndirectExtension=} [properties] Properties to set
+             * @returns {jspb.test.IndirectExtension} IndirectExtension instance
+             */
+            IndirectExtension.create = function create(properties) {
+                return new IndirectExtension(properties);
+            };
+
+            /**
+             * Encodes the specified IndirectExtension message. Does not implicitly {@link jspb.test.IndirectExtension.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.IndirectExtension
+             * @static
+             * @param {jspb.test.IIndirectExtension} message IndirectExtension message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            IndirectExtension.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified IndirectExtension message, length delimited. Does not implicitly {@link jspb.test.IndirectExtension.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.IndirectExtension
+             * @static
+             * @param {jspb.test.IIndirectExtension} message IndirectExtension message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            IndirectExtension.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes an IndirectExtension message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.IndirectExtension
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.IndirectExtension} IndirectExtension
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            IndirectExtension.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.IndirectExtension();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes an IndirectExtension message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.IndirectExtension
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.IndirectExtension} IndirectExtension
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            IndirectExtension.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies an IndirectExtension message.
+             * @function verify
+             * @memberof jspb.test.IndirectExtension
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            IndirectExtension.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                return null;
+            };
+
+            /**
+             * Creates an IndirectExtension message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.IndirectExtension
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.IndirectExtension} IndirectExtension
+             */
+            IndirectExtension.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.IndirectExtension)
+                    return object;
+                return new $root.jspb.test.IndirectExtension();
+            };
+
+            /**
+             * Creates a plain object from an IndirectExtension message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.IndirectExtension
+             * @static
+             * @param {jspb.test.IndirectExtension} message IndirectExtension
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            IndirectExtension.toObject = function toObject() {
+                return {};
+            };
+
+            /**
+             * Converts this IndirectExtension to JSON.
+             * @function toJSON
+             * @memberof jspb.test.IndirectExtension
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            IndirectExtension.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for IndirectExtension
+             * @function getTypeUrl
+             * @memberof jspb.test.IndirectExtension
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            IndirectExtension.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.IndirectExtension";
+            };
+
+            return IndirectExtension;
+        })();
+
+        test.DefaultValues = (function() {
+
+            /**
+             * Properties of a DefaultValues.
+             * @memberof jspb.test
+             * @interface IDefaultValues
+             * @property {string|null} [stringField] DefaultValues stringField
+             * @property {boolean|null} [boolField] DefaultValues boolField
+             * @property {number|Long|null} [intField] DefaultValues intField
+             * @property {jspb.test.DefaultValues.Enum|null} [enumField] DefaultValues enumField
+             * @property {string|null} [emptyField] DefaultValues emptyField
+             * @property {Uint8Array|null} [bytesField] DefaultValues bytesField
+             */
+
+            /**
+             * Constructs a new DefaultValues.
+             * @memberof jspb.test
+             * @classdesc Represents a DefaultValues.
+             * @implements IDefaultValues
+             * @constructor
+             * @param {jspb.test.IDefaultValues=} [properties] Properties to set
+             */
+            function DefaultValues(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * DefaultValues stringField.
+             * @member {string} stringField
+             * @memberof jspb.test.DefaultValues
+             * @instance
+             */
+            DefaultValues.prototype.stringField = "default<>abc";
+
+            /**
+             * DefaultValues boolField.
+             * @member {boolean} boolField
+             * @memberof jspb.test.DefaultValues
+             * @instance
+             */
+            DefaultValues.prototype.boolField = true;
+
+            /**
+             * DefaultValues intField.
+             * @member {number|Long} intField
+             * @memberof jspb.test.DefaultValues
+             * @instance
+             */
+            DefaultValues.prototype.intField = $util.Long ? $util.Long.fromBits(11,0,false) : 11;
+
+            /**
+             * DefaultValues enumField.
+             * @member {jspb.test.DefaultValues.Enum} enumField
+             * @memberof jspb.test.DefaultValues
+             * @instance
+             */
+            DefaultValues.prototype.enumField = 13;
+
+            /**
+             * DefaultValues emptyField.
+             * @member {string} emptyField
+             * @memberof jspb.test.DefaultValues
+             * @instance
+             */
+            DefaultValues.prototype.emptyField = "";
+
+            /**
+             * DefaultValues bytesField.
+             * @member {Uint8Array} bytesField
+             * @memberof jspb.test.DefaultValues
+             * @instance
+             */
+            DefaultValues.prototype.bytesField = $util.newBuffer([109,111,111]);
+
+            /**
+             * Creates a new DefaultValues instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.DefaultValues
+             * @static
+             * @param {jspb.test.IDefaultValues=} [properties] Properties to set
+             * @returns {jspb.test.DefaultValues} DefaultValues instance
+             */
+            DefaultValues.create = function create(properties) {
+                return new DefaultValues(properties);
+            };
+
+            /**
+             * Encodes the specified DefaultValues message. Does not implicitly {@link jspb.test.DefaultValues.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.DefaultValues
+             * @static
+             * @param {jspb.test.IDefaultValues} message DefaultValues message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            DefaultValues.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.stringField != null && Object.hasOwnProperty.call(message, "stringField"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.stringField);
+                if (message.boolField != null && Object.hasOwnProperty.call(message, "boolField"))
+                    writer.uint32(/* id 2, wireType 0 =*/16).bool(message.boolField);
+                if (message.intField != null && Object.hasOwnProperty.call(message, "intField"))
+                    writer.uint32(/* id 3, wireType 0 =*/24).int64(message.intField);
+                if (message.enumField != null && Object.hasOwnProperty.call(message, "enumField"))
+                    writer.uint32(/* id 4, wireType 0 =*/32).int32(message.enumField);
+                if (message.emptyField != null && Object.hasOwnProperty.call(message, "emptyField"))
+                    writer.uint32(/* id 6, wireType 2 =*/50).string(message.emptyField);
+                if (message.bytesField != null && Object.hasOwnProperty.call(message, "bytesField"))
+                    writer.uint32(/* id 8, wireType 2 =*/66).bytes(message.bytesField);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified DefaultValues message, length delimited. Does not implicitly {@link jspb.test.DefaultValues.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.DefaultValues
+             * @static
+             * @param {jspb.test.IDefaultValues} message DefaultValues message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            DefaultValues.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a DefaultValues message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.DefaultValues
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.DefaultValues} DefaultValues
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            DefaultValues.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.DefaultValues();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.stringField = reader.string();
+                        break;
+                    case 2:
+                        message.boolField = reader.bool();
+                        break;
+                    case 3:
+                        message.intField = reader.int64();
+                        break;
+                    case 4:
+                        message.enumField = reader.int32();
+                        break;
+                    case 6:
+                        message.emptyField = reader.string();
+                        break;
+                    case 8:
+                        message.bytesField = reader.bytes();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a DefaultValues message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.DefaultValues
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.DefaultValues} DefaultValues
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            DefaultValues.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a DefaultValues message.
+             * @function verify
+             * @memberof jspb.test.DefaultValues
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            DefaultValues.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.stringField != null && message.hasOwnProperty("stringField"))
+                    if (!$util.isString(message.stringField))
+                        return "stringField: string expected";
+                if (message.boolField != null && message.hasOwnProperty("boolField"))
+                    if (typeof message.boolField !== "boolean")
+                        return "boolField: boolean expected";
+                if (message.intField != null && message.hasOwnProperty("intField"))
+                    if (!$util.isInteger(message.intField) && !(message.intField && $util.isInteger(message.intField.low) && $util.isInteger(message.intField.high)))
+                        return "intField: integer|Long expected";
+                if (message.enumField != null && message.hasOwnProperty("enumField"))
+                    switch (message.enumField) {
+                    default:
+                        return "enumField: enum value expected";
+                    case 13:
+                    case 77:
+                        break;
+                    }
+                if (message.emptyField != null && message.hasOwnProperty("emptyField"))
+                    if (!$util.isString(message.emptyField))
+                        return "emptyField: string expected";
+                if (message.bytesField != null && message.hasOwnProperty("bytesField"))
+                    if (!(message.bytesField && typeof message.bytesField.length === "number" || $util.isString(message.bytesField)))
+                        return "bytesField: buffer expected";
+                return null;
+            };
+
+            /**
+             * Creates a DefaultValues message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.DefaultValues
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.DefaultValues} DefaultValues
+             */
+            DefaultValues.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.DefaultValues)
+                    return object;
+                var message = new $root.jspb.test.DefaultValues();
+                if (object.stringField != null)
+                    message.stringField = String(object.stringField);
+                if (object.boolField != null)
+                    message.boolField = Boolean(object.boolField);
+                if (object.intField != null)
+                    if ($util.Long)
+                        (message.intField = $util.Long.fromValue(object.intField)).unsigned = false;
+                    else if (typeof object.intField === "string")
+                        message.intField = parseInt(object.intField, 10);
+                    else if (typeof object.intField === "number")
+                        message.intField = object.intField;
+                    else if (typeof object.intField === "object")
+                        message.intField = new $util.LongBits(object.intField.low >>> 0, object.intField.high >>> 0).toNumber();
+                switch (object.enumField) {
+                case "E1":
+                case 13:
+                    message.enumField = 13;
+                    break;
+                case "E2":
+                case 77:
+                    message.enumField = 77;
+                    break;
+                }
+                if (object.emptyField != null)
+                    message.emptyField = String(object.emptyField);
+                if (object.bytesField != null)
+                    if (typeof object.bytesField === "string")
+                        $util.base64.decode(object.bytesField, message.bytesField = $util.newBuffer($util.base64.length(object.bytesField)), 0);
+                    else if (object.bytesField.length >= 0)
+                        message.bytesField = object.bytesField;
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a DefaultValues message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.DefaultValues
+             * @static
+             * @param {jspb.test.DefaultValues} message DefaultValues
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            DefaultValues.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults) {
+                    object.stringField = "default<>abc";
+                    object.boolField = true;
+                    if ($util.Long) {
+                        var long = new $util.Long(11, 0, false);
+                        object.intField = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
+                    } else
+                        object.intField = options.longs === String ? "11" : 11;
+                    object.enumField = options.enums === String ? "E1" : 13;
+                    object.emptyField = "";
+                    if (options.bytes === String)
+                        object.bytesField = "moo";
+                    else {
+                        object.bytesField = [
+                            109,
+                            111,
+                            111
+                        ];
+                        if (options.bytes !== Array)
+                            object.bytesField = $util.newBuffer(object.bytesField);
+                    }
+                }
+                if (message.stringField != null && message.hasOwnProperty("stringField"))
+                    object.stringField = message.stringField;
+                if (message.boolField != null && message.hasOwnProperty("boolField"))
+                    object.boolField = message.boolField;
+                if (message.intField != null && message.hasOwnProperty("intField"))
+                    if (typeof message.intField === "number")
+                        object.intField = options.longs === String ? String(message.intField) : message.intField;
+                    else
+                        object.intField = options.longs === String ? $util.Long.prototype.toString.call(message.intField) : options.longs === Number ? new $util.LongBits(message.intField.low >>> 0, message.intField.high >>> 0).toNumber() : message.intField;
+                if (message.enumField != null && message.hasOwnProperty("enumField"))
+                    object.enumField = options.enums === String ? $root.jspb.test.DefaultValues.Enum[message.enumField] : message.enumField;
+                if (message.emptyField != null && message.hasOwnProperty("emptyField"))
+                    object.emptyField = message.emptyField;
+                if (message.bytesField != null && message.hasOwnProperty("bytesField"))
+                    object.bytesField = options.bytes === String ? $util.base64.encode(message.bytesField, 0, message.bytesField.length) : options.bytes === Array ? Array.prototype.slice.call(message.bytesField) : message.bytesField;
+                return object;
+            };
+
+            /**
+             * Converts this DefaultValues to JSON.
+             * @function toJSON
+             * @memberof jspb.test.DefaultValues
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            DefaultValues.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for DefaultValues
+             * @function getTypeUrl
+             * @memberof jspb.test.DefaultValues
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            DefaultValues.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.DefaultValues";
+            };
+
+            /**
+             * Enum enum.
+             * @name jspb.test.DefaultValues.Enum
+             * @enum {number}
+             * @property {number} E1=13 E1 value
+             * @property {number} E2=77 E2 value
+             */
+            DefaultValues.Enum = (function() {
+                var valuesById = {}, values = Object.create(valuesById);
+                values[valuesById[13] = "E1"] = 13;
+                values[valuesById[77] = "E2"] = 77;
+                return values;
+            })();
+
+            return DefaultValues;
+        })();
+
+        test.FloatingPointFields = (function() {
+
+            /**
+             * Properties of a FloatingPointFields.
+             * @memberof jspb.test
+             * @interface IFloatingPointFields
+             * @property {number|null} [optionalFloatField] FloatingPointFields optionalFloatField
+             * @property {number} requiredFloatField FloatingPointFields requiredFloatField
+             * @property {Array.<number>|null} [repeatedFloatField] FloatingPointFields repeatedFloatField
+             * @property {number|null} [defaultFloatField] FloatingPointFields defaultFloatField
+             * @property {number|null} [optionalDoubleField] FloatingPointFields optionalDoubleField
+             * @property {number} requiredDoubleField FloatingPointFields requiredDoubleField
+             * @property {Array.<number>|null} [repeatedDoubleField] FloatingPointFields repeatedDoubleField
+             * @property {number|null} [defaultDoubleField] FloatingPointFields defaultDoubleField
+             */
+
+            /**
+             * Constructs a new FloatingPointFields.
+             * @memberof jspb.test
+             * @classdesc Represents a FloatingPointFields.
+             * @implements IFloatingPointFields
+             * @constructor
+             * @param {jspb.test.IFloatingPointFields=} [properties] Properties to set
+             */
+            function FloatingPointFields(properties) {
+                this.repeatedFloatField = [];
+                this.repeatedDoubleField = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * FloatingPointFields optionalFloatField.
+             * @member {number} optionalFloatField
+             * @memberof jspb.test.FloatingPointFields
+             * @instance
+             */
+            FloatingPointFields.prototype.optionalFloatField = 0;
+
+            /**
+             * FloatingPointFields requiredFloatField.
+             * @member {number} requiredFloatField
+             * @memberof jspb.test.FloatingPointFields
+             * @instance
+             */
+            FloatingPointFields.prototype.requiredFloatField = 0;
+
+            /**
+             * FloatingPointFields repeatedFloatField.
+             * @member {Array.<number>} repeatedFloatField
+             * @memberof jspb.test.FloatingPointFields
+             * @instance
+             */
+            FloatingPointFields.prototype.repeatedFloatField = $util.emptyArray;
+
+            /**
+             * FloatingPointFields defaultFloatField.
+             * @member {number} defaultFloatField
+             * @memberof jspb.test.FloatingPointFields
+             * @instance
+             */
+            FloatingPointFields.prototype.defaultFloatField = 2;
+
+            /**
+             * FloatingPointFields optionalDoubleField.
+             * @member {number} optionalDoubleField
+             * @memberof jspb.test.FloatingPointFields
+             * @instance
+             */
+            FloatingPointFields.prototype.optionalDoubleField = 0;
+
+            /**
+             * FloatingPointFields requiredDoubleField.
+             * @member {number} requiredDoubleField
+             * @memberof jspb.test.FloatingPointFields
+             * @instance
+             */
+            FloatingPointFields.prototype.requiredDoubleField = 0;
+
+            /**
+             * FloatingPointFields repeatedDoubleField.
+             * @member {Array.<number>} repeatedDoubleField
+             * @memberof jspb.test.FloatingPointFields
+             * @instance
+             */
+            FloatingPointFields.prototype.repeatedDoubleField = $util.emptyArray;
+
+            /**
+             * FloatingPointFields defaultDoubleField.
+             * @member {number} defaultDoubleField
+             * @memberof jspb.test.FloatingPointFields
+             * @instance
+             */
+            FloatingPointFields.prototype.defaultDoubleField = 2;
+
+            /**
+             * Creates a new FloatingPointFields instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.FloatingPointFields
+             * @static
+             * @param {jspb.test.IFloatingPointFields=} [properties] Properties to set
+             * @returns {jspb.test.FloatingPointFields} FloatingPointFields instance
+             */
+            FloatingPointFields.create = function create(properties) {
+                return new FloatingPointFields(properties);
+            };
+
+            /**
+             * Encodes the specified FloatingPointFields message. Does not implicitly {@link jspb.test.FloatingPointFields.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.FloatingPointFields
+             * @static
+             * @param {jspb.test.IFloatingPointFields} message FloatingPointFields message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            FloatingPointFields.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.optionalFloatField != null && Object.hasOwnProperty.call(message, "optionalFloatField"))
+                    writer.uint32(/* id 1, wireType 5 =*/13).float(message.optionalFloatField);
+                writer.uint32(/* id 2, wireType 5 =*/21).float(message.requiredFloatField);
+                if (message.repeatedFloatField != null && message.repeatedFloatField.length)
+                    for (var i = 0; i < message.repeatedFloatField.length; ++i)
+                        writer.uint32(/* id 3, wireType 5 =*/29).float(message.repeatedFloatField[i]);
+                if (message.defaultFloatField != null && Object.hasOwnProperty.call(message, "defaultFloatField"))
+                    writer.uint32(/* id 4, wireType 5 =*/37).float(message.defaultFloatField);
+                if (message.optionalDoubleField != null && Object.hasOwnProperty.call(message, "optionalDoubleField"))
+                    writer.uint32(/* id 5, wireType 1 =*/41).double(message.optionalDoubleField);
+                writer.uint32(/* id 6, wireType 1 =*/49).double(message.requiredDoubleField);
+                if (message.repeatedDoubleField != null && message.repeatedDoubleField.length)
+                    for (var i = 0; i < message.repeatedDoubleField.length; ++i)
+                        writer.uint32(/* id 7, wireType 1 =*/57).double(message.repeatedDoubleField[i]);
+                if (message.defaultDoubleField != null && Object.hasOwnProperty.call(message, "defaultDoubleField"))
+                    writer.uint32(/* id 8, wireType 1 =*/65).double(message.defaultDoubleField);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified FloatingPointFields message, length delimited. Does not implicitly {@link jspb.test.FloatingPointFields.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.FloatingPointFields
+             * @static
+             * @param {jspb.test.IFloatingPointFields} message FloatingPointFields message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            FloatingPointFields.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a FloatingPointFields message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.FloatingPointFields
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.FloatingPointFields} FloatingPointFields
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            FloatingPointFields.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.FloatingPointFields();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.optionalFloatField = reader.float();
+                        break;
+                    case 2:
+                        message.requiredFloatField = reader.float();
+                        break;
+                    case 3:
+                        if (!(message.repeatedFloatField && message.repeatedFloatField.length))
+                            message.repeatedFloatField = [];
+                        if ((tag & 7) === 2) {
+                            var end2 = reader.uint32() + reader.pos;
+                            while (reader.pos < end2)
+                                message.repeatedFloatField.push(reader.float());
+                        } else
+                            message.repeatedFloatField.push(reader.float());
+                        break;
+                    case 4:
+                        message.defaultFloatField = reader.float();
+                        break;
+                    case 5:
+                        message.optionalDoubleField = reader.double();
+                        break;
+                    case 6:
+                        message.requiredDoubleField = reader.double();
+                        break;
+                    case 7:
+                        if (!(message.repeatedDoubleField && message.repeatedDoubleField.length))
+                            message.repeatedDoubleField = [];
+                        if ((tag & 7) === 2) {
+                            var end2 = reader.uint32() + reader.pos;
+                            while (reader.pos < end2)
+                                message.repeatedDoubleField.push(reader.double());
+                        } else
+                            message.repeatedDoubleField.push(reader.double());
+                        break;
+                    case 8:
+                        message.defaultDoubleField = reader.double();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("requiredFloatField"))
+                    throw $util.ProtocolError("missing required 'requiredFloatField'", { instance: message });
+                if (!message.hasOwnProperty("requiredDoubleField"))
+                    throw $util.ProtocolError("missing required 'requiredDoubleField'", { instance: message });
+                return message;
+            };
+
+            /**
+             * Decodes a FloatingPointFields message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.FloatingPointFields
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.FloatingPointFields} FloatingPointFields
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            FloatingPointFields.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a FloatingPointFields message.
+             * @function verify
+             * @memberof jspb.test.FloatingPointFields
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            FloatingPointFields.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.optionalFloatField != null && message.hasOwnProperty("optionalFloatField"))
+                    if (typeof message.optionalFloatField !== "number")
+                        return "optionalFloatField: number expected";
+                if (typeof message.requiredFloatField !== "number")
+                    return "requiredFloatField: number expected";
+                if (message.repeatedFloatField != null && message.hasOwnProperty("repeatedFloatField")) {
+                    if (!Array.isArray(message.repeatedFloatField))
+                        return "repeatedFloatField: array expected";
+                    for (var i = 0; i < message.repeatedFloatField.length; ++i)
+                        if (typeof message.repeatedFloatField[i] !== "number")
+                            return "repeatedFloatField: number[] expected";
+                }
+                if (message.defaultFloatField != null && message.hasOwnProperty("defaultFloatField"))
+                    if (typeof message.defaultFloatField !== "number")
+                        return "defaultFloatField: number expected";
+                if (message.optionalDoubleField != null && message.hasOwnProperty("optionalDoubleField"))
+                    if (typeof message.optionalDoubleField !== "number")
+                        return "optionalDoubleField: number expected";
+                if (typeof message.requiredDoubleField !== "number")
+                    return "requiredDoubleField: number expected";
+                if (message.repeatedDoubleField != null && message.hasOwnProperty("repeatedDoubleField")) {
+                    if (!Array.isArray(message.repeatedDoubleField))
+                        return "repeatedDoubleField: array expected";
+                    for (var i = 0; i < message.repeatedDoubleField.length; ++i)
+                        if (typeof message.repeatedDoubleField[i] !== "number")
+                            return "repeatedDoubleField: number[] expected";
+                }
+                if (message.defaultDoubleField != null && message.hasOwnProperty("defaultDoubleField"))
+                    if (typeof message.defaultDoubleField !== "number")
+                        return "defaultDoubleField: number expected";
+                return null;
+            };
+
+            /**
+             * Creates a FloatingPointFields message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.FloatingPointFields
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.FloatingPointFields} FloatingPointFields
+             */
+            FloatingPointFields.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.FloatingPointFields)
+                    return object;
+                var message = new $root.jspb.test.FloatingPointFields();
+                if (object.optionalFloatField != null)
+                    message.optionalFloatField = Number(object.optionalFloatField);
+                if (object.requiredFloatField != null)
+                    message.requiredFloatField = Number(object.requiredFloatField);
+                if (object.repeatedFloatField) {
+                    if (!Array.isArray(object.repeatedFloatField))
+                        throw TypeError(".jspb.test.FloatingPointFields.repeatedFloatField: array expected");
+                    message.repeatedFloatField = [];
+                    for (var i = 0; i < object.repeatedFloatField.length; ++i)
+                        message.repeatedFloatField[i] = Number(object.repeatedFloatField[i]);
+                }
+                if (object.defaultFloatField != null)
+                    message.defaultFloatField = Number(object.defaultFloatField);
+                if (object.optionalDoubleField != null)
+                    message.optionalDoubleField = Number(object.optionalDoubleField);
+                if (object.requiredDoubleField != null)
+                    message.requiredDoubleField = Number(object.requiredDoubleField);
+                if (object.repeatedDoubleField) {
+                    if (!Array.isArray(object.repeatedDoubleField))
+                        throw TypeError(".jspb.test.FloatingPointFields.repeatedDoubleField: array expected");
+                    message.repeatedDoubleField = [];
+                    for (var i = 0; i < object.repeatedDoubleField.length; ++i)
+                        message.repeatedDoubleField[i] = Number(object.repeatedDoubleField[i]);
+                }
+                if (object.defaultDoubleField != null)
+                    message.defaultDoubleField = Number(object.defaultDoubleField);
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a FloatingPointFields message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.FloatingPointFields
+             * @static
+             * @param {jspb.test.FloatingPointFields} message FloatingPointFields
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            FloatingPointFields.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults) {
+                    object.repeatedFloatField = [];
+                    object.repeatedDoubleField = [];
+                }
+                if (options.defaults) {
+                    object.optionalFloatField = 0;
+                    object.requiredFloatField = 0;
+                    object.defaultFloatField = 2;
+                    object.optionalDoubleField = 0;
+                    object.requiredDoubleField = 0;
+                    object.defaultDoubleField = 2;
+                }
+                if (message.optionalFloatField != null && message.hasOwnProperty("optionalFloatField"))
+                    object.optionalFloatField = options.json && !isFinite(message.optionalFloatField) ? String(message.optionalFloatField) : message.optionalFloatField;
+                if (message.requiredFloatField != null && message.hasOwnProperty("requiredFloatField"))
+                    object.requiredFloatField = options.json && !isFinite(message.requiredFloatField) ? String(message.requiredFloatField) : message.requiredFloatField;
+                if (message.repeatedFloatField && message.repeatedFloatField.length) {
+                    object.repeatedFloatField = [];
+                    for (var j = 0; j < message.repeatedFloatField.length; ++j)
+                        object.repeatedFloatField[j] = options.json && !isFinite(message.repeatedFloatField[j]) ? String(message.repeatedFloatField[j]) : message.repeatedFloatField[j];
+                }
+                if (message.defaultFloatField != null && message.hasOwnProperty("defaultFloatField"))
+                    object.defaultFloatField = options.json && !isFinite(message.defaultFloatField) ? String(message.defaultFloatField) : message.defaultFloatField;
+                if (message.optionalDoubleField != null && message.hasOwnProperty("optionalDoubleField"))
+                    object.optionalDoubleField = options.json && !isFinite(message.optionalDoubleField) ? String(message.optionalDoubleField) : message.optionalDoubleField;
+                if (message.requiredDoubleField != null && message.hasOwnProperty("requiredDoubleField"))
+                    object.requiredDoubleField = options.json && !isFinite(message.requiredDoubleField) ? String(message.requiredDoubleField) : message.requiredDoubleField;
+                if (message.repeatedDoubleField && message.repeatedDoubleField.length) {
+                    object.repeatedDoubleField = [];
+                    for (var j = 0; j < message.repeatedDoubleField.length; ++j)
+                        object.repeatedDoubleField[j] = options.json && !isFinite(message.repeatedDoubleField[j]) ? String(message.repeatedDoubleField[j]) : message.repeatedDoubleField[j];
+                }
+                if (message.defaultDoubleField != null && message.hasOwnProperty("defaultDoubleField"))
+                    object.defaultDoubleField = options.json && !isFinite(message.defaultDoubleField) ? String(message.defaultDoubleField) : message.defaultDoubleField;
+                return object;
+            };
+
+            /**
+             * Converts this FloatingPointFields to JSON.
+             * @function toJSON
+             * @memberof jspb.test.FloatingPointFields
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            FloatingPointFields.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for FloatingPointFields
+             * @function getTypeUrl
+             * @memberof jspb.test.FloatingPointFields
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            FloatingPointFields.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.FloatingPointFields";
+            };
+
+            return FloatingPointFields;
+        })();
+
+        test.TestClone = (function() {
+
+            /**
+             * Properties of a TestClone.
+             * @memberof jspb.test
+             * @interface ITestClone
+             * @property {string|null} [str] TestClone str
+             * @property {jspb.test.ISimple1|null} [simple1] TestClone simple1
+             * @property {Array.<jspb.test.ISimple1>|null} [simple2] TestClone simple2
+             * @property {Uint8Array|null} [bytesField] TestClone bytesField
+             * @property {string|null} [unused] TestClone unused
+             * @property {jspb.test.ICloneExtension|null} [".jspb.test.CloneExtension.extField"] TestClone .jspb.test.CloneExtension.extField
+             */
+
+            /**
+             * Constructs a new TestClone.
+             * @memberof jspb.test
+             * @classdesc Represents a TestClone.
+             * @implements ITestClone
+             * @constructor
+             * @param {jspb.test.ITestClone=} [properties] Properties to set
+             */
+            function TestClone(properties) {
+                this.simple2 = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * TestClone str.
+             * @member {string} str
+             * @memberof jspb.test.TestClone
+             * @instance
+             */
+            TestClone.prototype.str = "";
+
+            /**
+             * TestClone simple1.
+             * @member {jspb.test.ISimple1|null|undefined} simple1
+             * @memberof jspb.test.TestClone
+             * @instance
+             */
+            TestClone.prototype.simple1 = null;
+
+            /**
+             * TestClone simple2.
+             * @member {Array.<jspb.test.ISimple1>} simple2
+             * @memberof jspb.test.TestClone
+             * @instance
+             */
+            TestClone.prototype.simple2 = $util.emptyArray;
+
+            /**
+             * TestClone bytesField.
+             * @member {Uint8Array} bytesField
+             * @memberof jspb.test.TestClone
+             * @instance
+             */
+            TestClone.prototype.bytesField = $util.newBuffer([]);
+
+            /**
+             * TestClone unused.
+             * @member {string} unused
+             * @memberof jspb.test.TestClone
+             * @instance
+             */
+            TestClone.prototype.unused = "";
+
+            /**
+             * TestClone .jspb.test.CloneExtension.extField.
+             * @member {jspb.test.ICloneExtension|null|undefined} .jspb.test.CloneExtension.extField
+             * @memberof jspb.test.TestClone
+             * @instance
+             */
+            TestClone.prototype[".jspb.test.CloneExtension.extField"] = null;
+
+            /**
+             * Creates a new TestClone instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.TestClone
+             * @static
+             * @param {jspb.test.ITestClone=} [properties] Properties to set
+             * @returns {jspb.test.TestClone} TestClone instance
+             */
+            TestClone.create = function create(properties) {
+                return new TestClone(properties);
+            };
+
+            /**
+             * Encodes the specified TestClone message. Does not implicitly {@link jspb.test.TestClone.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.TestClone
+             * @static
+             * @param {jspb.test.ITestClone} message TestClone message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestClone.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.str != null && Object.hasOwnProperty.call(message, "str"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.str);
+                if (message.simple1 != null && Object.hasOwnProperty.call(message, "simple1"))
+                    $root.jspb.test.Simple1.encode(message.simple1, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim();
+                if (message.simple2 != null && message.simple2.length)
+                    for (var i = 0; i < message.simple2.length; ++i)
+                        $root.jspb.test.Simple1.encode(message.simple2[i], writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim();
+                if (message.bytesField != null && Object.hasOwnProperty.call(message, "bytesField"))
+                    writer.uint32(/* id 6, wireType 2 =*/50).bytes(message.bytesField);
+                if (message.unused != null && Object.hasOwnProperty.call(message, "unused"))
+                    writer.uint32(/* id 7, wireType 2 =*/58).string(message.unused);
+                if (message[".jspb.test.CloneExtension.extField"] != null && Object.hasOwnProperty.call(message, ".jspb.test.CloneExtension.extField"))
+                    $root.jspb.test.CloneExtension.encode(message[".jspb.test.CloneExtension.extField"], writer.uint32(/* id 100, wireType 2 =*/802).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified TestClone message, length delimited. Does not implicitly {@link jspb.test.TestClone.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.TestClone
+             * @static
+             * @param {jspb.test.ITestClone} message TestClone message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestClone.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a TestClone message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.TestClone
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.TestClone} TestClone
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestClone.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.TestClone();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.str = reader.string();
+                        break;
+                    case 3:
+                        message.simple1 = $root.jspb.test.Simple1.decode(reader, reader.uint32());
+                        break;
+                    case 5:
+                        if (!(message.simple2 && message.simple2.length))
+                            message.simple2 = [];
+                        message.simple2.push($root.jspb.test.Simple1.decode(reader, reader.uint32()));
+                        break;
+                    case 6:
+                        message.bytesField = reader.bytes();
+                        break;
+                    case 7:
+                        message.unused = reader.string();
+                        break;
+                    case 100:
+                        message[".jspb.test.CloneExtension.extField"] = $root.jspb.test.CloneExtension.decode(reader, reader.uint32());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a TestClone message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.TestClone
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.TestClone} TestClone
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestClone.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a TestClone message.
+             * @function verify
+             * @memberof jspb.test.TestClone
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            TestClone.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.str != null && message.hasOwnProperty("str"))
+                    if (!$util.isString(message.str))
+                        return "str: string expected";
+                if (message.simple1 != null && message.hasOwnProperty("simple1")) {
+                    var error = $root.jspb.test.Simple1.verify(message.simple1);
+                    if (error)
+                        return "simple1." + error;
+                }
+                if (message.simple2 != null && message.hasOwnProperty("simple2")) {
+                    if (!Array.isArray(message.simple2))
+                        return "simple2: array expected";
+                    for (var i = 0; i < message.simple2.length; ++i) {
+                        var error = $root.jspb.test.Simple1.verify(message.simple2[i]);
+                        if (error)
+                            return "simple2." + error;
+                    }
+                }
+                if (message.bytesField != null && message.hasOwnProperty("bytesField"))
+                    if (!(message.bytesField && typeof message.bytesField.length === "number" || $util.isString(message.bytesField)))
+                        return "bytesField: buffer expected";
+                if (message.unused != null && message.hasOwnProperty("unused"))
+                    if (!$util.isString(message.unused))
+                        return "unused: string expected";
+                if (message[".jspb.test.CloneExtension.extField"] != null && message.hasOwnProperty(".jspb.test.CloneExtension.extField")) {
+                    var error = $root.jspb.test.CloneExtension.verify(message[".jspb.test.CloneExtension.extField"]);
+                    if (error)
+                        return ".jspb.test.CloneExtension.extField." + error;
+                }
+                return null;
+            };
+
+            /**
+             * Creates a TestClone message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.TestClone
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.TestClone} TestClone
+             */
+            TestClone.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.TestClone)
+                    return object;
+                var message = new $root.jspb.test.TestClone();
+                if (object.str != null)
+                    message.str = String(object.str);
+                if (object.simple1 != null) {
+                    if (typeof object.simple1 !== "object")
+                        throw TypeError(".jspb.test.TestClone.simple1: object expected");
+                    message.simple1 = $root.jspb.test.Simple1.fromObject(object.simple1);
+                }
+                if (object.simple2) {
+                    if (!Array.isArray(object.simple2))
+                        throw TypeError(".jspb.test.TestClone.simple2: array expected");
+                    message.simple2 = [];
+                    for (var i = 0; i < object.simple2.length; ++i) {
+                        if (typeof object.simple2[i] !== "object")
+                            throw TypeError(".jspb.test.TestClone.simple2: object expected");
+                        message.simple2[i] = $root.jspb.test.Simple1.fromObject(object.simple2[i]);
+                    }
+                }
+                if (object.bytesField != null)
+                    if (typeof object.bytesField === "string")
+                        $util.base64.decode(object.bytesField, message.bytesField = $util.newBuffer($util.base64.length(object.bytesField)), 0);
+                    else if (object.bytesField.length >= 0)
+                        message.bytesField = object.bytesField;
+                if (object.unused != null)
+                    message.unused = String(object.unused);
+                if (object[".jspb.test.CloneExtension.extField"] != null) {
+                    if (typeof object[".jspb.test.CloneExtension.extField"] !== "object")
+                        throw TypeError(".jspb.test.TestClone..jspb.test.CloneExtension.extField: object expected");
+                    message[".jspb.test.CloneExtension.extField"] = $root.jspb.test.CloneExtension.fromObject(object[".jspb.test.CloneExtension.extField"]);
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a TestClone message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.TestClone
+             * @static
+             * @param {jspb.test.TestClone} message TestClone
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            TestClone.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.simple2 = [];
+                if (options.defaults) {
+                    object.str = "";
+                    object.simple1 = null;
+                    if (options.bytes === String)
+                        object.bytesField = "";
+                    else {
+                        object.bytesField = [];
+                        if (options.bytes !== Array)
+                            object.bytesField = $util.newBuffer(object.bytesField);
+                    }
+                    object.unused = "";
+                    object[".jspb.test.CloneExtension.extField"] = null;
+                }
+                if (message.str != null && message.hasOwnProperty("str"))
+                    object.str = message.str;
+                if (message.simple1 != null && message.hasOwnProperty("simple1"))
+                    object.simple1 = $root.jspb.test.Simple1.toObject(message.simple1, options);
+                if (message.simple2 && message.simple2.length) {
+                    object.simple2 = [];
+                    for (var j = 0; j < message.simple2.length; ++j)
+                        object.simple2[j] = $root.jspb.test.Simple1.toObject(message.simple2[j], options);
+                }
+                if (message.bytesField != null && message.hasOwnProperty("bytesField"))
+                    object.bytesField = options.bytes === String ? $util.base64.encode(message.bytesField, 0, message.bytesField.length) : options.bytes === Array ? Array.prototype.slice.call(message.bytesField) : message.bytesField;
+                if (message.unused != null && message.hasOwnProperty("unused"))
+                    object.unused = message.unused;
+                if (message[".jspb.test.CloneExtension.extField"] != null && message.hasOwnProperty(".jspb.test.CloneExtension.extField"))
+                    object[".jspb.test.CloneExtension.extField"] = $root.jspb.test.CloneExtension.toObject(message[".jspb.test.CloneExtension.extField"], options);
+                return object;
+            };
+
+            /**
+             * Converts this TestClone to JSON.
+             * @function toJSON
+             * @memberof jspb.test.TestClone
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            TestClone.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for TestClone
+             * @function getTypeUrl
+             * @memberof jspb.test.TestClone
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            TestClone.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.TestClone";
+            };
+
+            return TestClone;
+        })();
+
+        test.CloneExtension = (function() {
+
+            /**
+             * Properties of a CloneExtension.
+             * @memberof jspb.test
+             * @interface ICloneExtension
+             * @property {string|null} [ext] CloneExtension ext
+             */
+
+            /**
+             * Constructs a new CloneExtension.
+             * @memberof jspb.test
+             * @classdesc Represents a CloneExtension.
+             * @implements ICloneExtension
+             * @constructor
+             * @param {jspb.test.ICloneExtension=} [properties] Properties to set
+             */
+            function CloneExtension(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * CloneExtension ext.
+             * @member {string} ext
+             * @memberof jspb.test.CloneExtension
+             * @instance
+             */
+            CloneExtension.prototype.ext = "";
+
+            /**
+             * Creates a new CloneExtension instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.CloneExtension
+             * @static
+             * @param {jspb.test.ICloneExtension=} [properties] Properties to set
+             * @returns {jspb.test.CloneExtension} CloneExtension instance
+             */
+            CloneExtension.create = function create(properties) {
+                return new CloneExtension(properties);
+            };
+
+            /**
+             * Encodes the specified CloneExtension message. Does not implicitly {@link jspb.test.CloneExtension.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.CloneExtension
+             * @static
+             * @param {jspb.test.ICloneExtension} message CloneExtension message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            CloneExtension.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.ext != null && Object.hasOwnProperty.call(message, "ext"))
+                    writer.uint32(/* id 2, wireType 2 =*/18).string(message.ext);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified CloneExtension message, length delimited. Does not implicitly {@link jspb.test.CloneExtension.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.CloneExtension
+             * @static
+             * @param {jspb.test.ICloneExtension} message CloneExtension message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            CloneExtension.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a CloneExtension message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.CloneExtension
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.CloneExtension} CloneExtension
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            CloneExtension.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.CloneExtension();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 2:
+                        message.ext = reader.string();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a CloneExtension message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.CloneExtension
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.CloneExtension} CloneExtension
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            CloneExtension.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a CloneExtension message.
+             * @function verify
+             * @memberof jspb.test.CloneExtension
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            CloneExtension.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.ext != null && message.hasOwnProperty("ext"))
+                    if (!$util.isString(message.ext))
+                        return "ext: string expected";
+                return null;
+            };
+
+            /**
+             * Creates a CloneExtension message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.CloneExtension
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.CloneExtension} CloneExtension
+             */
+            CloneExtension.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.CloneExtension)
+                    return object;
+                var message = new $root.jspb.test.CloneExtension();
+                if (object.ext != null)
+                    message.ext = String(object.ext);
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a CloneExtension message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.CloneExtension
+             * @static
+             * @param {jspb.test.CloneExtension} message CloneExtension
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            CloneExtension.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults)
+                    object.ext = "";
+                if (message.ext != null && message.hasOwnProperty("ext"))
+                    object.ext = message.ext;
+                return object;
+            };
+
+            /**
+             * Converts this CloneExtension to JSON.
+             * @function toJSON
+             * @memberof jspb.test.CloneExtension
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            CloneExtension.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for CloneExtension
+             * @function getTypeUrl
+             * @memberof jspb.test.CloneExtension
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            CloneExtension.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.CloneExtension";
+            };
+
+            return CloneExtension;
+        })();
+
+        test.TestGroup = (function() {
+
+            /**
+             * Properties of a TestGroup.
+             * @memberof jspb.test
+             * @interface ITestGroup
+             * @property {Array.<jspb.test.TestGroup.IRepeatedGroup>|null} [repeatedGroup] TestGroup repeatedGroup
+             * @property {jspb.test.TestGroup.IRequiredGroup} requiredGroup TestGroup requiredGroup
+             * @property {jspb.test.TestGroup.IOptionalGroup|null} [optionalGroup] TestGroup optionalGroup
+             * @property {string|null} [id] TestGroup id
+             * @property {jspb.test.ISimple2} requiredSimple TestGroup requiredSimple
+             * @property {jspb.test.ISimple2|null} [optionalSimple] TestGroup optionalSimple
+             */
+
+            /**
+             * Constructs a new TestGroup.
+             * @memberof jspb.test
+             * @classdesc Represents a TestGroup.
+             * @implements ITestGroup
+             * @constructor
+             * @param {jspb.test.ITestGroup=} [properties] Properties to set
+             */
+            function TestGroup(properties) {
+                this.repeatedGroup = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * TestGroup repeatedGroup.
+             * @member {Array.<jspb.test.TestGroup.IRepeatedGroup>} repeatedGroup
+             * @memberof jspb.test.TestGroup
+             * @instance
+             */
+            TestGroup.prototype.repeatedGroup = $util.emptyArray;
+
+            /**
+             * TestGroup requiredGroup.
+             * @member {jspb.test.TestGroup.IRequiredGroup} requiredGroup
+             * @memberof jspb.test.TestGroup
+             * @instance
+             */
+            TestGroup.prototype.requiredGroup = null;
+
+            /**
+             * TestGroup optionalGroup.
+             * @member {jspb.test.TestGroup.IOptionalGroup|null|undefined} optionalGroup
+             * @memberof jspb.test.TestGroup
+             * @instance
+             */
+            TestGroup.prototype.optionalGroup = null;
+
+            /**
+             * TestGroup id.
+             * @member {string} id
+             * @memberof jspb.test.TestGroup
+             * @instance
+             */
+            TestGroup.prototype.id = "";
+
+            /**
+             * TestGroup requiredSimple.
+             * @member {jspb.test.ISimple2} requiredSimple
+             * @memberof jspb.test.TestGroup
+             * @instance
+             */
+            TestGroup.prototype.requiredSimple = null;
+
+            /**
+             * TestGroup optionalSimple.
+             * @member {jspb.test.ISimple2|null|undefined} optionalSimple
+             * @memberof jspb.test.TestGroup
+             * @instance
+             */
+            TestGroup.prototype.optionalSimple = null;
+
+            /**
+             * Creates a new TestGroup instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.TestGroup
+             * @static
+             * @param {jspb.test.ITestGroup=} [properties] Properties to set
+             * @returns {jspb.test.TestGroup} TestGroup instance
+             */
+            TestGroup.create = function create(properties) {
+                return new TestGroup(properties);
+            };
+
+            /**
+             * Encodes the specified TestGroup message. Does not implicitly {@link jspb.test.TestGroup.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.TestGroup
+             * @static
+             * @param {jspb.test.ITestGroup} message TestGroup message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestGroup.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.repeatedGroup != null && message.repeatedGroup.length)
+                    for (var i = 0; i < message.repeatedGroup.length; ++i)
+                        $root.jspb.test.TestGroup.RepeatedGroup.encode(message.repeatedGroup[i], writer.uint32(/* id 1, wireType 3 =*/11)).uint32(/* id 1, wireType 4 =*/12);
+                $root.jspb.test.TestGroup.RequiredGroup.encode(message.requiredGroup, writer.uint32(/* id 2, wireType 3 =*/19)).uint32(/* id 2, wireType 4 =*/20);
+                if (message.optionalGroup != null && Object.hasOwnProperty.call(message, "optionalGroup"))
+                    $root.jspb.test.TestGroup.OptionalGroup.encode(message.optionalGroup, writer.uint32(/* id 3, wireType 3 =*/27)).uint32(/* id 3, wireType 4 =*/28);
+                if (message.id != null && Object.hasOwnProperty.call(message, "id"))
+                    writer.uint32(/* id 4, wireType 2 =*/34).string(message.id);
+                $root.jspb.test.Simple2.encode(message.requiredSimple, writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim();
+                if (message.optionalSimple != null && Object.hasOwnProperty.call(message, "optionalSimple"))
+                    $root.jspb.test.Simple2.encode(message.optionalSimple, writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified TestGroup message, length delimited. Does not implicitly {@link jspb.test.TestGroup.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.TestGroup
+             * @static
+             * @param {jspb.test.ITestGroup} message TestGroup message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestGroup.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a TestGroup message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.TestGroup
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.TestGroup} TestGroup
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestGroup.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.TestGroup();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        if (!(message.repeatedGroup && message.repeatedGroup.length))
+                            message.repeatedGroup = [];
+                        message.repeatedGroup.push($root.jspb.test.TestGroup.RepeatedGroup.decode(reader));
+                        break;
+                    case 2:
+                        message.requiredGroup = $root.jspb.test.TestGroup.RequiredGroup.decode(reader);
+                        break;
+                    case 3:
+                        message.optionalGroup = $root.jspb.test.TestGroup.OptionalGroup.decode(reader);
+                        break;
+                    case 4:
+                        message.id = reader.string();
+                        break;
+                    case 5:
+                        message.requiredSimple = $root.jspb.test.Simple2.decode(reader, reader.uint32());
+                        break;
+                    case 6:
+                        message.optionalSimple = $root.jspb.test.Simple2.decode(reader, reader.uint32());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("requiredGroup"))
+                    throw $util.ProtocolError("missing required 'requiredGroup'", { instance: message });
+                if (!message.hasOwnProperty("requiredSimple"))
+                    throw $util.ProtocolError("missing required 'requiredSimple'", { instance: message });
+                return message;
+            };
+
+            /**
+             * Decodes a TestGroup message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.TestGroup
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.TestGroup} TestGroup
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestGroup.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a TestGroup message.
+             * @function verify
+             * @memberof jspb.test.TestGroup
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            TestGroup.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.repeatedGroup != null && message.hasOwnProperty("repeatedGroup")) {
+                    if (!Array.isArray(message.repeatedGroup))
+                        return "repeatedGroup: array expected";
+                    for (var i = 0; i < message.repeatedGroup.length; ++i) {
+                        var error = $root.jspb.test.TestGroup.RepeatedGroup.verify(message.repeatedGroup[i]);
+                        if (error)
+                            return "repeatedGroup." + error;
+                    }
+                }
+                {
+                    var error = $root.jspb.test.TestGroup.RequiredGroup.verify(message.requiredGroup);
+                    if (error)
+                        return "requiredGroup." + error;
+                }
+                if (message.optionalGroup != null && message.hasOwnProperty("optionalGroup")) {
+                    var error = $root.jspb.test.TestGroup.OptionalGroup.verify(message.optionalGroup);
+                    if (error)
+                        return "optionalGroup." + error;
+                }
+                if (message.id != null && message.hasOwnProperty("id"))
+                    if (!$util.isString(message.id))
+                        return "id: string expected";
+                {
+                    var error = $root.jspb.test.Simple2.verify(message.requiredSimple);
+                    if (error)
+                        return "requiredSimple." + error;
+                }
+                if (message.optionalSimple != null && message.hasOwnProperty("optionalSimple")) {
+                    var error = $root.jspb.test.Simple2.verify(message.optionalSimple);
+                    if (error)
+                        return "optionalSimple." + error;
+                }
+                return null;
+            };
+
+            /**
+             * Creates a TestGroup message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.TestGroup
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.TestGroup} TestGroup
+             */
+            TestGroup.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.TestGroup)
+                    return object;
+                var message = new $root.jspb.test.TestGroup();
+                if (object.repeatedGroup) {
+                    if (!Array.isArray(object.repeatedGroup))
+                        throw TypeError(".jspb.test.TestGroup.repeatedGroup: array expected");
+                    message.repeatedGroup = [];
+                    for (var i = 0; i < object.repeatedGroup.length; ++i) {
+                        if (typeof object.repeatedGroup[i] !== "object")
+                            throw TypeError(".jspb.test.TestGroup.repeatedGroup: object expected");
+                        message.repeatedGroup[i] = $root.jspb.test.TestGroup.RepeatedGroup.fromObject(object.repeatedGroup[i]);
+                    }
+                }
+                if (object.requiredGroup != null) {
+                    if (typeof object.requiredGroup !== "object")
+                        throw TypeError(".jspb.test.TestGroup.requiredGroup: object expected");
+                    message.requiredGroup = $root.jspb.test.TestGroup.RequiredGroup.fromObject(object.requiredGroup);
+                }
+                if (object.optionalGroup != null) {
+                    if (typeof object.optionalGroup !== "object")
+                        throw TypeError(".jspb.test.TestGroup.optionalGroup: object expected");
+                    message.optionalGroup = $root.jspb.test.TestGroup.OptionalGroup.fromObject(object.optionalGroup);
+                }
+                if (object.id != null)
+                    message.id = String(object.id);
+                if (object.requiredSimple != null) {
+                    if (typeof object.requiredSimple !== "object")
+                        throw TypeError(".jspb.test.TestGroup.requiredSimple: object expected");
+                    message.requiredSimple = $root.jspb.test.Simple2.fromObject(object.requiredSimple);
+                }
+                if (object.optionalSimple != null) {
+                    if (typeof object.optionalSimple !== "object")
+                        throw TypeError(".jspb.test.TestGroup.optionalSimple: object expected");
+                    message.optionalSimple = $root.jspb.test.Simple2.fromObject(object.optionalSimple);
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a TestGroup message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.TestGroup
+             * @static
+             * @param {jspb.test.TestGroup} message TestGroup
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            TestGroup.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.repeatedGroup = [];
+                if (options.defaults) {
+                    object.requiredGroup = null;
+                    object.optionalGroup = null;
+                    object.id = "";
+                    object.requiredSimple = null;
+                    object.optionalSimple = null;
+                }
+                if (message.repeatedGroup && message.repeatedGroup.length) {
+                    object.repeatedGroup = [];
+                    for (var j = 0; j < message.repeatedGroup.length; ++j)
+                        object.repeatedGroup[j] = $root.jspb.test.TestGroup.RepeatedGroup.toObject(message.repeatedGroup[j], options);
+                }
+                if (message.requiredGroup != null && message.hasOwnProperty("requiredGroup"))
+                    object.requiredGroup = $root.jspb.test.TestGroup.RequiredGroup.toObject(message.requiredGroup, options);
+                if (message.optionalGroup != null && message.hasOwnProperty("optionalGroup"))
+                    object.optionalGroup = $root.jspb.test.TestGroup.OptionalGroup.toObject(message.optionalGroup, options);
+                if (message.id != null && message.hasOwnProperty("id"))
+                    object.id = message.id;
+                if (message.requiredSimple != null && message.hasOwnProperty("requiredSimple"))
+                    object.requiredSimple = $root.jspb.test.Simple2.toObject(message.requiredSimple, options);
+                if (message.optionalSimple != null && message.hasOwnProperty("optionalSimple"))
+                    object.optionalSimple = $root.jspb.test.Simple2.toObject(message.optionalSimple, options);
+                return object;
+            };
+
+            /**
+             * Converts this TestGroup to JSON.
+             * @function toJSON
+             * @memberof jspb.test.TestGroup
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            TestGroup.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for TestGroup
+             * @function getTypeUrl
+             * @memberof jspb.test.TestGroup
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            TestGroup.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.TestGroup";
+            };
+
+            TestGroup.RepeatedGroup = (function() {
+
+                /**
+                 * Properties of a RepeatedGroup.
+                 * @memberof jspb.test.TestGroup
+                 * @interface IRepeatedGroup
+                 * @property {string} id RepeatedGroup id
+                 * @property {Array.<boolean>|null} [someBool] RepeatedGroup someBool
+                 */
+
+                /**
+                 * Constructs a new RepeatedGroup.
+                 * @memberof jspb.test.TestGroup
+                 * @classdesc Represents a RepeatedGroup.
+                 * @implements IRepeatedGroup
+                 * @constructor
+                 * @param {jspb.test.TestGroup.IRepeatedGroup=} [properties] Properties to set
+                 */
+                function RepeatedGroup(properties) {
+                    this.someBool = [];
+                    if (properties)
+                        for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                            if (properties[keys[i]] != null)
+                                this[keys[i]] = properties[keys[i]];
+                }
+
+                /**
+                 * RepeatedGroup id.
+                 * @member {string} id
+                 * @memberof jspb.test.TestGroup.RepeatedGroup
+                 * @instance
+                 */
+                RepeatedGroup.prototype.id = "";
+
+                /**
+                 * RepeatedGroup someBool.
+                 * @member {Array.<boolean>} someBool
+                 * @memberof jspb.test.TestGroup.RepeatedGroup
+                 * @instance
+                 */
+                RepeatedGroup.prototype.someBool = $util.emptyArray;
+
+                /**
+                 * Creates a new RepeatedGroup instance using the specified properties.
+                 * @function create
+                 * @memberof jspb.test.TestGroup.RepeatedGroup
+                 * @static
+                 * @param {jspb.test.TestGroup.IRepeatedGroup=} [properties] Properties to set
+                 * @returns {jspb.test.TestGroup.RepeatedGroup} RepeatedGroup instance
+                 */
+                RepeatedGroup.create = function create(properties) {
+                    return new RepeatedGroup(properties);
+                };
+
+                /**
+                 * Encodes the specified RepeatedGroup message. Does not implicitly {@link jspb.test.TestGroup.RepeatedGroup.verify|verify} messages.
+                 * @function encode
+                 * @memberof jspb.test.TestGroup.RepeatedGroup
+                 * @static
+                 * @param {jspb.test.TestGroup.IRepeatedGroup} message RepeatedGroup message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                RepeatedGroup.encode = function encode(message, writer) {
+                    if (!writer)
+                        writer = $Writer.create();
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.id);
+                    if (message.someBool != null && message.someBool.length)
+                        for (var i = 0; i < message.someBool.length; ++i)
+                            writer.uint32(/* id 2, wireType 0 =*/16).bool(message.someBool[i]);
+                    return writer;
+                };
+
+                /**
+                 * Encodes the specified RepeatedGroup message, length delimited. Does not implicitly {@link jspb.test.TestGroup.RepeatedGroup.verify|verify} messages.
+                 * @function encodeDelimited
+                 * @memberof jspb.test.TestGroup.RepeatedGroup
+                 * @static
+                 * @param {jspb.test.TestGroup.IRepeatedGroup} message RepeatedGroup message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                RepeatedGroup.encodeDelimited = function encodeDelimited(message, writer) {
+                    return this.encode(message, writer).ldelim();
+                };
+
+                /**
+                 * Decodes a RepeatedGroup message from the specified reader or buffer.
+                 * @function decode
+                 * @memberof jspb.test.TestGroup.RepeatedGroup
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @param {number} [length] Message length if known beforehand
+                 * @returns {jspb.test.TestGroup.RepeatedGroup} RepeatedGroup
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                RepeatedGroup.decode = function decode(reader, length) {
+                    if (!(reader instanceof $Reader))
+                        reader = $Reader.create(reader);
+                    var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.TestGroup.RepeatedGroup();
+                    while (reader.pos < end) {
+                        var tag = reader.uint32();
+                        if ((tag & 7) === 4)
+                            break;
+                        switch (tag >>> 3) {
+                        case 1:
+                            message.id = reader.string();
+                            break;
+                        case 2:
+                            if (!(message.someBool && message.someBool.length))
+                                message.someBool = [];
+                            if ((tag & 7) === 2) {
+                                var end2 = reader.uint32() + reader.pos;
+                                while (reader.pos < end2)
+                                    message.someBool.push(reader.bool());
+                            } else
+                                message.someBool.push(reader.bool());
+                            break;
+                        default:
+                            reader.skipType(tag & 7);
+                            break;
+                        }
+                    }
+                    if (!message.hasOwnProperty("id"))
+                        throw $util.ProtocolError("missing required 'id'", { instance: message });
+                    return message;
+                };
+
+                /**
+                 * Decodes a RepeatedGroup message from the specified reader or buffer, length delimited.
+                 * @function decodeDelimited
+                 * @memberof jspb.test.TestGroup.RepeatedGroup
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @returns {jspb.test.TestGroup.RepeatedGroup} RepeatedGroup
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                RepeatedGroup.decodeDelimited = function decodeDelimited(reader) {
+                    if (!(reader instanceof $Reader))
+                        reader = new $Reader(reader);
+                    return this.decode(reader, reader.uint32());
+                };
+
+                /**
+                 * Verifies a RepeatedGroup message.
+                 * @function verify
+                 * @memberof jspb.test.TestGroup.RepeatedGroup
+                 * @static
+                 * @param {Object.<string,*>} message Plain object to verify
+                 * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                 */
+                RepeatedGroup.verify = function verify(message) {
+                    if (typeof message !== "object" || message === null)
+                        return "object expected";
+                    if (!$util.isString(message.id))
+                        return "id: string expected";
+                    if (message.someBool != null && message.hasOwnProperty("someBool")) {
+                        if (!Array.isArray(message.someBool))
+                            return "someBool: array expected";
+                        for (var i = 0; i < message.someBool.length; ++i)
+                            if (typeof message.someBool[i] !== "boolean")
+                                return "someBool: boolean[] expected";
+                    }
+                    return null;
+                };
+
+                /**
+                 * Creates a RepeatedGroup message from a plain object. Also converts values to their respective internal types.
+                 * @function fromObject
+                 * @memberof jspb.test.TestGroup.RepeatedGroup
+                 * @static
+                 * @param {Object.<string,*>} object Plain object
+                 * @returns {jspb.test.TestGroup.RepeatedGroup} RepeatedGroup
+                 */
+                RepeatedGroup.fromObject = function fromObject(object) {
+                    if (object instanceof $root.jspb.test.TestGroup.RepeatedGroup)
+                        return object;
+                    var message = new $root.jspb.test.TestGroup.RepeatedGroup();
+                    if (object.id != null)
+                        message.id = String(object.id);
+                    if (object.someBool) {
+                        if (!Array.isArray(object.someBool))
+                            throw TypeError(".jspb.test.TestGroup.RepeatedGroup.someBool: array expected");
+                        message.someBool = [];
+                        for (var i = 0; i < object.someBool.length; ++i)
+                            message.someBool[i] = Boolean(object.someBool[i]);
+                    }
+                    return message;
+                };
+
+                /**
+                 * Creates a plain object from a RepeatedGroup message. Also converts values to other types if specified.
+                 * @function toObject
+                 * @memberof jspb.test.TestGroup.RepeatedGroup
+                 * @static
+                 * @param {jspb.test.TestGroup.RepeatedGroup} message RepeatedGroup
+                 * @param {$protobuf.IConversionOptions} [options] Conversion options
+                 * @returns {Object.<string,*>} Plain object
+                 */
+                RepeatedGroup.toObject = function toObject(message, options) {
+                    if (!options)
+                        options = {};
+                    var object = {};
+                    if (options.arrays || options.defaults)
+                        object.someBool = [];
+                    if (options.defaults)
+                        object.id = "";
+                    if (message.id != null && message.hasOwnProperty("id"))
+                        object.id = message.id;
+                    if (message.someBool && message.someBool.length) {
+                        object.someBool = [];
+                        for (var j = 0; j < message.someBool.length; ++j)
+                            object.someBool[j] = message.someBool[j];
+                    }
+                    return object;
+                };
+
+                /**
+                 * Converts this RepeatedGroup to JSON.
+                 * @function toJSON
+                 * @memberof jspb.test.TestGroup.RepeatedGroup
+                 * @instance
+                 * @returns {Object.<string,*>} JSON object
+                 */
+                RepeatedGroup.prototype.toJSON = function toJSON() {
+                    return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                };
+
+                /**
+                 * Gets the default type url for RepeatedGroup
+                 * @function getTypeUrl
+                 * @memberof jspb.test.TestGroup.RepeatedGroup
+                 * @static
+                 * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                 * @returns {string} The default type url
+                 */
+                RepeatedGroup.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                    if (typeUrlPrefix === undefined) {
+                        typeUrlPrefix = "type.googleapis.com";
+                    }
+                    return typeUrlPrefix + "/jspb.test.TestGroup.RepeatedGroup";
+                };
+
+                return RepeatedGroup;
+            })();
+
+            TestGroup.RequiredGroup = (function() {
+
+                /**
+                 * Properties of a RequiredGroup.
+                 * @memberof jspb.test.TestGroup
+                 * @interface IRequiredGroup
+                 * @property {string} id RequiredGroup id
+                 */
+
+                /**
+                 * Constructs a new RequiredGroup.
+                 * @memberof jspb.test.TestGroup
+                 * @classdesc Represents a RequiredGroup.
+                 * @implements IRequiredGroup
+                 * @constructor
+                 * @param {jspb.test.TestGroup.IRequiredGroup=} [properties] Properties to set
+                 */
+                function RequiredGroup(properties) {
+                    if (properties)
+                        for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                            if (properties[keys[i]] != null)
+                                this[keys[i]] = properties[keys[i]];
+                }
+
+                /**
+                 * RequiredGroup id.
+                 * @member {string} id
+                 * @memberof jspb.test.TestGroup.RequiredGroup
+                 * @instance
+                 */
+                RequiredGroup.prototype.id = "";
+
+                /**
+                 * Creates a new RequiredGroup instance using the specified properties.
+                 * @function create
+                 * @memberof jspb.test.TestGroup.RequiredGroup
+                 * @static
+                 * @param {jspb.test.TestGroup.IRequiredGroup=} [properties] Properties to set
+                 * @returns {jspb.test.TestGroup.RequiredGroup} RequiredGroup instance
+                 */
+                RequiredGroup.create = function create(properties) {
+                    return new RequiredGroup(properties);
+                };
+
+                /**
+                 * Encodes the specified RequiredGroup message. Does not implicitly {@link jspb.test.TestGroup.RequiredGroup.verify|verify} messages.
+                 * @function encode
+                 * @memberof jspb.test.TestGroup.RequiredGroup
+                 * @static
+                 * @param {jspb.test.TestGroup.IRequiredGroup} message RequiredGroup message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                RequiredGroup.encode = function encode(message, writer) {
+                    if (!writer)
+                        writer = $Writer.create();
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.id);
+                    return writer;
+                };
+
+                /**
+                 * Encodes the specified RequiredGroup message, length delimited. Does not implicitly {@link jspb.test.TestGroup.RequiredGroup.verify|verify} messages.
+                 * @function encodeDelimited
+                 * @memberof jspb.test.TestGroup.RequiredGroup
+                 * @static
+                 * @param {jspb.test.TestGroup.IRequiredGroup} message RequiredGroup message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                RequiredGroup.encodeDelimited = function encodeDelimited(message, writer) {
+                    return this.encode(message, writer).ldelim();
+                };
+
+                /**
+                 * Decodes a RequiredGroup message from the specified reader or buffer.
+                 * @function decode
+                 * @memberof jspb.test.TestGroup.RequiredGroup
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @param {number} [length] Message length if known beforehand
+                 * @returns {jspb.test.TestGroup.RequiredGroup} RequiredGroup
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                RequiredGroup.decode = function decode(reader, length) {
+                    if (!(reader instanceof $Reader))
+                        reader = $Reader.create(reader);
+                    var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.TestGroup.RequiredGroup();
+                    while (reader.pos < end) {
+                        var tag = reader.uint32();
+                        if ((tag & 7) === 4)
+                            break;
+                        switch (tag >>> 3) {
+                        case 1:
+                            message.id = reader.string();
+                            break;
+                        default:
+                            reader.skipType(tag & 7);
+                            break;
+                        }
+                    }
+                    if (!message.hasOwnProperty("id"))
+                        throw $util.ProtocolError("missing required 'id'", { instance: message });
+                    return message;
+                };
+
+                /**
+                 * Decodes a RequiredGroup message from the specified reader or buffer, length delimited.
+                 * @function decodeDelimited
+                 * @memberof jspb.test.TestGroup.RequiredGroup
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @returns {jspb.test.TestGroup.RequiredGroup} RequiredGroup
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                RequiredGroup.decodeDelimited = function decodeDelimited(reader) {
+                    if (!(reader instanceof $Reader))
+                        reader = new $Reader(reader);
+                    return this.decode(reader, reader.uint32());
+                };
+
+                /**
+                 * Verifies a RequiredGroup message.
+                 * @function verify
+                 * @memberof jspb.test.TestGroup.RequiredGroup
+                 * @static
+                 * @param {Object.<string,*>} message Plain object to verify
+                 * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                 */
+                RequiredGroup.verify = function verify(message) {
+                    if (typeof message !== "object" || message === null)
+                        return "object expected";
+                    if (!$util.isString(message.id))
+                        return "id: string expected";
+                    return null;
+                };
+
+                /**
+                 * Creates a RequiredGroup message from a plain object. Also converts values to their respective internal types.
+                 * @function fromObject
+                 * @memberof jspb.test.TestGroup.RequiredGroup
+                 * @static
+                 * @param {Object.<string,*>} object Plain object
+                 * @returns {jspb.test.TestGroup.RequiredGroup} RequiredGroup
+                 */
+                RequiredGroup.fromObject = function fromObject(object) {
+                    if (object instanceof $root.jspb.test.TestGroup.RequiredGroup)
+                        return object;
+                    var message = new $root.jspb.test.TestGroup.RequiredGroup();
+                    if (object.id != null)
+                        message.id = String(object.id);
+                    return message;
+                };
+
+                /**
+                 * Creates a plain object from a RequiredGroup message. Also converts values to other types if specified.
+                 * @function toObject
+                 * @memberof jspb.test.TestGroup.RequiredGroup
+                 * @static
+                 * @param {jspb.test.TestGroup.RequiredGroup} message RequiredGroup
+                 * @param {$protobuf.IConversionOptions} [options] Conversion options
+                 * @returns {Object.<string,*>} Plain object
+                 */
+                RequiredGroup.toObject = function toObject(message, options) {
+                    if (!options)
+                        options = {};
+                    var object = {};
+                    if (options.defaults)
+                        object.id = "";
+                    if (message.id != null && message.hasOwnProperty("id"))
+                        object.id = message.id;
+                    return object;
+                };
+
+                /**
+                 * Converts this RequiredGroup to JSON.
+                 * @function toJSON
+                 * @memberof jspb.test.TestGroup.RequiredGroup
+                 * @instance
+                 * @returns {Object.<string,*>} JSON object
+                 */
+                RequiredGroup.prototype.toJSON = function toJSON() {
+                    return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                };
+
+                /**
+                 * Gets the default type url for RequiredGroup
+                 * @function getTypeUrl
+                 * @memberof jspb.test.TestGroup.RequiredGroup
+                 * @static
+                 * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                 * @returns {string} The default type url
+                 */
+                RequiredGroup.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                    if (typeUrlPrefix === undefined) {
+                        typeUrlPrefix = "type.googleapis.com";
+                    }
+                    return typeUrlPrefix + "/jspb.test.TestGroup.RequiredGroup";
+                };
+
+                return RequiredGroup;
+            })();
+
+            TestGroup.OptionalGroup = (function() {
+
+                /**
+                 * Properties of an OptionalGroup.
+                 * @memberof jspb.test.TestGroup
+                 * @interface IOptionalGroup
+                 * @property {string} id OptionalGroup id
+                 */
+
+                /**
+                 * Constructs a new OptionalGroup.
+                 * @memberof jspb.test.TestGroup
+                 * @classdesc Represents an OptionalGroup.
+                 * @implements IOptionalGroup
+                 * @constructor
+                 * @param {jspb.test.TestGroup.IOptionalGroup=} [properties] Properties to set
+                 */
+                function OptionalGroup(properties) {
+                    if (properties)
+                        for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                            if (properties[keys[i]] != null)
+                                this[keys[i]] = properties[keys[i]];
+                }
+
+                /**
+                 * OptionalGroup id.
+                 * @member {string} id
+                 * @memberof jspb.test.TestGroup.OptionalGroup
+                 * @instance
+                 */
+                OptionalGroup.prototype.id = "";
+
+                /**
+                 * Creates a new OptionalGroup instance using the specified properties.
+                 * @function create
+                 * @memberof jspb.test.TestGroup.OptionalGroup
+                 * @static
+                 * @param {jspb.test.TestGroup.IOptionalGroup=} [properties] Properties to set
+                 * @returns {jspb.test.TestGroup.OptionalGroup} OptionalGroup instance
+                 */
+                OptionalGroup.create = function create(properties) {
+                    return new OptionalGroup(properties);
+                };
+
+                /**
+                 * Encodes the specified OptionalGroup message. Does not implicitly {@link jspb.test.TestGroup.OptionalGroup.verify|verify} messages.
+                 * @function encode
+                 * @memberof jspb.test.TestGroup.OptionalGroup
+                 * @static
+                 * @param {jspb.test.TestGroup.IOptionalGroup} message OptionalGroup message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                OptionalGroup.encode = function encode(message, writer) {
+                    if (!writer)
+                        writer = $Writer.create();
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.id);
+                    return writer;
+                };
+
+                /**
+                 * Encodes the specified OptionalGroup message, length delimited. Does not implicitly {@link jspb.test.TestGroup.OptionalGroup.verify|verify} messages.
+                 * @function encodeDelimited
+                 * @memberof jspb.test.TestGroup.OptionalGroup
+                 * @static
+                 * @param {jspb.test.TestGroup.IOptionalGroup} message OptionalGroup message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                OptionalGroup.encodeDelimited = function encodeDelimited(message, writer) {
+                    return this.encode(message, writer).ldelim();
+                };
+
+                /**
+                 * Decodes an OptionalGroup message from the specified reader or buffer.
+                 * @function decode
+                 * @memberof jspb.test.TestGroup.OptionalGroup
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @param {number} [length] Message length if known beforehand
+                 * @returns {jspb.test.TestGroup.OptionalGroup} OptionalGroup
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                OptionalGroup.decode = function decode(reader, length) {
+                    if (!(reader instanceof $Reader))
+                        reader = $Reader.create(reader);
+                    var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.TestGroup.OptionalGroup();
+                    while (reader.pos < end) {
+                        var tag = reader.uint32();
+                        if ((tag & 7) === 4)
+                            break;
+                        switch (tag >>> 3) {
+                        case 1:
+                            message.id = reader.string();
+                            break;
+                        default:
+                            reader.skipType(tag & 7);
+                            break;
+                        }
+                    }
+                    if (!message.hasOwnProperty("id"))
+                        throw $util.ProtocolError("missing required 'id'", { instance: message });
+                    return message;
+                };
+
+                /**
+                 * Decodes an OptionalGroup message from the specified reader or buffer, length delimited.
+                 * @function decodeDelimited
+                 * @memberof jspb.test.TestGroup.OptionalGroup
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @returns {jspb.test.TestGroup.OptionalGroup} OptionalGroup
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                OptionalGroup.decodeDelimited = function decodeDelimited(reader) {
+                    if (!(reader instanceof $Reader))
+                        reader = new $Reader(reader);
+                    return this.decode(reader, reader.uint32());
+                };
+
+                /**
+                 * Verifies an OptionalGroup message.
+                 * @function verify
+                 * @memberof jspb.test.TestGroup.OptionalGroup
+                 * @static
+                 * @param {Object.<string,*>} message Plain object to verify
+                 * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                 */
+                OptionalGroup.verify = function verify(message) {
+                    if (typeof message !== "object" || message === null)
+                        return "object expected";
+                    if (!$util.isString(message.id))
+                        return "id: string expected";
+                    return null;
+                };
+
+                /**
+                 * Creates an OptionalGroup message from a plain object. Also converts values to their respective internal types.
+                 * @function fromObject
+                 * @memberof jspb.test.TestGroup.OptionalGroup
+                 * @static
+                 * @param {Object.<string,*>} object Plain object
+                 * @returns {jspb.test.TestGroup.OptionalGroup} OptionalGroup
+                 */
+                OptionalGroup.fromObject = function fromObject(object) {
+                    if (object instanceof $root.jspb.test.TestGroup.OptionalGroup)
+                        return object;
+                    var message = new $root.jspb.test.TestGroup.OptionalGroup();
+                    if (object.id != null)
+                        message.id = String(object.id);
+                    return message;
+                };
+
+                /**
+                 * Creates a plain object from an OptionalGroup message. Also converts values to other types if specified.
+                 * @function toObject
+                 * @memberof jspb.test.TestGroup.OptionalGroup
+                 * @static
+                 * @param {jspb.test.TestGroup.OptionalGroup} message OptionalGroup
+                 * @param {$protobuf.IConversionOptions} [options] Conversion options
+                 * @returns {Object.<string,*>} Plain object
+                 */
+                OptionalGroup.toObject = function toObject(message, options) {
+                    if (!options)
+                        options = {};
+                    var object = {};
+                    if (options.defaults)
+                        object.id = "";
+                    if (message.id != null && message.hasOwnProperty("id"))
+                        object.id = message.id;
+                    return object;
+                };
+
+                /**
+                 * Converts this OptionalGroup to JSON.
+                 * @function toJSON
+                 * @memberof jspb.test.TestGroup.OptionalGroup
+                 * @instance
+                 * @returns {Object.<string,*>} JSON object
+                 */
+                OptionalGroup.prototype.toJSON = function toJSON() {
+                    return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                };
+
+                /**
+                 * Gets the default type url for OptionalGroup
+                 * @function getTypeUrl
+                 * @memberof jspb.test.TestGroup.OptionalGroup
+                 * @static
+                 * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                 * @returns {string} The default type url
+                 */
+                OptionalGroup.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                    if (typeUrlPrefix === undefined) {
+                        typeUrlPrefix = "type.googleapis.com";
+                    }
+                    return typeUrlPrefix + "/jspb.test.TestGroup.OptionalGroup";
+                };
+
+                return OptionalGroup;
+            })();
+
+            return TestGroup;
+        })();
+
+        test.TestGroup1 = (function() {
+
+            /**
+             * Properties of a TestGroup1.
+             * @memberof jspb.test
+             * @interface ITestGroup1
+             * @property {jspb.test.TestGroup.IRepeatedGroup|null} [group] TestGroup1 group
+             */
+
+            /**
+             * Constructs a new TestGroup1.
+             * @memberof jspb.test
+             * @classdesc Represents a TestGroup1.
+             * @implements ITestGroup1
+             * @constructor
+             * @param {jspb.test.ITestGroup1=} [properties] Properties to set
+             */
+            function TestGroup1(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * TestGroup1 group.
+             * @member {jspb.test.TestGroup.IRepeatedGroup|null|undefined} group
+             * @memberof jspb.test.TestGroup1
+             * @instance
+             */
+            TestGroup1.prototype.group = null;
+
+            /**
+             * Creates a new TestGroup1 instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.TestGroup1
+             * @static
+             * @param {jspb.test.ITestGroup1=} [properties] Properties to set
+             * @returns {jspb.test.TestGroup1} TestGroup1 instance
+             */
+            TestGroup1.create = function create(properties) {
+                return new TestGroup1(properties);
+            };
+
+            /**
+             * Encodes the specified TestGroup1 message. Does not implicitly {@link jspb.test.TestGroup1.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.TestGroup1
+             * @static
+             * @param {jspb.test.ITestGroup1} message TestGroup1 message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestGroup1.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.group != null && Object.hasOwnProperty.call(message, "group"))
+                    $root.jspb.test.TestGroup.RepeatedGroup.encode(message.group, writer.uint32(/* id 1, wireType 3 =*/11)).uint32(/* id 1, wireType 4 =*/12);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified TestGroup1 message, length delimited. Does not implicitly {@link jspb.test.TestGroup1.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.TestGroup1
+             * @static
+             * @param {jspb.test.ITestGroup1} message TestGroup1 message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestGroup1.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a TestGroup1 message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.TestGroup1
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.TestGroup1} TestGroup1
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestGroup1.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.TestGroup1();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.group = $root.jspb.test.TestGroup.RepeatedGroup.decode(reader);
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a TestGroup1 message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.TestGroup1
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.TestGroup1} TestGroup1
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestGroup1.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a TestGroup1 message.
+             * @function verify
+             * @memberof jspb.test.TestGroup1
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            TestGroup1.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.group != null && message.hasOwnProperty("group")) {
+                    var error = $root.jspb.test.TestGroup.RepeatedGroup.verify(message.group);
+                    if (error)
+                        return "group." + error;
+                }
+                return null;
+            };
+
+            /**
+             * Creates a TestGroup1 message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.TestGroup1
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.TestGroup1} TestGroup1
+             */
+            TestGroup1.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.TestGroup1)
+                    return object;
+                var message = new $root.jspb.test.TestGroup1();
+                if (object.group != null) {
+                    if (typeof object.group !== "object")
+                        throw TypeError(".jspb.test.TestGroup1.group: object expected");
+                    message.group = $root.jspb.test.TestGroup.RepeatedGroup.fromObject(object.group);
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a TestGroup1 message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.TestGroup1
+             * @static
+             * @param {jspb.test.TestGroup1} message TestGroup1
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            TestGroup1.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults)
+                    object.group = null;
+                if (message.group != null && message.hasOwnProperty("group"))
+                    object.group = $root.jspb.test.TestGroup.RepeatedGroup.toObject(message.group, options);
+                return object;
+            };
+
+            /**
+             * Converts this TestGroup1 to JSON.
+             * @function toJSON
+             * @memberof jspb.test.TestGroup1
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            TestGroup1.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for TestGroup1
+             * @function getTypeUrl
+             * @memberof jspb.test.TestGroup1
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            TestGroup1.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.TestGroup1";
+            };
+
+            return TestGroup1;
+        })();
+
+        test.TestReservedNames = (function() {
+
+            /**
+             * Properties of a TestReservedNames.
+             * @memberof jspb.test
+             * @interface ITestReservedNames
+             * @property {number|null} [extension] TestReservedNames extension
+             * @property {number|null} [".jspb.test.TestReservedNamesExtension.foo"] TestReservedNames .jspb.test.TestReservedNamesExtension.foo
+             */
+
+            /**
+             * Constructs a new TestReservedNames.
+             * @memberof jspb.test
+             * @classdesc Represents a TestReservedNames.
+             * @implements ITestReservedNames
+             * @constructor
+             * @param {jspb.test.ITestReservedNames=} [properties] Properties to set
+             */
+            function TestReservedNames(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * TestReservedNames extension.
+             * @member {number} extension
+             * @memberof jspb.test.TestReservedNames
+             * @instance
+             */
+            TestReservedNames.prototype.extension = 0;
+
+            /**
+             * TestReservedNames .jspb.test.TestReservedNamesExtension.foo.
+             * @member {number} .jspb.test.TestReservedNamesExtension.foo
+             * @memberof jspb.test.TestReservedNames
+             * @instance
+             */
+            TestReservedNames.prototype[".jspb.test.TestReservedNamesExtension.foo"] = 0;
+
+            /**
+             * Creates a new TestReservedNames instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.TestReservedNames
+             * @static
+             * @param {jspb.test.ITestReservedNames=} [properties] Properties to set
+             * @returns {jspb.test.TestReservedNames} TestReservedNames instance
+             */
+            TestReservedNames.create = function create(properties) {
+                return new TestReservedNames(properties);
+            };
+
+            /**
+             * Encodes the specified TestReservedNames message. Does not implicitly {@link jspb.test.TestReservedNames.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.TestReservedNames
+             * @static
+             * @param {jspb.test.ITestReservedNames} message TestReservedNames message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestReservedNames.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.extension != null && Object.hasOwnProperty.call(message, "extension"))
+                    writer.uint32(/* id 1, wireType 0 =*/8).int32(message.extension);
+                if (message[".jspb.test.TestReservedNamesExtension.foo"] != null && Object.hasOwnProperty.call(message, ".jspb.test.TestReservedNamesExtension.foo"))
+                    writer.uint32(/* id 10, wireType 0 =*/80).int32(message[".jspb.test.TestReservedNamesExtension.foo"]);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified TestReservedNames message, length delimited. Does not implicitly {@link jspb.test.TestReservedNames.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.TestReservedNames
+             * @static
+             * @param {jspb.test.ITestReservedNames} message TestReservedNames message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestReservedNames.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a TestReservedNames message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.TestReservedNames
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.TestReservedNames} TestReservedNames
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestReservedNames.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.TestReservedNames();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.extension = reader.int32();
+                        break;
+                    case 10:
+                        message[".jspb.test.TestReservedNamesExtension.foo"] = reader.int32();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a TestReservedNames message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.TestReservedNames
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.TestReservedNames} TestReservedNames
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestReservedNames.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a TestReservedNames message.
+             * @function verify
+             * @memberof jspb.test.TestReservedNames
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            TestReservedNames.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.extension != null && message.hasOwnProperty("extension"))
+                    if (!$util.isInteger(message.extension))
+                        return "extension: integer expected";
+                if (message[".jspb.test.TestReservedNamesExtension.foo"] != null && message.hasOwnProperty(".jspb.test.TestReservedNamesExtension.foo"))
+                    if (!$util.isInteger(message[".jspb.test.TestReservedNamesExtension.foo"]))
+                        return ".jspb.test.TestReservedNamesExtension.foo: integer expected";
+                return null;
+            };
+
+            /**
+             * Creates a TestReservedNames message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.TestReservedNames
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.TestReservedNames} TestReservedNames
+             */
+            TestReservedNames.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.TestReservedNames)
+                    return object;
+                var message = new $root.jspb.test.TestReservedNames();
+                if (object.extension != null)
+                    message.extension = object.extension | 0;
+                if (object[".jspb.test.TestReservedNamesExtension.foo"] != null)
+                    message[".jspb.test.TestReservedNamesExtension.foo"] = object[".jspb.test.TestReservedNamesExtension.foo"] | 0;
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a TestReservedNames message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.TestReservedNames
+             * @static
+             * @param {jspb.test.TestReservedNames} message TestReservedNames
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            TestReservedNames.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults) {
+                    object.extension = 0;
+                    object[".jspb.test.TestReservedNamesExtension.foo"] = 0;
+                }
+                if (message.extension != null && message.hasOwnProperty("extension"))
+                    object.extension = message.extension;
+                if (message[".jspb.test.TestReservedNamesExtension.foo"] != null && message.hasOwnProperty(".jspb.test.TestReservedNamesExtension.foo"))
+                    object[".jspb.test.TestReservedNamesExtension.foo"] = message[".jspb.test.TestReservedNamesExtension.foo"];
+                return object;
+            };
+
+            /**
+             * Converts this TestReservedNames to JSON.
+             * @function toJSON
+             * @memberof jspb.test.TestReservedNames
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            TestReservedNames.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for TestReservedNames
+             * @function getTypeUrl
+             * @memberof jspb.test.TestReservedNames
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            TestReservedNames.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.TestReservedNames";
+            };
+
+            return TestReservedNames;
+        })();
+
+        test.TestReservedNamesExtension = (function() {
+
+            /**
+             * Properties of a TestReservedNamesExtension.
+             * @memberof jspb.test
+             * @interface ITestReservedNamesExtension
+             */
+
+            /**
+             * Constructs a new TestReservedNamesExtension.
+             * @memberof jspb.test
+             * @classdesc Represents a TestReservedNamesExtension.
+             * @implements ITestReservedNamesExtension
+             * @constructor
+             * @param {jspb.test.ITestReservedNamesExtension=} [properties] Properties to set
+             */
+            function TestReservedNamesExtension(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * Creates a new TestReservedNamesExtension instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.TestReservedNamesExtension
+             * @static
+             * @param {jspb.test.ITestReservedNamesExtension=} [properties] Properties to set
+             * @returns {jspb.test.TestReservedNamesExtension} TestReservedNamesExtension instance
+             */
+            TestReservedNamesExtension.create = function create(properties) {
+                return new TestReservedNamesExtension(properties);
+            };
+
+            /**
+             * Encodes the specified TestReservedNamesExtension message. Does not implicitly {@link jspb.test.TestReservedNamesExtension.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.TestReservedNamesExtension
+             * @static
+             * @param {jspb.test.ITestReservedNamesExtension} message TestReservedNamesExtension message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestReservedNamesExtension.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified TestReservedNamesExtension message, length delimited. Does not implicitly {@link jspb.test.TestReservedNamesExtension.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.TestReservedNamesExtension
+             * @static
+             * @param {jspb.test.ITestReservedNamesExtension} message TestReservedNamesExtension message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestReservedNamesExtension.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a TestReservedNamesExtension message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.TestReservedNamesExtension
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.TestReservedNamesExtension} TestReservedNamesExtension
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestReservedNamesExtension.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.TestReservedNamesExtension();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a TestReservedNamesExtension message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.TestReservedNamesExtension
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.TestReservedNamesExtension} TestReservedNamesExtension
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestReservedNamesExtension.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a TestReservedNamesExtension message.
+             * @function verify
+             * @memberof jspb.test.TestReservedNamesExtension
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            TestReservedNamesExtension.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                return null;
+            };
+
+            /**
+             * Creates a TestReservedNamesExtension message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.TestReservedNamesExtension
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.TestReservedNamesExtension} TestReservedNamesExtension
+             */
+            TestReservedNamesExtension.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.TestReservedNamesExtension)
+                    return object;
+                return new $root.jspb.test.TestReservedNamesExtension();
+            };
+
+            /**
+             * Creates a plain object from a TestReservedNamesExtension message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.TestReservedNamesExtension
+             * @static
+             * @param {jspb.test.TestReservedNamesExtension} message TestReservedNamesExtension
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            TestReservedNamesExtension.toObject = function toObject() {
+                return {};
+            };
+
+            /**
+             * Converts this TestReservedNamesExtension to JSON.
+             * @function toJSON
+             * @memberof jspb.test.TestReservedNamesExtension
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            TestReservedNamesExtension.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for TestReservedNamesExtension
+             * @function getTypeUrl
+             * @memberof jspb.test.TestReservedNamesExtension
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            TestReservedNamesExtension.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.TestReservedNamesExtension";
+            };
+
+            return TestReservedNamesExtension;
+        })();
+
+        test.TestMessageWithOneof = (function() {
+
+            /**
+             * Properties of a TestMessageWithOneof.
+             * @memberof jspb.test
+             * @interface ITestMessageWithOneof
+             * @property {string|null} [pone] TestMessageWithOneof pone
+             * @property {string|null} [pthree] TestMessageWithOneof pthree
+             * @property {jspb.test.ITestMessageWithOneof|null} [rone] TestMessageWithOneof rone
+             * @property {string|null} [rtwo] TestMessageWithOneof rtwo
+             * @property {boolean|null} [normalField] TestMessageWithOneof normalField
+             * @property {Array.<string>|null} [repeatedField] TestMessageWithOneof repeatedField
+             * @property {number|null} [aone] TestMessageWithOneof aone
+             * @property {number|null} [atwo] TestMessageWithOneof atwo
+             * @property {number|null} [bone] TestMessageWithOneof bone
+             * @property {number|null} [btwo] TestMessageWithOneof btwo
+             */
+
+            /**
+             * Constructs a new TestMessageWithOneof.
+             * @memberof jspb.test
+             * @classdesc Represents a TestMessageWithOneof.
+             * @implements ITestMessageWithOneof
+             * @constructor
+             * @param {jspb.test.ITestMessageWithOneof=} [properties] Properties to set
+             */
+            function TestMessageWithOneof(properties) {
+                this.repeatedField = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * TestMessageWithOneof pone.
+             * @member {string|null|undefined} pone
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            TestMessageWithOneof.prototype.pone = null;
+
+            /**
+             * TestMessageWithOneof pthree.
+             * @member {string|null|undefined} pthree
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            TestMessageWithOneof.prototype.pthree = null;
+
+            /**
+             * TestMessageWithOneof rone.
+             * @member {jspb.test.ITestMessageWithOneof|null|undefined} rone
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            TestMessageWithOneof.prototype.rone = null;
+
+            /**
+             * TestMessageWithOneof rtwo.
+             * @member {string|null|undefined} rtwo
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            TestMessageWithOneof.prototype.rtwo = null;
+
+            /**
+             * TestMessageWithOneof normalField.
+             * @member {boolean} normalField
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            TestMessageWithOneof.prototype.normalField = false;
+
+            /**
+             * TestMessageWithOneof repeatedField.
+             * @member {Array.<string>} repeatedField
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            TestMessageWithOneof.prototype.repeatedField = $util.emptyArray;
+
+            /**
+             * TestMessageWithOneof aone.
+             * @member {number|null|undefined} aone
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            TestMessageWithOneof.prototype.aone = null;
+
+            /**
+             * TestMessageWithOneof atwo.
+             * @member {number|null|undefined} atwo
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            TestMessageWithOneof.prototype.atwo = null;
+
+            /**
+             * TestMessageWithOneof bone.
+             * @member {number|null|undefined} bone
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            TestMessageWithOneof.prototype.bone = null;
+
+            /**
+             * TestMessageWithOneof btwo.
+             * @member {number|null|undefined} btwo
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            TestMessageWithOneof.prototype.btwo = null;
+
+            // OneOf field names bound to virtual getters and setters
+            var $oneOfFields;
+
+            /**
+             * TestMessageWithOneof partialOneof.
+             * @member {"pone"|"pthree"|undefined} partialOneof
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            Object.defineProperty(TestMessageWithOneof.prototype, "partialOneof", {
+                get: $util.oneOfGetter($oneOfFields = ["pone", "pthree"]),
+                set: $util.oneOfSetter($oneOfFields)
+            });
+
+            /**
+             * TestMessageWithOneof recursiveOneof.
+             * @member {"rone"|"rtwo"|undefined} recursiveOneof
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            Object.defineProperty(TestMessageWithOneof.prototype, "recursiveOneof", {
+                get: $util.oneOfGetter($oneOfFields = ["rone", "rtwo"]),
+                set: $util.oneOfSetter($oneOfFields)
+            });
+
+            /**
+             * TestMessageWithOneof defaultOneofA.
+             * @member {"aone"|"atwo"|undefined} defaultOneofA
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            Object.defineProperty(TestMessageWithOneof.prototype, "defaultOneofA", {
+                get: $util.oneOfGetter($oneOfFields = ["aone", "atwo"]),
+                set: $util.oneOfSetter($oneOfFields)
+            });
+
+            /**
+             * TestMessageWithOneof defaultOneofB.
+             * @member {"bone"|"btwo"|undefined} defaultOneofB
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             */
+            Object.defineProperty(TestMessageWithOneof.prototype, "defaultOneofB", {
+                get: $util.oneOfGetter($oneOfFields = ["bone", "btwo"]),
+                set: $util.oneOfSetter($oneOfFields)
+            });
+
+            /**
+             * Creates a new TestMessageWithOneof instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.TestMessageWithOneof
+             * @static
+             * @param {jspb.test.ITestMessageWithOneof=} [properties] Properties to set
+             * @returns {jspb.test.TestMessageWithOneof} TestMessageWithOneof instance
+             */
+            TestMessageWithOneof.create = function create(properties) {
+                return new TestMessageWithOneof(properties);
+            };
+
+            /**
+             * Encodes the specified TestMessageWithOneof message. Does not implicitly {@link jspb.test.TestMessageWithOneof.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.TestMessageWithOneof
+             * @static
+             * @param {jspb.test.ITestMessageWithOneof} message TestMessageWithOneof message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestMessageWithOneof.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.pone != null && Object.hasOwnProperty.call(message, "pone"))
+                    writer.uint32(/* id 3, wireType 2 =*/26).string(message.pone);
+                if (message.pthree != null && Object.hasOwnProperty.call(message, "pthree"))
+                    writer.uint32(/* id 5, wireType 2 =*/42).string(message.pthree);
+                if (message.rone != null && Object.hasOwnProperty.call(message, "rone"))
+                    $root.jspb.test.TestMessageWithOneof.encode(message.rone, writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim();
+                if (message.rtwo != null && Object.hasOwnProperty.call(message, "rtwo"))
+                    writer.uint32(/* id 7, wireType 2 =*/58).string(message.rtwo);
+                if (message.normalField != null && Object.hasOwnProperty.call(message, "normalField"))
+                    writer.uint32(/* id 8, wireType 0 =*/64).bool(message.normalField);
+                if (message.repeatedField != null && message.repeatedField.length)
+                    for (var i = 0; i < message.repeatedField.length; ++i)
+                        writer.uint32(/* id 9, wireType 2 =*/74).string(message.repeatedField[i]);
+                if (message.aone != null && Object.hasOwnProperty.call(message, "aone"))
+                    writer.uint32(/* id 10, wireType 0 =*/80).int32(message.aone);
+                if (message.atwo != null && Object.hasOwnProperty.call(message, "atwo"))
+                    writer.uint32(/* id 11, wireType 0 =*/88).int32(message.atwo);
+                if (message.bone != null && Object.hasOwnProperty.call(message, "bone"))
+                    writer.uint32(/* id 12, wireType 0 =*/96).int32(message.bone);
+                if (message.btwo != null && Object.hasOwnProperty.call(message, "btwo"))
+                    writer.uint32(/* id 13, wireType 0 =*/104).int32(message.btwo);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified TestMessageWithOneof message, length delimited. Does not implicitly {@link jspb.test.TestMessageWithOneof.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.TestMessageWithOneof
+             * @static
+             * @param {jspb.test.ITestMessageWithOneof} message TestMessageWithOneof message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestMessageWithOneof.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a TestMessageWithOneof message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.TestMessageWithOneof
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.TestMessageWithOneof} TestMessageWithOneof
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestMessageWithOneof.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.TestMessageWithOneof();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 3:
+                        message.pone = reader.string();
+                        break;
+                    case 5:
+                        message.pthree = reader.string();
+                        break;
+                    case 6:
+                        message.rone = $root.jspb.test.TestMessageWithOneof.decode(reader, reader.uint32());
+                        break;
+                    case 7:
+                        message.rtwo = reader.string();
+                        break;
+                    case 8:
+                        message.normalField = reader.bool();
+                        break;
+                    case 9:
+                        if (!(message.repeatedField && message.repeatedField.length))
+                            message.repeatedField = [];
+                        message.repeatedField.push(reader.string());
+                        break;
+                    case 10:
+                        message.aone = reader.int32();
+                        break;
+                    case 11:
+                        message.atwo = reader.int32();
+                        break;
+                    case 12:
+                        message.bone = reader.int32();
+                        break;
+                    case 13:
+                        message.btwo = reader.int32();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a TestMessageWithOneof message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.TestMessageWithOneof
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.TestMessageWithOneof} TestMessageWithOneof
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestMessageWithOneof.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a TestMessageWithOneof message.
+             * @function verify
+             * @memberof jspb.test.TestMessageWithOneof
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            TestMessageWithOneof.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                var properties = {};
+                if (message.pone != null && message.hasOwnProperty("pone")) {
+                    properties.partialOneof = 1;
+                    if (!$util.isString(message.pone))
+                        return "pone: string expected";
+                }
+                if (message.pthree != null && message.hasOwnProperty("pthree")) {
+                    if (properties.partialOneof === 1)
+                        return "partialOneof: multiple values";
+                    properties.partialOneof = 1;
+                    if (!$util.isString(message.pthree))
+                        return "pthree: string expected";
+                }
+                if (message.rone != null && message.hasOwnProperty("rone")) {
+                    properties.recursiveOneof = 1;
+                    {
+                        var error = $root.jspb.test.TestMessageWithOneof.verify(message.rone);
+                        if (error)
+                            return "rone." + error;
+                    }
+                }
+                if (message.rtwo != null && message.hasOwnProperty("rtwo")) {
+                    if (properties.recursiveOneof === 1)
+                        return "recursiveOneof: multiple values";
+                    properties.recursiveOneof = 1;
+                    if (!$util.isString(message.rtwo))
+                        return "rtwo: string expected";
+                }
+                if (message.normalField != null && message.hasOwnProperty("normalField"))
+                    if (typeof message.normalField !== "boolean")
+                        return "normalField: boolean expected";
+                if (message.repeatedField != null && message.hasOwnProperty("repeatedField")) {
+                    if (!Array.isArray(message.repeatedField))
+                        return "repeatedField: array expected";
+                    for (var i = 0; i < message.repeatedField.length; ++i)
+                        if (!$util.isString(message.repeatedField[i]))
+                            return "repeatedField: string[] expected";
+                }
+                if (message.aone != null && message.hasOwnProperty("aone")) {
+                    properties.defaultOneofA = 1;
+                    if (!$util.isInteger(message.aone))
+                        return "aone: integer expected";
+                }
+                if (message.atwo != null && message.hasOwnProperty("atwo")) {
+                    if (properties.defaultOneofA === 1)
+                        return "defaultOneofA: multiple values";
+                    properties.defaultOneofA = 1;
+                    if (!$util.isInteger(message.atwo))
+                        return "atwo: integer expected";
+                }
+                if (message.bone != null && message.hasOwnProperty("bone")) {
+                    properties.defaultOneofB = 1;
+                    if (!$util.isInteger(message.bone))
+                        return "bone: integer expected";
+                }
+                if (message.btwo != null && message.hasOwnProperty("btwo")) {
+                    if (properties.defaultOneofB === 1)
+                        return "defaultOneofB: multiple values";
+                    properties.defaultOneofB = 1;
+                    if (!$util.isInteger(message.btwo))
+                        return "btwo: integer expected";
+                }
+                return null;
+            };
+
+            /**
+             * Creates a TestMessageWithOneof message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.TestMessageWithOneof
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.TestMessageWithOneof} TestMessageWithOneof
+             */
+            TestMessageWithOneof.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.TestMessageWithOneof)
+                    return object;
+                var message = new $root.jspb.test.TestMessageWithOneof();
+                if (object.pone != null)
+                    message.pone = String(object.pone);
+                if (object.pthree != null)
+                    message.pthree = String(object.pthree);
+                if (object.rone != null) {
+                    if (typeof object.rone !== "object")
+                        throw TypeError(".jspb.test.TestMessageWithOneof.rone: object expected");
+                    message.rone = $root.jspb.test.TestMessageWithOneof.fromObject(object.rone);
+                }
+                if (object.rtwo != null)
+                    message.rtwo = String(object.rtwo);
+                if (object.normalField != null)
+                    message.normalField = Boolean(object.normalField);
+                if (object.repeatedField) {
+                    if (!Array.isArray(object.repeatedField))
+                        throw TypeError(".jspb.test.TestMessageWithOneof.repeatedField: array expected");
+                    message.repeatedField = [];
+                    for (var i = 0; i < object.repeatedField.length; ++i)
+                        message.repeatedField[i] = String(object.repeatedField[i]);
+                }
+                if (object.aone != null)
+                    message.aone = object.aone | 0;
+                if (object.atwo != null)
+                    message.atwo = object.atwo | 0;
+                if (object.bone != null)
+                    message.bone = object.bone | 0;
+                if (object.btwo != null)
+                    message.btwo = object.btwo | 0;
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a TestMessageWithOneof message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.TestMessageWithOneof
+             * @static
+             * @param {jspb.test.TestMessageWithOneof} message TestMessageWithOneof
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            TestMessageWithOneof.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.repeatedField = [];
+                if (options.defaults)
+                    object.normalField = false;
+                if (message.pone != null && message.hasOwnProperty("pone")) {
+                    object.pone = message.pone;
+                    if (options.oneofs)
+                        object.partialOneof = "pone";
+                }
+                if (message.pthree != null && message.hasOwnProperty("pthree")) {
+                    object.pthree = message.pthree;
+                    if (options.oneofs)
+                        object.partialOneof = "pthree";
+                }
+                if (message.rone != null && message.hasOwnProperty("rone")) {
+                    object.rone = $root.jspb.test.TestMessageWithOneof.toObject(message.rone, options);
+                    if (options.oneofs)
+                        object.recursiveOneof = "rone";
+                }
+                if (message.rtwo != null && message.hasOwnProperty("rtwo")) {
+                    object.rtwo = message.rtwo;
+                    if (options.oneofs)
+                        object.recursiveOneof = "rtwo";
+                }
+                if (message.normalField != null && message.hasOwnProperty("normalField"))
+                    object.normalField = message.normalField;
+                if (message.repeatedField && message.repeatedField.length) {
+                    object.repeatedField = [];
+                    for (var j = 0; j < message.repeatedField.length; ++j)
+                        object.repeatedField[j] = message.repeatedField[j];
+                }
+                if (message.aone != null && message.hasOwnProperty("aone")) {
+                    object.aone = message.aone;
+                    if (options.oneofs)
+                        object.defaultOneofA = "aone";
+                }
+                if (message.atwo != null && message.hasOwnProperty("atwo")) {
+                    object.atwo = message.atwo;
+                    if (options.oneofs)
+                        object.defaultOneofA = "atwo";
+                }
+                if (message.bone != null && message.hasOwnProperty("bone")) {
+                    object.bone = message.bone;
+                    if (options.oneofs)
+                        object.defaultOneofB = "bone";
+                }
+                if (message.btwo != null && message.hasOwnProperty("btwo")) {
+                    object.btwo = message.btwo;
+                    if (options.oneofs)
+                        object.defaultOneofB = "btwo";
+                }
+                return object;
+            };
+
+            /**
+             * Converts this TestMessageWithOneof to JSON.
+             * @function toJSON
+             * @memberof jspb.test.TestMessageWithOneof
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            TestMessageWithOneof.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for TestMessageWithOneof
+             * @function getTypeUrl
+             * @memberof jspb.test.TestMessageWithOneof
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            TestMessageWithOneof.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.TestMessageWithOneof";
+            };
+
+            return TestMessageWithOneof;
+        })();
+
+        test.TestEndsWithBytes = (function() {
+
+            /**
+             * Properties of a TestEndsWithBytes.
+             * @memberof jspb.test
+             * @interface ITestEndsWithBytes
+             * @property {number|null} [value] TestEndsWithBytes value
+             * @property {Uint8Array|null} [data] TestEndsWithBytes data
+             */
+
+            /**
+             * Constructs a new TestEndsWithBytes.
+             * @memberof jspb.test
+             * @classdesc Represents a TestEndsWithBytes.
+             * @implements ITestEndsWithBytes
+             * @constructor
+             * @param {jspb.test.ITestEndsWithBytes=} [properties] Properties to set
+             */
+            function TestEndsWithBytes(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * TestEndsWithBytes value.
+             * @member {number} value
+             * @memberof jspb.test.TestEndsWithBytes
+             * @instance
+             */
+            TestEndsWithBytes.prototype.value = 0;
+
+            /**
+             * TestEndsWithBytes data.
+             * @member {Uint8Array} data
+             * @memberof jspb.test.TestEndsWithBytes
+             * @instance
+             */
+            TestEndsWithBytes.prototype.data = $util.newBuffer([]);
+
+            /**
+             * Creates a new TestEndsWithBytes instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.TestEndsWithBytes
+             * @static
+             * @param {jspb.test.ITestEndsWithBytes=} [properties] Properties to set
+             * @returns {jspb.test.TestEndsWithBytes} TestEndsWithBytes instance
+             */
+            TestEndsWithBytes.create = function create(properties) {
+                return new TestEndsWithBytes(properties);
+            };
+
+            /**
+             * Encodes the specified TestEndsWithBytes message. Does not implicitly {@link jspb.test.TestEndsWithBytes.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.TestEndsWithBytes
+             * @static
+             * @param {jspb.test.ITestEndsWithBytes} message TestEndsWithBytes message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestEndsWithBytes.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.value != null && Object.hasOwnProperty.call(message, "value"))
+                    writer.uint32(/* id 1, wireType 0 =*/8).int32(message.value);
+                if (message.data != null && Object.hasOwnProperty.call(message, "data"))
+                    writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.data);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified TestEndsWithBytes message, length delimited. Does not implicitly {@link jspb.test.TestEndsWithBytes.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.TestEndsWithBytes
+             * @static
+             * @param {jspb.test.ITestEndsWithBytes} message TestEndsWithBytes message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestEndsWithBytes.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a TestEndsWithBytes message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.TestEndsWithBytes
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.TestEndsWithBytes} TestEndsWithBytes
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestEndsWithBytes.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.TestEndsWithBytes();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.value = reader.int32();
+                        break;
+                    case 2:
+                        message.data = reader.bytes();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a TestEndsWithBytes message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.TestEndsWithBytes
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.TestEndsWithBytes} TestEndsWithBytes
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestEndsWithBytes.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a TestEndsWithBytes message.
+             * @function verify
+             * @memberof jspb.test.TestEndsWithBytes
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            TestEndsWithBytes.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.value != null && message.hasOwnProperty("value"))
+                    if (!$util.isInteger(message.value))
+                        return "value: integer expected";
+                if (message.data != null && message.hasOwnProperty("data"))
+                    if (!(message.data && typeof message.data.length === "number" || $util.isString(message.data)))
+                        return "data: buffer expected";
+                return null;
+            };
+
+            /**
+             * Creates a TestEndsWithBytes message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.TestEndsWithBytes
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.TestEndsWithBytes} TestEndsWithBytes
+             */
+            TestEndsWithBytes.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.TestEndsWithBytes)
+                    return object;
+                var message = new $root.jspb.test.TestEndsWithBytes();
+                if (object.value != null)
+                    message.value = object.value | 0;
+                if (object.data != null)
+                    if (typeof object.data === "string")
+                        $util.base64.decode(object.data, message.data = $util.newBuffer($util.base64.length(object.data)), 0);
+                    else if (object.data.length >= 0)
+                        message.data = object.data;
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a TestEndsWithBytes message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.TestEndsWithBytes
+             * @static
+             * @param {jspb.test.TestEndsWithBytes} message TestEndsWithBytes
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            TestEndsWithBytes.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults) {
+                    object.value = 0;
+                    if (options.bytes === String)
+                        object.data = "";
+                    else {
+                        object.data = [];
+                        if (options.bytes !== Array)
+                            object.data = $util.newBuffer(object.data);
+                    }
+                }
+                if (message.value != null && message.hasOwnProperty("value"))
+                    object.value = message.value;
+                if (message.data != null && message.hasOwnProperty("data"))
+                    object.data = options.bytes === String ? $util.base64.encode(message.data, 0, message.data.length) : options.bytes === Array ? Array.prototype.slice.call(message.data) : message.data;
+                return object;
+            };
+
+            /**
+             * Converts this TestEndsWithBytes to JSON.
+             * @function toJSON
+             * @memberof jspb.test.TestEndsWithBytes
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            TestEndsWithBytes.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for TestEndsWithBytes
+             * @function getTypeUrl
+             * @memberof jspb.test.TestEndsWithBytes
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            TestEndsWithBytes.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.TestEndsWithBytes";
+            };
+
+            return TestEndsWithBytes;
+        })();
+
+        test.TestMapFieldsNoBinary = (function() {
+
+            /**
+             * Properties of a TestMapFieldsNoBinary.
+             * @memberof jspb.test
+             * @interface ITestMapFieldsNoBinary
+             * @property {Object.<string,string>|null} [mapStringString] TestMapFieldsNoBinary mapStringString
+             * @property {Object.<string,number>|null} [mapStringInt32] TestMapFieldsNoBinary mapStringInt32
+             * @property {Object.<string,number|Long>|null} [mapStringInt64] TestMapFieldsNoBinary mapStringInt64
+             * @property {Object.<string,boolean>|null} [mapStringBool] TestMapFieldsNoBinary mapStringBool
+             * @property {Object.<string,number>|null} [mapStringDouble] TestMapFieldsNoBinary mapStringDouble
+             * @property {Object.<string,jspb.test.MapValueEnumNoBinary>|null} [mapStringEnum] TestMapFieldsNoBinary mapStringEnum
+             * @property {Object.<string,jspb.test.IMapValueMessageNoBinary>|null} [mapStringMsg] TestMapFieldsNoBinary mapStringMsg
+             * @property {Object.<string,string>|null} [mapInt32String] TestMapFieldsNoBinary mapInt32String
+             * @property {Object.<string,string>|null} [mapInt64String] TestMapFieldsNoBinary mapInt64String
+             * @property {Object.<string,string>|null} [mapBoolString] TestMapFieldsNoBinary mapBoolString
+             * @property {jspb.test.ITestMapFieldsNoBinary|null} [testMapFields] TestMapFieldsNoBinary testMapFields
+             * @property {Object.<string,jspb.test.ITestMapFieldsNoBinary>|null} [mapStringTestmapfields] TestMapFieldsNoBinary mapStringTestmapfields
+             */
+
+            /**
+             * Constructs a new TestMapFieldsNoBinary.
+             * @memberof jspb.test
+             * @classdesc Represents a TestMapFieldsNoBinary.
+             * @implements ITestMapFieldsNoBinary
+             * @constructor
+             * @param {jspb.test.ITestMapFieldsNoBinary=} [properties] Properties to set
+             */
+            function TestMapFieldsNoBinary(properties) {
+                this.mapStringString = {};
+                this.mapStringInt32 = {};
+                this.mapStringInt64 = {};
+                this.mapStringBool = {};
+                this.mapStringDouble = {};
+                this.mapStringEnum = {};
+                this.mapStringMsg = {};
+                this.mapInt32String = {};
+                this.mapInt64String = {};
+                this.mapBoolString = {};
+                this.mapStringTestmapfields = {};
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * TestMapFieldsNoBinary mapStringString.
+             * @member {Object.<string,string>} mapStringString
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @instance
+             */
+            TestMapFieldsNoBinary.prototype.mapStringString = $util.emptyObject;
+
+            /**
+             * TestMapFieldsNoBinary mapStringInt32.
+             * @member {Object.<string,number>} mapStringInt32
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @instance
+             */
+            TestMapFieldsNoBinary.prototype.mapStringInt32 = $util.emptyObject;
+
+            /**
+             * TestMapFieldsNoBinary mapStringInt64.
+             * @member {Object.<string,number|Long>} mapStringInt64
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @instance
+             */
+            TestMapFieldsNoBinary.prototype.mapStringInt64 = $util.emptyObject;
+
+            /**
+             * TestMapFieldsNoBinary mapStringBool.
+             * @member {Object.<string,boolean>} mapStringBool
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @instance
+             */
+            TestMapFieldsNoBinary.prototype.mapStringBool = $util.emptyObject;
+
+            /**
+             * TestMapFieldsNoBinary mapStringDouble.
+             * @member {Object.<string,number>} mapStringDouble
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @instance
+             */
+            TestMapFieldsNoBinary.prototype.mapStringDouble = $util.emptyObject;
+
+            /**
+             * TestMapFieldsNoBinary mapStringEnum.
+             * @member {Object.<string,jspb.test.MapValueEnumNoBinary>} mapStringEnum
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @instance
+             */
+            TestMapFieldsNoBinary.prototype.mapStringEnum = $util.emptyObject;
+
+            /**
+             * TestMapFieldsNoBinary mapStringMsg.
+             * @member {Object.<string,jspb.test.IMapValueMessageNoBinary>} mapStringMsg
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @instance
+             */
+            TestMapFieldsNoBinary.prototype.mapStringMsg = $util.emptyObject;
+
+            /**
+             * TestMapFieldsNoBinary mapInt32String.
+             * @member {Object.<string,string>} mapInt32String
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @instance
+             */
+            TestMapFieldsNoBinary.prototype.mapInt32String = $util.emptyObject;
+
+            /**
+             * TestMapFieldsNoBinary mapInt64String.
+             * @member {Object.<string,string>} mapInt64String
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @instance
+             */
+            TestMapFieldsNoBinary.prototype.mapInt64String = $util.emptyObject;
+
+            /**
+             * TestMapFieldsNoBinary mapBoolString.
+             * @member {Object.<string,string>} mapBoolString
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @instance
+             */
+            TestMapFieldsNoBinary.prototype.mapBoolString = $util.emptyObject;
+
+            /**
+             * TestMapFieldsNoBinary testMapFields.
+             * @member {jspb.test.ITestMapFieldsNoBinary|null|undefined} testMapFields
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @instance
+             */
+            TestMapFieldsNoBinary.prototype.testMapFields = null;
+
+            /**
+             * TestMapFieldsNoBinary mapStringTestmapfields.
+             * @member {Object.<string,jspb.test.ITestMapFieldsNoBinary>} mapStringTestmapfields
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @instance
+             */
+            TestMapFieldsNoBinary.prototype.mapStringTestmapfields = $util.emptyObject;
+
+            /**
+             * Creates a new TestMapFieldsNoBinary instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @static
+             * @param {jspb.test.ITestMapFieldsNoBinary=} [properties] Properties to set
+             * @returns {jspb.test.TestMapFieldsNoBinary} TestMapFieldsNoBinary instance
+             */
+            TestMapFieldsNoBinary.create = function create(properties) {
+                return new TestMapFieldsNoBinary(properties);
+            };
+
+            /**
+             * Encodes the specified TestMapFieldsNoBinary message. Does not implicitly {@link jspb.test.TestMapFieldsNoBinary.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @static
+             * @param {jspb.test.ITestMapFieldsNoBinary} message TestMapFieldsNoBinary message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestMapFieldsNoBinary.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.mapStringString != null && Object.hasOwnProperty.call(message, "mapStringString"))
+                    for (var keys = Object.keys(message.mapStringString), i = 0; i < keys.length; ++i)
+                        writer.uint32(/* id 1, wireType 2 =*/10).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]).uint32(/* id 2, wireType 2 =*/18).string(message.mapStringString[keys[i]]).ldelim();
+                if (message.mapStringInt32 != null && Object.hasOwnProperty.call(message, "mapStringInt32"))
+                    for (var keys = Object.keys(message.mapStringInt32), i = 0; i < keys.length; ++i)
+                        writer.uint32(/* id 2, wireType 2 =*/18).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]).uint32(/* id 2, wireType 0 =*/16).int32(message.mapStringInt32[keys[i]]).ldelim();
+                if (message.mapStringInt64 != null && Object.hasOwnProperty.call(message, "mapStringInt64"))
+                    for (var keys = Object.keys(message.mapStringInt64), i = 0; i < keys.length; ++i)
+                        writer.uint32(/* id 3, wireType 2 =*/26).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]).uint32(/* id 2, wireType 0 =*/16).int64(message.mapStringInt64[keys[i]]).ldelim();
+                if (message.mapStringBool != null && Object.hasOwnProperty.call(message, "mapStringBool"))
+                    for (var keys = Object.keys(message.mapStringBool), i = 0; i < keys.length; ++i)
+                        writer.uint32(/* id 4, wireType 2 =*/34).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]).uint32(/* id 2, wireType 0 =*/16).bool(message.mapStringBool[keys[i]]).ldelim();
+                if (message.mapStringDouble != null && Object.hasOwnProperty.call(message, "mapStringDouble"))
+                    for (var keys = Object.keys(message.mapStringDouble), i = 0; i < keys.length; ++i)
+                        writer.uint32(/* id 5, wireType 2 =*/42).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]).uint32(/* id 2, wireType 1 =*/17).double(message.mapStringDouble[keys[i]]).ldelim();
+                if (message.mapStringEnum != null && Object.hasOwnProperty.call(message, "mapStringEnum"))
+                    for (var keys = Object.keys(message.mapStringEnum), i = 0; i < keys.length; ++i)
+                        writer.uint32(/* id 6, wireType 2 =*/50).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]).uint32(/* id 2, wireType 0 =*/16).int32(message.mapStringEnum[keys[i]]).ldelim();
+                if (message.mapStringMsg != null && Object.hasOwnProperty.call(message, "mapStringMsg"))
+                    for (var keys = Object.keys(message.mapStringMsg), i = 0; i < keys.length; ++i) {
+                        writer.uint32(/* id 7, wireType 2 =*/58).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]);
+                        $root.jspb.test.MapValueMessageNoBinary.encode(message.mapStringMsg[keys[i]], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim().ldelim();
+                    }
+                if (message.mapInt32String != null && Object.hasOwnProperty.call(message, "mapInt32String"))
+                    for (var keys = Object.keys(message.mapInt32String), i = 0; i < keys.length; ++i)
+                        writer.uint32(/* id 8, wireType 2 =*/66).fork().uint32(/* id 1, wireType 0 =*/8).int32(keys[i]).uint32(/* id 2, wireType 2 =*/18).string(message.mapInt32String[keys[i]]).ldelim();
+                if (message.mapInt64String != null && Object.hasOwnProperty.call(message, "mapInt64String"))
+                    for (var keys = Object.keys(message.mapInt64String), i = 0; i < keys.length; ++i)
+                        writer.uint32(/* id 9, wireType 2 =*/74).fork().uint32(/* id 1, wireType 0 =*/8).int64(keys[i]).uint32(/* id 2, wireType 2 =*/18).string(message.mapInt64String[keys[i]]).ldelim();
+                if (message.mapBoolString != null && Object.hasOwnProperty.call(message, "mapBoolString"))
+                    for (var keys = Object.keys(message.mapBoolString), i = 0; i < keys.length; ++i)
+                        writer.uint32(/* id 10, wireType 2 =*/82).fork().uint32(/* id 1, wireType 0 =*/8).bool(keys[i]).uint32(/* id 2, wireType 2 =*/18).string(message.mapBoolString[keys[i]]).ldelim();
+                if (message.testMapFields != null && Object.hasOwnProperty.call(message, "testMapFields"))
+                    $root.jspb.test.TestMapFieldsNoBinary.encode(message.testMapFields, writer.uint32(/* id 11, wireType 2 =*/90).fork()).ldelim();
+                if (message.mapStringTestmapfields != null && Object.hasOwnProperty.call(message, "mapStringTestmapfields"))
+                    for (var keys = Object.keys(message.mapStringTestmapfields), i = 0; i < keys.length; ++i) {
+                        writer.uint32(/* id 12, wireType 2 =*/98).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]);
+                        $root.jspb.test.TestMapFieldsNoBinary.encode(message.mapStringTestmapfields[keys[i]], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim().ldelim();
+                    }
+                return writer;
+            };
+
+            /**
+             * Encodes the specified TestMapFieldsNoBinary message, length delimited. Does not implicitly {@link jspb.test.TestMapFieldsNoBinary.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @static
+             * @param {jspb.test.ITestMapFieldsNoBinary} message TestMapFieldsNoBinary message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            TestMapFieldsNoBinary.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a TestMapFieldsNoBinary message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.TestMapFieldsNoBinary} TestMapFieldsNoBinary
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestMapFieldsNoBinary.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.TestMapFieldsNoBinary(), key, value;
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        if (message.mapStringString === $util.emptyObject)
+                            message.mapStringString = {};
+                        var end2 = reader.uint32() + reader.pos;
+                        key = "";
+                        value = "";
+                        while (reader.pos < end2) {
+                            var tag2 = reader.uint32();
+                            switch (tag2 >>> 3) {
+                            case 1:
+                                key = reader.string();
+                                break;
+                            case 2:
+                                value = reader.string();
+                                break;
+                            default:
+                                reader.skipType(tag2 & 7);
+                                break;
+                            }
+                        }
+                        message.mapStringString[key] = value;
+                        break;
+                    case 2:
+                        if (message.mapStringInt32 === $util.emptyObject)
+                            message.mapStringInt32 = {};
+                        var end2 = reader.uint32() + reader.pos;
+                        key = "";
+                        value = 0;
+                        while (reader.pos < end2) {
+                            var tag2 = reader.uint32();
+                            switch (tag2 >>> 3) {
+                            case 1:
+                                key = reader.string();
+                                break;
+                            case 2:
+                                value = reader.int32();
+                                break;
+                            default:
+                                reader.skipType(tag2 & 7);
+                                break;
+                            }
+                        }
+                        message.mapStringInt32[key] = value;
+                        break;
+                    case 3:
+                        if (message.mapStringInt64 === $util.emptyObject)
+                            message.mapStringInt64 = {};
+                        var end2 = reader.uint32() + reader.pos;
+                        key = "";
+                        value = 0;
+                        while (reader.pos < end2) {
+                            var tag2 = reader.uint32();
+                            switch (tag2 >>> 3) {
+                            case 1:
+                                key = reader.string();
+                                break;
+                            case 2:
+                                value = reader.int64();
+                                break;
+                            default:
+                                reader.skipType(tag2 & 7);
+                                break;
+                            }
+                        }
+                        message.mapStringInt64[key] = value;
+                        break;
+                    case 4:
+                        if (message.mapStringBool === $util.emptyObject)
+                            message.mapStringBool = {};
+                        var end2 = reader.uint32() + reader.pos;
+                        key = "";
+                        value = false;
+                        while (reader.pos < end2) {
+                            var tag2 = reader.uint32();
+                            switch (tag2 >>> 3) {
+                            case 1:
+                                key = reader.string();
+                                break;
+                            case 2:
+                                value = reader.bool();
+                                break;
+                            default:
+                                reader.skipType(tag2 & 7);
+                                break;
+                            }
+                        }
+                        message.mapStringBool[key] = value;
+                        break;
+                    case 5:
+                        if (message.mapStringDouble === $util.emptyObject)
+                            message.mapStringDouble = {};
+                        var end2 = reader.uint32() + reader.pos;
+                        key = "";
+                        value = 0;
+                        while (reader.pos < end2) {
+                            var tag2 = reader.uint32();
+                            switch (tag2 >>> 3) {
+                            case 1:
+                                key = reader.string();
+                                break;
+                            case 2:
+                                value = reader.double();
+                                break;
+                            default:
+                                reader.skipType(tag2 & 7);
+                                break;
+                            }
+                        }
+                        message.mapStringDouble[key] = value;
+                        break;
+                    case 6:
+                        if (message.mapStringEnum === $util.emptyObject)
+                            message.mapStringEnum = {};
+                        var end2 = reader.uint32() + reader.pos;
+                        key = "";
+                        value = 0;
+                        while (reader.pos < end2) {
+                            var tag2 = reader.uint32();
+                            switch (tag2 >>> 3) {
+                            case 1:
+                                key = reader.string();
+                                break;
+                            case 2:
+                                value = reader.int32();
+                                break;
+                            default:
+                                reader.skipType(tag2 & 7);
+                                break;
+                            }
+                        }
+                        message.mapStringEnum[key] = value;
+                        break;
+                    case 7:
+                        if (message.mapStringMsg === $util.emptyObject)
+                            message.mapStringMsg = {};
+                        var end2 = reader.uint32() + reader.pos;
+                        key = "";
+                        value = null;
+                        while (reader.pos < end2) {
+                            var tag2 = reader.uint32();
+                            switch (tag2 >>> 3) {
+                            case 1:
+                                key = reader.string();
+                                break;
+                            case 2:
+                                value = $root.jspb.test.MapValueMessageNoBinary.decode(reader, reader.uint32());
+                                break;
+                            default:
+                                reader.skipType(tag2 & 7);
+                                break;
+                            }
+                        }
+                        message.mapStringMsg[key] = value;
+                        break;
+                    case 8:
+                        if (message.mapInt32String === $util.emptyObject)
+                            message.mapInt32String = {};
+                        var end2 = reader.uint32() + reader.pos;
+                        key = 0;
+                        value = "";
+                        while (reader.pos < end2) {
+                            var tag2 = reader.uint32();
+                            switch (tag2 >>> 3) {
+                            case 1:
+                                key = reader.int32();
+                                break;
+                            case 2:
+                                value = reader.string();
+                                break;
+                            default:
+                                reader.skipType(tag2 & 7);
+                                break;
+                            }
+                        }
+                        message.mapInt32String[key] = value;
+                        break;
+                    case 9:
+                        if (message.mapInt64String === $util.emptyObject)
+                            message.mapInt64String = {};
+                        var end2 = reader.uint32() + reader.pos;
+                        key = 0;
+                        value = "";
+                        while (reader.pos < end2) {
+                            var tag2 = reader.uint32();
+                            switch (tag2 >>> 3) {
+                            case 1:
+                                key = reader.int64();
+                                break;
+                            case 2:
+                                value = reader.string();
+                                break;
+                            default:
+                                reader.skipType(tag2 & 7);
+                                break;
+                            }
+                        }
+                        message.mapInt64String[typeof key === "object" ? $util.longToHash(key) : key] = value;
+                        break;
+                    case 10:
+                        if (message.mapBoolString === $util.emptyObject)
+                            message.mapBoolString = {};
+                        var end2 = reader.uint32() + reader.pos;
+                        key = false;
+                        value = "";
+                        while (reader.pos < end2) {
+                            var tag2 = reader.uint32();
+                            switch (tag2 >>> 3) {
+                            case 1:
+                                key = reader.bool();
+                                break;
+                            case 2:
+                                value = reader.string();
+                                break;
+                            default:
+                                reader.skipType(tag2 & 7);
+                                break;
+                            }
+                        }
+                        message.mapBoolString[key] = value;
+                        break;
+                    case 11:
+                        message.testMapFields = $root.jspb.test.TestMapFieldsNoBinary.decode(reader, reader.uint32());
+                        break;
+                    case 12:
+                        if (message.mapStringTestmapfields === $util.emptyObject)
+                            message.mapStringTestmapfields = {};
+                        var end2 = reader.uint32() + reader.pos;
+                        key = "";
+                        value = null;
+                        while (reader.pos < end2) {
+                            var tag2 = reader.uint32();
+                            switch (tag2 >>> 3) {
+                            case 1:
+                                key = reader.string();
+                                break;
+                            case 2:
+                                value = $root.jspb.test.TestMapFieldsNoBinary.decode(reader, reader.uint32());
+                                break;
+                            default:
+                                reader.skipType(tag2 & 7);
+                                break;
+                            }
+                        }
+                        message.mapStringTestmapfields[key] = value;
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a TestMapFieldsNoBinary message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.TestMapFieldsNoBinary} TestMapFieldsNoBinary
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            TestMapFieldsNoBinary.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a TestMapFieldsNoBinary message.
+             * @function verify
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            TestMapFieldsNoBinary.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.mapStringString != null && message.hasOwnProperty("mapStringString")) {
+                    if (!$util.isObject(message.mapStringString))
+                        return "mapStringString: object expected";
+                    var key = Object.keys(message.mapStringString);
+                    for (var i = 0; i < key.length; ++i)
+                        if (!$util.isString(message.mapStringString[key[i]]))
+                            return "mapStringString: string{k:string} expected";
+                }
+                if (message.mapStringInt32 != null && message.hasOwnProperty("mapStringInt32")) {
+                    if (!$util.isObject(message.mapStringInt32))
+                        return "mapStringInt32: object expected";
+                    var key = Object.keys(message.mapStringInt32);
+                    for (var i = 0; i < key.length; ++i)
+                        if (!$util.isInteger(message.mapStringInt32[key[i]]))
+                            return "mapStringInt32: integer{k:string} expected";
+                }
+                if (message.mapStringInt64 != null && message.hasOwnProperty("mapStringInt64")) {
+                    if (!$util.isObject(message.mapStringInt64))
+                        return "mapStringInt64: object expected";
+                    var key = Object.keys(message.mapStringInt64);
+                    for (var i = 0; i < key.length; ++i)
+                        if (!$util.isInteger(message.mapStringInt64[key[i]]) && !(message.mapStringInt64[key[i]] && $util.isInteger(message.mapStringInt64[key[i]].low) && $util.isInteger(message.mapStringInt64[key[i]].high)))
+                            return "mapStringInt64: integer|Long{k:string} expected";
+                }
+                if (message.mapStringBool != null && message.hasOwnProperty("mapStringBool")) {
+                    if (!$util.isObject(message.mapStringBool))
+                        return "mapStringBool: object expected";
+                    var key = Object.keys(message.mapStringBool);
+                    for (var i = 0; i < key.length; ++i)
+                        if (typeof message.mapStringBool[key[i]] !== "boolean")
+                            return "mapStringBool: boolean{k:string} expected";
+                }
+                if (message.mapStringDouble != null && message.hasOwnProperty("mapStringDouble")) {
+                    if (!$util.isObject(message.mapStringDouble))
+                        return "mapStringDouble: object expected";
+                    var key = Object.keys(message.mapStringDouble);
+                    for (var i = 0; i < key.length; ++i)
+                        if (typeof message.mapStringDouble[key[i]] !== "number")
+                            return "mapStringDouble: number{k:string} expected";
+                }
+                if (message.mapStringEnum != null && message.hasOwnProperty("mapStringEnum")) {
+                    if (!$util.isObject(message.mapStringEnum))
+                        return "mapStringEnum: object expected";
+                    var key = Object.keys(message.mapStringEnum);
+                    for (var i = 0; i < key.length; ++i)
+                        switch (message.mapStringEnum[key[i]]) {
+                        default:
+                            return "mapStringEnum: enum value{k:string} expected";
+                        case 0:
+                        case 1:
+                        case 2:
+                            break;
+                        }
+                }
+                if (message.mapStringMsg != null && message.hasOwnProperty("mapStringMsg")) {
+                    if (!$util.isObject(message.mapStringMsg))
+                        return "mapStringMsg: object expected";
+                    var key = Object.keys(message.mapStringMsg);
+                    for (var i = 0; i < key.length; ++i) {
+                        var error = $root.jspb.test.MapValueMessageNoBinary.verify(message.mapStringMsg[key[i]]);
+                        if (error)
+                            return "mapStringMsg." + error;
+                    }
+                }
+                if (message.mapInt32String != null && message.hasOwnProperty("mapInt32String")) {
+                    if (!$util.isObject(message.mapInt32String))
+                        return "mapInt32String: object expected";
+                    var key = Object.keys(message.mapInt32String);
+                    for (var i = 0; i < key.length; ++i) {
+                        if (!$util.key32Re.test(key[i]))
+                            return "mapInt32String: integer key{k:int32} expected";
+                        if (!$util.isString(message.mapInt32String[key[i]]))
+                            return "mapInt32String: string{k:int32} expected";
+                    }
+                }
+                if (message.mapInt64String != null && message.hasOwnProperty("mapInt64String")) {
+                    if (!$util.isObject(message.mapInt64String))
+                        return "mapInt64String: object expected";
+                    var key = Object.keys(message.mapInt64String);
+                    for (var i = 0; i < key.length; ++i) {
+                        if (!$util.key64Re.test(key[i]))
+                            return "mapInt64String: integer|Long key{k:int64} expected";
+                        if (!$util.isString(message.mapInt64String[key[i]]))
+                            return "mapInt64String: string{k:int64} expected";
+                    }
+                }
+                if (message.mapBoolString != null && message.hasOwnProperty("mapBoolString")) {
+                    if (!$util.isObject(message.mapBoolString))
+                        return "mapBoolString: object expected";
+                    var key = Object.keys(message.mapBoolString);
+                    for (var i = 0; i < key.length; ++i) {
+                        if (!$util.key2Re.test(key[i]))
+                            return "mapBoolString: boolean key{k:bool} expected";
+                        if (!$util.isString(message.mapBoolString[key[i]]))
+                            return "mapBoolString: string{k:bool} expected";
+                    }
+                }
+                if (message.testMapFields != null && message.hasOwnProperty("testMapFields")) {
+                    var error = $root.jspb.test.TestMapFieldsNoBinary.verify(message.testMapFields);
+                    if (error)
+                        return "testMapFields." + error;
+                }
+                if (message.mapStringTestmapfields != null && message.hasOwnProperty("mapStringTestmapfields")) {
+                    if (!$util.isObject(message.mapStringTestmapfields))
+                        return "mapStringTestmapfields: object expected";
+                    var key = Object.keys(message.mapStringTestmapfields);
+                    for (var i = 0; i < key.length; ++i) {
+                        var error = $root.jspb.test.TestMapFieldsNoBinary.verify(message.mapStringTestmapfields[key[i]]);
+                        if (error)
+                            return "mapStringTestmapfields." + error;
+                    }
+                }
+                return null;
+            };
+
+            /**
+             * Creates a TestMapFieldsNoBinary message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.TestMapFieldsNoBinary} TestMapFieldsNoBinary
+             */
+            TestMapFieldsNoBinary.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.TestMapFieldsNoBinary)
+                    return object;
+                var message = new $root.jspb.test.TestMapFieldsNoBinary();
+                if (object.mapStringString) {
+                    if (typeof object.mapStringString !== "object")
+                        throw TypeError(".jspb.test.TestMapFieldsNoBinary.mapStringString: object expected");
+                    message.mapStringString = {};
+                    for (var keys = Object.keys(object.mapStringString), i = 0; i < keys.length; ++i)
+                        message.mapStringString[keys[i]] = String(object.mapStringString[keys[i]]);
+                }
+                if (object.mapStringInt32) {
+                    if (typeof object.mapStringInt32 !== "object")
+                        throw TypeError(".jspb.test.TestMapFieldsNoBinary.mapStringInt32: object expected");
+                    message.mapStringInt32 = {};
+                    for (var keys = Object.keys(object.mapStringInt32), i = 0; i < keys.length; ++i)
+                        message.mapStringInt32[keys[i]] = object.mapStringInt32[keys[i]] | 0;
+                }
+                if (object.mapStringInt64) {
+                    if (typeof object.mapStringInt64 !== "object")
+                        throw TypeError(".jspb.test.TestMapFieldsNoBinary.mapStringInt64: object expected");
+                    message.mapStringInt64 = {};
+                    for (var keys = Object.keys(object.mapStringInt64), i = 0; i < keys.length; ++i)
+                        if ($util.Long)
+                            (message.mapStringInt64[keys[i]] = $util.Long.fromValue(object.mapStringInt64[keys[i]])).unsigned = false;
+                        else if (typeof object.mapStringInt64[keys[i]] === "string")
+                            message.mapStringInt64[keys[i]] = parseInt(object.mapStringInt64[keys[i]], 10);
+                        else if (typeof object.mapStringInt64[keys[i]] === "number")
+                            message.mapStringInt64[keys[i]] = object.mapStringInt64[keys[i]];
+                        else if (typeof object.mapStringInt64[keys[i]] === "object")
+                            message.mapStringInt64[keys[i]] = new $util.LongBits(object.mapStringInt64[keys[i]].low >>> 0, object.mapStringInt64[keys[i]].high >>> 0).toNumber();
+                }
+                if (object.mapStringBool) {
+                    if (typeof object.mapStringBool !== "object")
+                        throw TypeError(".jspb.test.TestMapFieldsNoBinary.mapStringBool: object expected");
+                    message.mapStringBool = {};
+                    for (var keys = Object.keys(object.mapStringBool), i = 0; i < keys.length; ++i)
+                        message.mapStringBool[keys[i]] = Boolean(object.mapStringBool[keys[i]]);
+                }
+                if (object.mapStringDouble) {
+                    if (typeof object.mapStringDouble !== "object")
+                        throw TypeError(".jspb.test.TestMapFieldsNoBinary.mapStringDouble: object expected");
+                    message.mapStringDouble = {};
+                    for (var keys = Object.keys(object.mapStringDouble), i = 0; i < keys.length; ++i)
+                        message.mapStringDouble[keys[i]] = Number(object.mapStringDouble[keys[i]]);
+                }
+                if (object.mapStringEnum) {
+                    if (typeof object.mapStringEnum !== "object")
+                        throw TypeError(".jspb.test.TestMapFieldsNoBinary.mapStringEnum: object expected");
+                    message.mapStringEnum = {};
+                    for (var keys = Object.keys(object.mapStringEnum), i = 0; i < keys.length; ++i)
+                        switch (object.mapStringEnum[keys[i]]) {
+                        case "MAP_VALUE_FOO_NOBINARY":
+                        case 0:
+                            message.mapStringEnum[keys[i]] = 0;
+                            break;
+                        case "MAP_VALUE_BAR_NOBINARY":
+                        case 1:
+                            message.mapStringEnum[keys[i]] = 1;
+                            break;
+                        case "MAP_VALUE_BAZ_NOBINARY":
+                        case 2:
+                            message.mapStringEnum[keys[i]] = 2;
+                            break;
+                        }
+                }
+                if (object.mapStringMsg) {
+                    if (typeof object.mapStringMsg !== "object")
+                        throw TypeError(".jspb.test.TestMapFieldsNoBinary.mapStringMsg: object expected");
+                    message.mapStringMsg = {};
+                    for (var keys = Object.keys(object.mapStringMsg), i = 0; i < keys.length; ++i) {
+                        if (typeof object.mapStringMsg[keys[i]] !== "object")
+                            throw TypeError(".jspb.test.TestMapFieldsNoBinary.mapStringMsg: object expected");
+                        message.mapStringMsg[keys[i]] = $root.jspb.test.MapValueMessageNoBinary.fromObject(object.mapStringMsg[keys[i]]);
+                    }
+                }
+                if (object.mapInt32String) {
+                    if (typeof object.mapInt32String !== "object")
+                        throw TypeError(".jspb.test.TestMapFieldsNoBinary.mapInt32String: object expected");
+                    message.mapInt32String = {};
+                    for (var keys = Object.keys(object.mapInt32String), i = 0; i < keys.length; ++i)
+                        message.mapInt32String[keys[i]] = String(object.mapInt32String[keys[i]]);
+                }
+                if (object.mapInt64String) {
+                    if (typeof object.mapInt64String !== "object")
+                        throw TypeError(".jspb.test.TestMapFieldsNoBinary.mapInt64String: object expected");
+                    message.mapInt64String = {};
+                    for (var keys = Object.keys(object.mapInt64String), i = 0; i < keys.length; ++i)
+                        message.mapInt64String[keys[i]] = String(object.mapInt64String[keys[i]]);
+                }
+                if (object.mapBoolString) {
+                    if (typeof object.mapBoolString !== "object")
+                        throw TypeError(".jspb.test.TestMapFieldsNoBinary.mapBoolString: object expected");
+                    message.mapBoolString = {};
+                    for (var keys = Object.keys(object.mapBoolString), i = 0; i < keys.length; ++i)
+                        message.mapBoolString[keys[i]] = String(object.mapBoolString[keys[i]]);
+                }
+                if (object.testMapFields != null) {
+                    if (typeof object.testMapFields !== "object")
+                        throw TypeError(".jspb.test.TestMapFieldsNoBinary.testMapFields: object expected");
+                    message.testMapFields = $root.jspb.test.TestMapFieldsNoBinary.fromObject(object.testMapFields);
+                }
+                if (object.mapStringTestmapfields) {
+                    if (typeof object.mapStringTestmapfields !== "object")
+                        throw TypeError(".jspb.test.TestMapFieldsNoBinary.mapStringTestmapfields: object expected");
+                    message.mapStringTestmapfields = {};
+                    for (var keys = Object.keys(object.mapStringTestmapfields), i = 0; i < keys.length; ++i) {
+                        if (typeof object.mapStringTestmapfields[keys[i]] !== "object")
+                            throw TypeError(".jspb.test.TestMapFieldsNoBinary.mapStringTestmapfields: object expected");
+                        message.mapStringTestmapfields[keys[i]] = $root.jspb.test.TestMapFieldsNoBinary.fromObject(object.mapStringTestmapfields[keys[i]]);
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a TestMapFieldsNoBinary message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @static
+             * @param {jspb.test.TestMapFieldsNoBinary} message TestMapFieldsNoBinary
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            TestMapFieldsNoBinary.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.objects || options.defaults) {
+                    object.mapStringString = {};
+                    object.mapStringInt32 = {};
+                    object.mapStringInt64 = {};
+                    object.mapStringBool = {};
+                    object.mapStringDouble = {};
+                    object.mapStringEnum = {};
+                    object.mapStringMsg = {};
+                    object.mapInt32String = {};
+                    object.mapInt64String = {};
+                    object.mapBoolString = {};
+                    object.mapStringTestmapfields = {};
+                }
+                if (options.defaults)
+                    object.testMapFields = null;
+                var keys2;
+                if (message.mapStringString && (keys2 = Object.keys(message.mapStringString)).length) {
+                    object.mapStringString = {};
+                    for (var j = 0; j < keys2.length; ++j)
+                        object.mapStringString[keys2[j]] = message.mapStringString[keys2[j]];
+                }
+                if (message.mapStringInt32 && (keys2 = Object.keys(message.mapStringInt32)).length) {
+                    object.mapStringInt32 = {};
+                    for (var j = 0; j < keys2.length; ++j)
+                        object.mapStringInt32[keys2[j]] = message.mapStringInt32[keys2[j]];
+                }
+                if (message.mapStringInt64 && (keys2 = Object.keys(message.mapStringInt64)).length) {
+                    object.mapStringInt64 = {};
+                    for (var j = 0; j < keys2.length; ++j)
+                        if (typeof message.mapStringInt64[keys2[j]] === "number")
+                            object.mapStringInt64[keys2[j]] = options.longs === String ? String(message.mapStringInt64[keys2[j]]) : message.mapStringInt64[keys2[j]];
+                        else
+                            object.mapStringInt64[keys2[j]] = options.longs === String ? $util.Long.prototype.toString.call(message.mapStringInt64[keys2[j]]) : options.longs === Number ? new $util.LongBits(message.mapStringInt64[keys2[j]].low >>> 0, message.mapStringInt64[keys2[j]].high >>> 0).toNumber() : message.mapStringInt64[keys2[j]];
+                }
+                if (message.mapStringBool && (keys2 = Object.keys(message.mapStringBool)).length) {
+                    object.mapStringBool = {};
+                    for (var j = 0; j < keys2.length; ++j)
+                        object.mapStringBool[keys2[j]] = message.mapStringBool[keys2[j]];
+                }
+                if (message.mapStringDouble && (keys2 = Object.keys(message.mapStringDouble)).length) {
+                    object.mapStringDouble = {};
+                    for (var j = 0; j < keys2.length; ++j)
+                        object.mapStringDouble[keys2[j]] = options.json && !isFinite(message.mapStringDouble[keys2[j]]) ? String(message.mapStringDouble[keys2[j]]) : message.mapStringDouble[keys2[j]];
+                }
+                if (message.mapStringEnum && (keys2 = Object.keys(message.mapStringEnum)).length) {
+                    object.mapStringEnum = {};
+                    for (var j = 0; j < keys2.length; ++j)
+                        object.mapStringEnum[keys2[j]] = options.enums === String ? $root.jspb.test.MapValueEnumNoBinary[message.mapStringEnum[keys2[j]]] : message.mapStringEnum[keys2[j]];
+                }
+                if (message.mapStringMsg && (keys2 = Object.keys(message.mapStringMsg)).length) {
+                    object.mapStringMsg = {};
+                    for (var j = 0; j < keys2.length; ++j)
+                        object.mapStringMsg[keys2[j]] = $root.jspb.test.MapValueMessageNoBinary.toObject(message.mapStringMsg[keys2[j]], options);
+                }
+                if (message.mapInt32String && (keys2 = Object.keys(message.mapInt32String)).length) {
+                    object.mapInt32String = {};
+                    for (var j = 0; j < keys2.length; ++j)
+                        object.mapInt32String[keys2[j]] = message.mapInt32String[keys2[j]];
+                }
+                if (message.mapInt64String && (keys2 = Object.keys(message.mapInt64String)).length) {
+                    object.mapInt64String = {};
+                    for (var j = 0; j < keys2.length; ++j)
+                        object.mapInt64String[keys2[j]] = message.mapInt64String[keys2[j]];
+                }
+                if (message.mapBoolString && (keys2 = Object.keys(message.mapBoolString)).length) {
+                    object.mapBoolString = {};
+                    for (var j = 0; j < keys2.length; ++j)
+                        object.mapBoolString[keys2[j]] = message.mapBoolString[keys2[j]];
+                }
+                if (message.testMapFields != null && message.hasOwnProperty("testMapFields"))
+                    object.testMapFields = $root.jspb.test.TestMapFieldsNoBinary.toObject(message.testMapFields, options);
+                if (message.mapStringTestmapfields && (keys2 = Object.keys(message.mapStringTestmapfields)).length) {
+                    object.mapStringTestmapfields = {};
+                    for (var j = 0; j < keys2.length; ++j)
+                        object.mapStringTestmapfields[keys2[j]] = $root.jspb.test.TestMapFieldsNoBinary.toObject(message.mapStringTestmapfields[keys2[j]], options);
+                }
+                return object;
+            };
+
+            /**
+             * Converts this TestMapFieldsNoBinary to JSON.
+             * @function toJSON
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            TestMapFieldsNoBinary.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for TestMapFieldsNoBinary
+             * @function getTypeUrl
+             * @memberof jspb.test.TestMapFieldsNoBinary
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            TestMapFieldsNoBinary.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.TestMapFieldsNoBinary";
+            };
+
+            return TestMapFieldsNoBinary;
+        })();
+
+        /**
+         * MapValueEnumNoBinary enum.
+         * @name jspb.test.MapValueEnumNoBinary
+         * @enum {number}
+         * @property {number} MAP_VALUE_FOO_NOBINARY=0 MAP_VALUE_FOO_NOBINARY value
+         * @property {number} MAP_VALUE_BAR_NOBINARY=1 MAP_VALUE_BAR_NOBINARY value
+         * @property {number} MAP_VALUE_BAZ_NOBINARY=2 MAP_VALUE_BAZ_NOBINARY value
+         */
+        test.MapValueEnumNoBinary = (function() {
+            var valuesById = {}, values = Object.create(valuesById);
+            values[valuesById[0] = "MAP_VALUE_FOO_NOBINARY"] = 0;
+            values[valuesById[1] = "MAP_VALUE_BAR_NOBINARY"] = 1;
+            values[valuesById[2] = "MAP_VALUE_BAZ_NOBINARY"] = 2;
+            return values;
+        })();
+
+        test.MapValueMessageNoBinary = (function() {
+
+            /**
+             * Properties of a MapValueMessageNoBinary.
+             * @memberof jspb.test
+             * @interface IMapValueMessageNoBinary
+             * @property {number|null} [foo] MapValueMessageNoBinary foo
+             */
+
+            /**
+             * Constructs a new MapValueMessageNoBinary.
+             * @memberof jspb.test
+             * @classdesc Represents a MapValueMessageNoBinary.
+             * @implements IMapValueMessageNoBinary
+             * @constructor
+             * @param {jspb.test.IMapValueMessageNoBinary=} [properties] Properties to set
+             */
+            function MapValueMessageNoBinary(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * MapValueMessageNoBinary foo.
+             * @member {number} foo
+             * @memberof jspb.test.MapValueMessageNoBinary
+             * @instance
+             */
+            MapValueMessageNoBinary.prototype.foo = 0;
+
+            /**
+             * Creates a new MapValueMessageNoBinary instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.MapValueMessageNoBinary
+             * @static
+             * @param {jspb.test.IMapValueMessageNoBinary=} [properties] Properties to set
+             * @returns {jspb.test.MapValueMessageNoBinary} MapValueMessageNoBinary instance
+             */
+            MapValueMessageNoBinary.create = function create(properties) {
+                return new MapValueMessageNoBinary(properties);
+            };
+
+            /**
+             * Encodes the specified MapValueMessageNoBinary message. Does not implicitly {@link jspb.test.MapValueMessageNoBinary.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.MapValueMessageNoBinary
+             * @static
+             * @param {jspb.test.IMapValueMessageNoBinary} message MapValueMessageNoBinary message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            MapValueMessageNoBinary.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.foo != null && Object.hasOwnProperty.call(message, "foo"))
+                    writer.uint32(/* id 1, wireType 0 =*/8).int32(message.foo);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified MapValueMessageNoBinary message, length delimited. Does not implicitly {@link jspb.test.MapValueMessageNoBinary.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.MapValueMessageNoBinary
+             * @static
+             * @param {jspb.test.IMapValueMessageNoBinary} message MapValueMessageNoBinary message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            MapValueMessageNoBinary.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a MapValueMessageNoBinary message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.MapValueMessageNoBinary
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.MapValueMessageNoBinary} MapValueMessageNoBinary
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            MapValueMessageNoBinary.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.MapValueMessageNoBinary();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.foo = reader.int32();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a MapValueMessageNoBinary message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.MapValueMessageNoBinary
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.MapValueMessageNoBinary} MapValueMessageNoBinary
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            MapValueMessageNoBinary.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a MapValueMessageNoBinary message.
+             * @function verify
+             * @memberof jspb.test.MapValueMessageNoBinary
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            MapValueMessageNoBinary.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.foo != null && message.hasOwnProperty("foo"))
+                    if (!$util.isInteger(message.foo))
+                        return "foo: integer expected";
+                return null;
+            };
+
+            /**
+             * Creates a MapValueMessageNoBinary message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.MapValueMessageNoBinary
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.MapValueMessageNoBinary} MapValueMessageNoBinary
+             */
+            MapValueMessageNoBinary.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.MapValueMessageNoBinary)
+                    return object;
+                var message = new $root.jspb.test.MapValueMessageNoBinary();
+                if (object.foo != null)
+                    message.foo = object.foo | 0;
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a MapValueMessageNoBinary message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.MapValueMessageNoBinary
+             * @static
+             * @param {jspb.test.MapValueMessageNoBinary} message MapValueMessageNoBinary
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            MapValueMessageNoBinary.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults)
+                    object.foo = 0;
+                if (message.foo != null && message.hasOwnProperty("foo"))
+                    object.foo = message.foo;
+                return object;
+            };
+
+            /**
+             * Converts this MapValueMessageNoBinary to JSON.
+             * @function toJSON
+             * @memberof jspb.test.MapValueMessageNoBinary
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            MapValueMessageNoBinary.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for MapValueMessageNoBinary
+             * @function getTypeUrl
+             * @memberof jspb.test.MapValueMessageNoBinary
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            MapValueMessageNoBinary.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.MapValueMessageNoBinary";
+            };
+
+            return MapValueMessageNoBinary;
+        })();
+
+        test.Deeply = (function() {
+
+            /**
+             * Properties of a Deeply.
+             * @memberof jspb.test
+             * @interface IDeeply
+             */
+
+            /**
+             * Constructs a new Deeply.
+             * @memberof jspb.test
+             * @classdesc Represents a Deeply.
+             * @implements IDeeply
+             * @constructor
+             * @param {jspb.test.IDeeply=} [properties] Properties to set
+             */
+            function Deeply(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * Creates a new Deeply instance using the specified properties.
+             * @function create
+             * @memberof jspb.test.Deeply
+             * @static
+             * @param {jspb.test.IDeeply=} [properties] Properties to set
+             * @returns {jspb.test.Deeply} Deeply instance
+             */
+            Deeply.create = function create(properties) {
+                return new Deeply(properties);
+            };
+
+            /**
+             * Encodes the specified Deeply message. Does not implicitly {@link jspb.test.Deeply.verify|verify} messages.
+             * @function encode
+             * @memberof jspb.test.Deeply
+             * @static
+             * @param {jspb.test.IDeeply} message Deeply message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Deeply.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified Deeply message, length delimited. Does not implicitly {@link jspb.test.Deeply.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof jspb.test.Deeply
+             * @static
+             * @param {jspb.test.IDeeply} message Deeply message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            Deeply.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a Deeply message from the specified reader or buffer.
+             * @function decode
+             * @memberof jspb.test.Deeply
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {jspb.test.Deeply} Deeply
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Deeply.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.Deeply();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a Deeply message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof jspb.test.Deeply
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {jspb.test.Deeply} Deeply
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            Deeply.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a Deeply message.
+             * @function verify
+             * @memberof jspb.test.Deeply
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            Deeply.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                return null;
+            };
+
+            /**
+             * Creates a Deeply message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof jspb.test.Deeply
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {jspb.test.Deeply} Deeply
+             */
+            Deeply.fromObject = function fromObject(object) {
+                if (object instanceof $root.jspb.test.Deeply)
+                    return object;
+                return new $root.jspb.test.Deeply();
+            };
+
+            /**
+             * Creates a plain object from a Deeply message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof jspb.test.Deeply
+             * @static
+             * @param {jspb.test.Deeply} message Deeply
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            Deeply.toObject = function toObject() {
+                return {};
+            };
+
+            /**
+             * Converts this Deeply to JSON.
+             * @function toJSON
+             * @memberof jspb.test.Deeply
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            Deeply.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for Deeply
+             * @function getTypeUrl
+             * @memberof jspb.test.Deeply
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            Deeply.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/jspb.test.Deeply";
+            };
+
+            Deeply.Nested = (function() {
+
+                /**
+                 * Properties of a Nested.
+                 * @memberof jspb.test.Deeply
+                 * @interface INested
+                 */
+
+                /**
+                 * Constructs a new Nested.
+                 * @memberof jspb.test.Deeply
+                 * @classdesc Represents a Nested.
+                 * @implements INested
+                 * @constructor
+                 * @param {jspb.test.Deeply.INested=} [properties] Properties to set
+                 */
+                function Nested(properties) {
+                    if (properties)
+                        for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                            if (properties[keys[i]] != null)
+                                this[keys[i]] = properties[keys[i]];
+                }
+
+                /**
+                 * Creates a new Nested instance using the specified properties.
+                 * @function create
+                 * @memberof jspb.test.Deeply.Nested
+                 * @static
+                 * @param {jspb.test.Deeply.INested=} [properties] Properties to set
+                 * @returns {jspb.test.Deeply.Nested} Nested instance
+                 */
+                Nested.create = function create(properties) {
+                    return new Nested(properties);
+                };
+
+                /**
+                 * Encodes the specified Nested message. Does not implicitly {@link jspb.test.Deeply.Nested.verify|verify} messages.
+                 * @function encode
+                 * @memberof jspb.test.Deeply.Nested
+                 * @static
+                 * @param {jspb.test.Deeply.INested} message Nested message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                Nested.encode = function encode(message, writer) {
+                    if (!writer)
+                        writer = $Writer.create();
+                    return writer;
+                };
+
+                /**
+                 * Encodes the specified Nested message, length delimited. Does not implicitly {@link jspb.test.Deeply.Nested.verify|verify} messages.
+                 * @function encodeDelimited
+                 * @memberof jspb.test.Deeply.Nested
+                 * @static
+                 * @param {jspb.test.Deeply.INested} message Nested message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                Nested.encodeDelimited = function encodeDelimited(message, writer) {
+                    return this.encode(message, writer).ldelim();
+                };
+
+                /**
+                 * Decodes a Nested message from the specified reader or buffer.
+                 * @function decode
+                 * @memberof jspb.test.Deeply.Nested
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @param {number} [length] Message length if known beforehand
+                 * @returns {jspb.test.Deeply.Nested} Nested
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                Nested.decode = function decode(reader, length) {
+                    if (!(reader instanceof $Reader))
+                        reader = $Reader.create(reader);
+                    var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.Deeply.Nested();
+                    while (reader.pos < end) {
+                        var tag = reader.uint32();
+                        switch (tag >>> 3) {
+                        default:
+                            reader.skipType(tag & 7);
+                            break;
+                        }
+                    }
+                    return message;
+                };
+
+                /**
+                 * Decodes a Nested message from the specified reader or buffer, length delimited.
+                 * @function decodeDelimited
+                 * @memberof jspb.test.Deeply.Nested
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @returns {jspb.test.Deeply.Nested} Nested
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                Nested.decodeDelimited = function decodeDelimited(reader) {
+                    if (!(reader instanceof $Reader))
+                        reader = new $Reader(reader);
+                    return this.decode(reader, reader.uint32());
+                };
+
+                /**
+                 * Verifies a Nested message.
+                 * @function verify
+                 * @memberof jspb.test.Deeply.Nested
+                 * @static
+                 * @param {Object.<string,*>} message Plain object to verify
+                 * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                 */
+                Nested.verify = function verify(message) {
+                    if (typeof message !== "object" || message === null)
+                        return "object expected";
+                    return null;
+                };
+
+                /**
+                 * Creates a Nested message from a plain object. Also converts values to their respective internal types.
+                 * @function fromObject
+                 * @memberof jspb.test.Deeply.Nested
+                 * @static
+                 * @param {Object.<string,*>} object Plain object
+                 * @returns {jspb.test.Deeply.Nested} Nested
+                 */
+                Nested.fromObject = function fromObject(object) {
+                    if (object instanceof $root.jspb.test.Deeply.Nested)
+                        return object;
+                    return new $root.jspb.test.Deeply.Nested();
+                };
+
+                /**
+                 * Creates a plain object from a Nested message. Also converts values to other types if specified.
+                 * @function toObject
+                 * @memberof jspb.test.Deeply.Nested
+                 * @static
+                 * @param {jspb.test.Deeply.Nested} message Nested
+                 * @param {$protobuf.IConversionOptions} [options] Conversion options
+                 * @returns {Object.<string,*>} Plain object
+                 */
+                Nested.toObject = function toObject() {
+                    return {};
+                };
+
+                /**
+                 * Converts this Nested to JSON.
+                 * @function toJSON
+                 * @memberof jspb.test.Deeply.Nested
+                 * @instance
+                 * @returns {Object.<string,*>} JSON object
+                 */
+                Nested.prototype.toJSON = function toJSON() {
+                    return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                };
+
+                /**
+                 * Gets the default type url for Nested
+                 * @function getTypeUrl
+                 * @memberof jspb.test.Deeply.Nested
+                 * @static
+                 * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                 * @returns {string} The default type url
+                 */
+                Nested.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                    if (typeUrlPrefix === undefined) {
+                        typeUrlPrefix = "type.googleapis.com";
+                    }
+                    return typeUrlPrefix + "/jspb.test.Deeply.Nested";
+                };
+
+                Nested.Message = (function() {
+
+                    /**
+                     * Properties of a Message.
+                     * @memberof jspb.test.Deeply.Nested
+                     * @interface IMessage
+                     * @property {number|null} [count] Message count
+                     */
+
+                    /**
+                     * Constructs a new Message.
+                     * @memberof jspb.test.Deeply.Nested
+                     * @classdesc Represents a Message.
+                     * @implements IMessage
+                     * @constructor
+                     * @param {jspb.test.Deeply.Nested.IMessage=} [properties] Properties to set
+                     */
+                    function Message(properties) {
+                        if (properties)
+                            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                                if (properties[keys[i]] != null)
+                                    this[keys[i]] = properties[keys[i]];
+                    }
+
+                    /**
+                     * Message count.
+                     * @member {number} count
+                     * @memberof jspb.test.Deeply.Nested.Message
+                     * @instance
+                     */
+                    Message.prototype.count = 0;
+
+                    /**
+                     * Creates a new Message instance using the specified properties.
+                     * @function create
+                     * @memberof jspb.test.Deeply.Nested.Message
+                     * @static
+                     * @param {jspb.test.Deeply.Nested.IMessage=} [properties] Properties to set
+                     * @returns {jspb.test.Deeply.Nested.Message} Message instance
+                     */
+                    Message.create = function create(properties) {
+                        return new Message(properties);
+                    };
+
+                    /**
+                     * Encodes the specified Message message. Does not implicitly {@link jspb.test.Deeply.Nested.Message.verify|verify} messages.
+                     * @function encode
+                     * @memberof jspb.test.Deeply.Nested.Message
+                     * @static
+                     * @param {jspb.test.Deeply.Nested.IMessage} message Message message or plain object to encode
+                     * @param {$protobuf.Writer} [writer] Writer to encode to
+                     * @returns {$protobuf.Writer} Writer
+                     */
+                    Message.encode = function encode(message, writer) {
+                        if (!writer)
+                            writer = $Writer.create();
+                        if (message.count != null && Object.hasOwnProperty.call(message, "count"))
+                            writer.uint32(/* id 1, wireType 0 =*/8).int32(message.count);
+                        return writer;
+                    };
+
+                    /**
+                     * Encodes the specified Message message, length delimited. Does not implicitly {@link jspb.test.Deeply.Nested.Message.verify|verify} messages.
+                     * @function encodeDelimited
+                     * @memberof jspb.test.Deeply.Nested.Message
+                     * @static
+                     * @param {jspb.test.Deeply.Nested.IMessage} message Message message or plain object to encode
+                     * @param {$protobuf.Writer} [writer] Writer to encode to
+                     * @returns {$protobuf.Writer} Writer
+                     */
+                    Message.encodeDelimited = function encodeDelimited(message, writer) {
+                        return this.encode(message, writer).ldelim();
+                    };
+
+                    /**
+                     * Decodes a Message message from the specified reader or buffer.
+                     * @function decode
+                     * @memberof jspb.test.Deeply.Nested.Message
+                     * @static
+                     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                     * @param {number} [length] Message length if known beforehand
+                     * @returns {jspb.test.Deeply.Nested.Message} Message
+                     * @throws {Error} If the payload is not a reader or valid buffer
+                     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                     */
+                    Message.decode = function decode(reader, length) {
+                        if (!(reader instanceof $Reader))
+                            reader = $Reader.create(reader);
+                        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.jspb.test.Deeply.Nested.Message();
+                        while (reader.pos < end) {
+                            var tag = reader.uint32();
+                            switch (tag >>> 3) {
+                            case 1:
+                                message.count = reader.int32();
+                                break;
+                            default:
+                                reader.skipType(tag & 7);
+                                break;
+                            }
+                        }
+                        return message;
+                    };
+
+                    /**
+                     * Decodes a Message message from the specified reader or buffer, length delimited.
+                     * @function decodeDelimited
+                     * @memberof jspb.test.Deeply.Nested.Message
+                     * @static
+                     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                     * @returns {jspb.test.Deeply.Nested.Message} Message
+                     * @throws {Error} If the payload is not a reader or valid buffer
+                     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                     */
+                    Message.decodeDelimited = function decodeDelimited(reader) {
+                        if (!(reader instanceof $Reader))
+                            reader = new $Reader(reader);
+                        return this.decode(reader, reader.uint32());
+                    };
+
+                    /**
+                     * Verifies a Message message.
+                     * @function verify
+                     * @memberof jspb.test.Deeply.Nested.Message
+                     * @static
+                     * @param {Object.<string,*>} message Plain object to verify
+                     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                     */
+                    Message.verify = function verify(message) {
+                        if (typeof message !== "object" || message === null)
+                            return "object expected";
+                        if (message.count != null && message.hasOwnProperty("count"))
+                            if (!$util.isInteger(message.count))
+                                return "count: integer expected";
+                        return null;
+                    };
+
+                    /**
+                     * Creates a Message message from a plain object. Also converts values to their respective internal types.
+                     * @function fromObject
+                     * @memberof jspb.test.Deeply.Nested.Message
+                     * @static
+                     * @param {Object.<string,*>} object Plain object
+                     * @returns {jspb.test.Deeply.Nested.Message} Message
+                     */
+                    Message.fromObject = function fromObject(object) {
+                        if (object instanceof $root.jspb.test.Deeply.Nested.Message)
+                            return object;
+                        var message = new $root.jspb.test.Deeply.Nested.Message();
+                        if (object.count != null)
+                            message.count = object.count | 0;
+                        return message;
+                    };
+
+                    /**
+                     * Creates a plain object from a Message message. Also converts values to other types if specified.
+                     * @function toObject
+                     * @memberof jspb.test.Deeply.Nested.Message
+                     * @static
+                     * @param {jspb.test.Deeply.Nested.Message} message Message
+                     * @param {$protobuf.IConversionOptions} [options] Conversion options
+                     * @returns {Object.<string,*>} Plain object
+                     */
+                    Message.toObject = function toObject(message, options) {
+                        if (!options)
+                            options = {};
+                        var object = {};
+                        if (options.defaults)
+                            object.count = 0;
+                        if (message.count != null && message.hasOwnProperty("count"))
+                            object.count = message.count;
+                        return object;
+                    };
+
+                    /**
+                     * Converts this Message to JSON.
+                     * @function toJSON
+                     * @memberof jspb.test.Deeply.Nested.Message
+                     * @instance
+                     * @returns {Object.<string,*>} JSON object
+                     */
+                    Message.prototype.toJSON = function toJSON() {
+                        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                    };
+
+                    /**
+                     * Gets the default type url for Message
+                     * @function getTypeUrl
+                     * @memberof jspb.test.Deeply.Nested.Message
+                     * @static
+                     * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                     * @returns {string} The default type url
+                     */
+                    Message.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                        if (typeUrlPrefix === undefined) {
+                            typeUrlPrefix = "type.googleapis.com";
+                        }
+                        return typeUrlPrefix + "/jspb.test.Deeply.Nested.Message";
+                    };
+
+                    return Message;
+                })();
+
+                return Nested;
+            })();
+
+            return Deeply;
+        })();
+
+        return test;
+    })();
+
+    return jspb;
+})();
+
+$root.google = (function() {
+
+    /**
+     * Namespace google.
+     * @exports google
+     * @namespace
+     */
+    var google = {};
+
+    google.protobuf = (function() {
+
+        /**
+         * Namespace protobuf.
+         * @memberof google
+         * @namespace
+         */
+        var protobuf = {};
+
+        protobuf.FileDescriptorSet = (function() {
+
+            /**
+             * Properties of a FileDescriptorSet.
+             * @memberof google.protobuf
+             * @interface IFileDescriptorSet
+             * @property {Array.<google.protobuf.IFileDescriptorProto>|null} [file] FileDescriptorSet file
+             */
+
+            /**
+             * Constructs a new FileDescriptorSet.
+             * @memberof google.protobuf
+             * @classdesc Represents a FileDescriptorSet.
+             * @implements IFileDescriptorSet
+             * @constructor
+             * @param {google.protobuf.IFileDescriptorSet=} [properties] Properties to set
+             */
+            function FileDescriptorSet(properties) {
+                this.file = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * FileDescriptorSet file.
+             * @member {Array.<google.protobuf.IFileDescriptorProto>} file
+             * @memberof google.protobuf.FileDescriptorSet
+             * @instance
+             */
+            FileDescriptorSet.prototype.file = $util.emptyArray;
+
+            /**
+             * Creates a new FileDescriptorSet instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.FileDescriptorSet
+             * @static
+             * @param {google.protobuf.IFileDescriptorSet=} [properties] Properties to set
+             * @returns {google.protobuf.FileDescriptorSet} FileDescriptorSet instance
+             */
+            FileDescriptorSet.create = function create(properties) {
+                return new FileDescriptorSet(properties);
+            };
+
+            /**
+             * Encodes the specified FileDescriptorSet message. Does not implicitly {@link google.protobuf.FileDescriptorSet.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.FileDescriptorSet
+             * @static
+             * @param {google.protobuf.IFileDescriptorSet} message FileDescriptorSet message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            FileDescriptorSet.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.file != null && message.file.length)
+                    for (var i = 0; i < message.file.length; ++i)
+                        $root.google.protobuf.FileDescriptorProto.encode(message.file[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified FileDescriptorSet message, length delimited. Does not implicitly {@link google.protobuf.FileDescriptorSet.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.FileDescriptorSet
+             * @static
+             * @param {google.protobuf.IFileDescriptorSet} message FileDescriptorSet message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            FileDescriptorSet.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a FileDescriptorSet message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.FileDescriptorSet
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.FileDescriptorSet} FileDescriptorSet
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            FileDescriptorSet.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.FileDescriptorSet();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        if (!(message.file && message.file.length))
+                            message.file = [];
+                        message.file.push($root.google.protobuf.FileDescriptorProto.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a FileDescriptorSet message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.FileDescriptorSet
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.FileDescriptorSet} FileDescriptorSet
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            FileDescriptorSet.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a FileDescriptorSet message.
+             * @function verify
+             * @memberof google.protobuf.FileDescriptorSet
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            FileDescriptorSet.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.file != null && message.hasOwnProperty("file")) {
+                    if (!Array.isArray(message.file))
+                        return "file: array expected";
+                    for (var i = 0; i < message.file.length; ++i) {
+                        var error = $root.google.protobuf.FileDescriptorProto.verify(message.file[i]);
+                        if (error)
+                            return "file." + error;
+                    }
+                }
+                return null;
+            };
+
+            /**
+             * Creates a FileDescriptorSet message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.FileDescriptorSet
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.FileDescriptorSet} FileDescriptorSet
+             */
+            FileDescriptorSet.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.FileDescriptorSet)
+                    return object;
+                var message = new $root.google.protobuf.FileDescriptorSet();
+                if (object.file) {
+                    if (!Array.isArray(object.file))
+                        throw TypeError(".google.protobuf.FileDescriptorSet.file: array expected");
+                    message.file = [];
+                    for (var i = 0; i < object.file.length; ++i) {
+                        if (typeof object.file[i] !== "object")
+                            throw TypeError(".google.protobuf.FileDescriptorSet.file: object expected");
+                        message.file[i] = $root.google.protobuf.FileDescriptorProto.fromObject(object.file[i]);
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a FileDescriptorSet message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.FileDescriptorSet
+             * @static
+             * @param {google.protobuf.FileDescriptorSet} message FileDescriptorSet
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            FileDescriptorSet.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.file = [];
+                if (message.file && message.file.length) {
+                    object.file = [];
+                    for (var j = 0; j < message.file.length; ++j)
+                        object.file[j] = $root.google.protobuf.FileDescriptorProto.toObject(message.file[j], options);
+                }
+                return object;
+            };
+
+            /**
+             * Converts this FileDescriptorSet to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.FileDescriptorSet
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            FileDescriptorSet.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for FileDescriptorSet
+             * @function getTypeUrl
+             * @memberof google.protobuf.FileDescriptorSet
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            FileDescriptorSet.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.FileDescriptorSet";
+            };
+
+            return FileDescriptorSet;
+        })();
+
+        protobuf.FileDescriptorProto = (function() {
+
+            /**
+             * Properties of a FileDescriptorProto.
+             * @memberof google.protobuf
+             * @interface IFileDescriptorProto
+             * @property {string|null} [name] FileDescriptorProto name
+             * @property {string|null} ["package"] FileDescriptorProto package
+             * @property {Array.<string>|null} [dependency] FileDescriptorProto dependency
+             * @property {Array.<number>|null} [publicDependency] FileDescriptorProto publicDependency
+             * @property {Array.<number>|null} [weakDependency] FileDescriptorProto weakDependency
+             * @property {Array.<google.protobuf.IDescriptorProto>|null} [messageType] FileDescriptorProto messageType
+             * @property {Array.<google.protobuf.IEnumDescriptorProto>|null} [enumType] FileDescriptorProto enumType
+             * @property {Array.<google.protobuf.IServiceDescriptorProto>|null} [service] FileDescriptorProto service
+             * @property {Array.<google.protobuf.IFieldDescriptorProto>|null} [extension] FileDescriptorProto extension
+             * @property {google.protobuf.IFileOptions|null} [options] FileDescriptorProto options
+             * @property {google.protobuf.ISourceCodeInfo|null} [sourceCodeInfo] FileDescriptorProto sourceCodeInfo
+             * @property {string|null} [syntax] FileDescriptorProto syntax
+             */
+
+            /**
+             * Constructs a new FileDescriptorProto.
+             * @memberof google.protobuf
+             * @classdesc Represents a FileDescriptorProto.
+             * @implements IFileDescriptorProto
+             * @constructor
+             * @param {google.protobuf.IFileDescriptorProto=} [properties] Properties to set
+             */
+            function FileDescriptorProto(properties) {
+                this.dependency = [];
+                this.publicDependency = [];
+                this.weakDependency = [];
+                this.messageType = [];
+                this.enumType = [];
+                this.service = [];
+                this.extension = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * FileDescriptorProto name.
+             * @member {string} name
+             * @memberof google.protobuf.FileDescriptorProto
+             * @instance
+             */
+            FileDescriptorProto.prototype.name = "";
+
+            /**
+             * FileDescriptorProto package.
+             * @member {string} package
+             * @memberof google.protobuf.FileDescriptorProto
+             * @instance
+             */
+            FileDescriptorProto.prototype["package"] = "";
+
+            /**
+             * FileDescriptorProto dependency.
+             * @member {Array.<string>} dependency
+             * @memberof google.protobuf.FileDescriptorProto
+             * @instance
+             */
+            FileDescriptorProto.prototype.dependency = $util.emptyArray;
+
+            /**
+             * FileDescriptorProto publicDependency.
+             * @member {Array.<number>} publicDependency
+             * @memberof google.protobuf.FileDescriptorProto
+             * @instance
+             */
+            FileDescriptorProto.prototype.publicDependency = $util.emptyArray;
+
+            /**
+             * FileDescriptorProto weakDependency.
+             * @member {Array.<number>} weakDependency
+             * @memberof google.protobuf.FileDescriptorProto
+             * @instance
+             */
+            FileDescriptorProto.prototype.weakDependency = $util.emptyArray;
+
+            /**
+             * FileDescriptorProto messageType.
+             * @member {Array.<google.protobuf.IDescriptorProto>} messageType
+             * @memberof google.protobuf.FileDescriptorProto
+             * @instance
+             */
+            FileDescriptorProto.prototype.messageType = $util.emptyArray;
+
+            /**
+             * FileDescriptorProto enumType.
+             * @member {Array.<google.protobuf.IEnumDescriptorProto>} enumType
+             * @memberof google.protobuf.FileDescriptorProto
+             * @instance
+             */
+            FileDescriptorProto.prototype.enumType = $util.emptyArray;
+
+            /**
+             * FileDescriptorProto service.
+             * @member {Array.<google.protobuf.IServiceDescriptorProto>} service
+             * @memberof google.protobuf.FileDescriptorProto
+             * @instance
+             */
+            FileDescriptorProto.prototype.service = $util.emptyArray;
+
+            /**
+             * FileDescriptorProto extension.
+             * @member {Array.<google.protobuf.IFieldDescriptorProto>} extension
+             * @memberof google.protobuf.FileDescriptorProto
+             * @instance
+             */
+            FileDescriptorProto.prototype.extension = $util.emptyArray;
+
+            /**
+             * FileDescriptorProto options.
+             * @member {google.protobuf.IFileOptions|null|undefined} options
+             * @memberof google.protobuf.FileDescriptorProto
+             * @instance
+             */
+            FileDescriptorProto.prototype.options = null;
+
+            /**
+             * FileDescriptorProto sourceCodeInfo.
+             * @member {google.protobuf.ISourceCodeInfo|null|undefined} sourceCodeInfo
+             * @memberof google.protobuf.FileDescriptorProto
+             * @instance
+             */
+            FileDescriptorProto.prototype.sourceCodeInfo = null;
+
+            /**
+             * FileDescriptorProto syntax.
+             * @member {string} syntax
+             * @memberof google.protobuf.FileDescriptorProto
+             * @instance
+             */
+            FileDescriptorProto.prototype.syntax = "";
+
+            /**
+             * Creates a new FileDescriptorProto instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.FileDescriptorProto
+             * @static
+             * @param {google.protobuf.IFileDescriptorProto=} [properties] Properties to set
+             * @returns {google.protobuf.FileDescriptorProto} FileDescriptorProto instance
+             */
+            FileDescriptorProto.create = function create(properties) {
+                return new FileDescriptorProto(properties);
+            };
+
+            /**
+             * Encodes the specified FileDescriptorProto message. Does not implicitly {@link google.protobuf.FileDescriptorProto.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.FileDescriptorProto
+             * @static
+             * @param {google.protobuf.IFileDescriptorProto} message FileDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            FileDescriptorProto.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.name != null && Object.hasOwnProperty.call(message, "name"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.name);
+                if (message["package"] != null && Object.hasOwnProperty.call(message, "package"))
+                    writer.uint32(/* id 2, wireType 2 =*/18).string(message["package"]);
+                if (message.dependency != null && message.dependency.length)
+                    for (var i = 0; i < message.dependency.length; ++i)
+                        writer.uint32(/* id 3, wireType 2 =*/26).string(message.dependency[i]);
+                if (message.messageType != null && message.messageType.length)
+                    for (var i = 0; i < message.messageType.length; ++i)
+                        $root.google.protobuf.DescriptorProto.encode(message.messageType[i], writer.uint32(/* id 4, wireType 2 =*/34).fork()).ldelim();
+                if (message.enumType != null && message.enumType.length)
+                    for (var i = 0; i < message.enumType.length; ++i)
+                        $root.google.protobuf.EnumDescriptorProto.encode(message.enumType[i], writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim();
+                if (message.service != null && message.service.length)
+                    for (var i = 0; i < message.service.length; ++i)
+                        $root.google.protobuf.ServiceDescriptorProto.encode(message.service[i], writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim();
+                if (message.extension != null && message.extension.length)
+                    for (var i = 0; i < message.extension.length; ++i)
+                        $root.google.protobuf.FieldDescriptorProto.encode(message.extension[i], writer.uint32(/* id 7, wireType 2 =*/58).fork()).ldelim();
+                if (message.options != null && Object.hasOwnProperty.call(message, "options"))
+                    $root.google.protobuf.FileOptions.encode(message.options, writer.uint32(/* id 8, wireType 2 =*/66).fork()).ldelim();
+                if (message.sourceCodeInfo != null && Object.hasOwnProperty.call(message, "sourceCodeInfo"))
+                    $root.google.protobuf.SourceCodeInfo.encode(message.sourceCodeInfo, writer.uint32(/* id 9, wireType 2 =*/74).fork()).ldelim();
+                if (message.publicDependency != null && message.publicDependency.length)
+                    for (var i = 0; i < message.publicDependency.length; ++i)
+                        writer.uint32(/* id 10, wireType 0 =*/80).int32(message.publicDependency[i]);
+                if (message.weakDependency != null && message.weakDependency.length)
+                    for (var i = 0; i < message.weakDependency.length; ++i)
+                        writer.uint32(/* id 11, wireType 0 =*/88).int32(message.weakDependency[i]);
+                if (message.syntax != null && Object.hasOwnProperty.call(message, "syntax"))
+                    writer.uint32(/* id 12, wireType 2 =*/98).string(message.syntax);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified FileDescriptorProto message, length delimited. Does not implicitly {@link google.protobuf.FileDescriptorProto.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.FileDescriptorProto
+             * @static
+             * @param {google.protobuf.IFileDescriptorProto} message FileDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            FileDescriptorProto.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a FileDescriptorProto message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.FileDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.FileDescriptorProto} FileDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            FileDescriptorProto.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.FileDescriptorProto();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.name = reader.string();
+                        break;
+                    case 2:
+                        message["package"] = reader.string();
+                        break;
+                    case 3:
+                        if (!(message.dependency && message.dependency.length))
+                            message.dependency = [];
+                        message.dependency.push(reader.string());
+                        break;
+                    case 10:
+                        if (!(message.publicDependency && message.publicDependency.length))
+                            message.publicDependency = [];
+                        if ((tag & 7) === 2) {
+                            var end2 = reader.uint32() + reader.pos;
+                            while (reader.pos < end2)
+                                message.publicDependency.push(reader.int32());
+                        } else
+                            message.publicDependency.push(reader.int32());
+                        break;
+                    case 11:
+                        if (!(message.weakDependency && message.weakDependency.length))
+                            message.weakDependency = [];
+                        if ((tag & 7) === 2) {
+                            var end2 = reader.uint32() + reader.pos;
+                            while (reader.pos < end2)
+                                message.weakDependency.push(reader.int32());
+                        } else
+                            message.weakDependency.push(reader.int32());
+                        break;
+                    case 4:
+                        if (!(message.messageType && message.messageType.length))
+                            message.messageType = [];
+                        message.messageType.push($root.google.protobuf.DescriptorProto.decode(reader, reader.uint32()));
+                        break;
+                    case 5:
+                        if (!(message.enumType && message.enumType.length))
+                            message.enumType = [];
+                        message.enumType.push($root.google.protobuf.EnumDescriptorProto.decode(reader, reader.uint32()));
+                        break;
+                    case 6:
+                        if (!(message.service && message.service.length))
+                            message.service = [];
+                        message.service.push($root.google.protobuf.ServiceDescriptorProto.decode(reader, reader.uint32()));
+                        break;
+                    case 7:
+                        if (!(message.extension && message.extension.length))
+                            message.extension = [];
+                        message.extension.push($root.google.protobuf.FieldDescriptorProto.decode(reader, reader.uint32()));
+                        break;
+                    case 8:
+                        message.options = $root.google.protobuf.FileOptions.decode(reader, reader.uint32());
+                        break;
+                    case 9:
+                        message.sourceCodeInfo = $root.google.protobuf.SourceCodeInfo.decode(reader, reader.uint32());
+                        break;
+                    case 12:
+                        message.syntax = reader.string();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a FileDescriptorProto message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.FileDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.FileDescriptorProto} FileDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            FileDescriptorProto.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a FileDescriptorProto message.
+             * @function verify
+             * @memberof google.protobuf.FileDescriptorProto
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            FileDescriptorProto.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.name != null && message.hasOwnProperty("name"))
+                    if (!$util.isString(message.name))
+                        return "name: string expected";
+                if (message["package"] != null && message.hasOwnProperty("package"))
+                    if (!$util.isString(message["package"]))
+                        return "package: string expected";
+                if (message.dependency != null && message.hasOwnProperty("dependency")) {
+                    if (!Array.isArray(message.dependency))
+                        return "dependency: array expected";
+                    for (var i = 0; i < message.dependency.length; ++i)
+                        if (!$util.isString(message.dependency[i]))
+                            return "dependency: string[] expected";
+                }
+                if (message.publicDependency != null && message.hasOwnProperty("publicDependency")) {
+                    if (!Array.isArray(message.publicDependency))
+                        return "publicDependency: array expected";
+                    for (var i = 0; i < message.publicDependency.length; ++i)
+                        if (!$util.isInteger(message.publicDependency[i]))
+                            return "publicDependency: integer[] expected";
+                }
+                if (message.weakDependency != null && message.hasOwnProperty("weakDependency")) {
+                    if (!Array.isArray(message.weakDependency))
+                        return "weakDependency: array expected";
+                    for (var i = 0; i < message.weakDependency.length; ++i)
+                        if (!$util.isInteger(message.weakDependency[i]))
+                            return "weakDependency: integer[] expected";
+                }
+                if (message.messageType != null && message.hasOwnProperty("messageType")) {
+                    if (!Array.isArray(message.messageType))
+                        return "messageType: array expected";
+                    for (var i = 0; i < message.messageType.length; ++i) {
+                        var error = $root.google.protobuf.DescriptorProto.verify(message.messageType[i]);
+                        if (error)
+                            return "messageType." + error;
+                    }
+                }
+                if (message.enumType != null && message.hasOwnProperty("enumType")) {
+                    if (!Array.isArray(message.enumType))
+                        return "enumType: array expected";
+                    for (var i = 0; i < message.enumType.length; ++i) {
+                        var error = $root.google.protobuf.EnumDescriptorProto.verify(message.enumType[i]);
+                        if (error)
+                            return "enumType." + error;
+                    }
+                }
+                if (message.service != null && message.hasOwnProperty("service")) {
+                    if (!Array.isArray(message.service))
+                        return "service: array expected";
+                    for (var i = 0; i < message.service.length; ++i) {
+                        var error = $root.google.protobuf.ServiceDescriptorProto.verify(message.service[i]);
+                        if (error)
+                            return "service." + error;
+                    }
+                }
+                if (message.extension != null && message.hasOwnProperty("extension")) {
+                    if (!Array.isArray(message.extension))
+                        return "extension: array expected";
+                    for (var i = 0; i < message.extension.length; ++i) {
+                        var error = $root.google.protobuf.FieldDescriptorProto.verify(message.extension[i]);
+                        if (error)
+                            return "extension." + error;
+                    }
+                }
+                if (message.options != null && message.hasOwnProperty("options")) {
+                    var error = $root.google.protobuf.FileOptions.verify(message.options);
+                    if (error)
+                        return "options." + error;
+                }
+                if (message.sourceCodeInfo != null && message.hasOwnProperty("sourceCodeInfo")) {
+                    var error = $root.google.protobuf.SourceCodeInfo.verify(message.sourceCodeInfo);
+                    if (error)
+                        return "sourceCodeInfo." + error;
+                }
+                if (message.syntax != null && message.hasOwnProperty("syntax"))
+                    if (!$util.isString(message.syntax))
+                        return "syntax: string expected";
+                return null;
+            };
+
+            /**
+             * Creates a FileDescriptorProto message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.FileDescriptorProto
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.FileDescriptorProto} FileDescriptorProto
+             */
+            FileDescriptorProto.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.FileDescriptorProto)
+                    return object;
+                var message = new $root.google.protobuf.FileDescriptorProto();
+                if (object.name != null)
+                    message.name = String(object.name);
+                if (object["package"] != null)
+                    message["package"] = String(object["package"]);
+                if (object.dependency) {
+                    if (!Array.isArray(object.dependency))
+                        throw TypeError(".google.protobuf.FileDescriptorProto.dependency: array expected");
+                    message.dependency = [];
+                    for (var i = 0; i < object.dependency.length; ++i)
+                        message.dependency[i] = String(object.dependency[i]);
+                }
+                if (object.publicDependency) {
+                    if (!Array.isArray(object.publicDependency))
+                        throw TypeError(".google.protobuf.FileDescriptorProto.publicDependency: array expected");
+                    message.publicDependency = [];
+                    for (var i = 0; i < object.publicDependency.length; ++i)
+                        message.publicDependency[i] = object.publicDependency[i] | 0;
+                }
+                if (object.weakDependency) {
+                    if (!Array.isArray(object.weakDependency))
+                        throw TypeError(".google.protobuf.FileDescriptorProto.weakDependency: array expected");
+                    message.weakDependency = [];
+                    for (var i = 0; i < object.weakDependency.length; ++i)
+                        message.weakDependency[i] = object.weakDependency[i] | 0;
+                }
+                if (object.messageType) {
+                    if (!Array.isArray(object.messageType))
+                        throw TypeError(".google.protobuf.FileDescriptorProto.messageType: array expected");
+                    message.messageType = [];
+                    for (var i = 0; i < object.messageType.length; ++i) {
+                        if (typeof object.messageType[i] !== "object")
+                            throw TypeError(".google.protobuf.FileDescriptorProto.messageType: object expected");
+                        message.messageType[i] = $root.google.protobuf.DescriptorProto.fromObject(object.messageType[i]);
+                    }
+                }
+                if (object.enumType) {
+                    if (!Array.isArray(object.enumType))
+                        throw TypeError(".google.protobuf.FileDescriptorProto.enumType: array expected");
+                    message.enumType = [];
+                    for (var i = 0; i < object.enumType.length; ++i) {
+                        if (typeof object.enumType[i] !== "object")
+                            throw TypeError(".google.protobuf.FileDescriptorProto.enumType: object expected");
+                        message.enumType[i] = $root.google.protobuf.EnumDescriptorProto.fromObject(object.enumType[i]);
+                    }
+                }
+                if (object.service) {
+                    if (!Array.isArray(object.service))
+                        throw TypeError(".google.protobuf.FileDescriptorProto.service: array expected");
+                    message.service = [];
+                    for (var i = 0; i < object.service.length; ++i) {
+                        if (typeof object.service[i] !== "object")
+                            throw TypeError(".google.protobuf.FileDescriptorProto.service: object expected");
+                        message.service[i] = $root.google.protobuf.ServiceDescriptorProto.fromObject(object.service[i]);
+                    }
+                }
+                if (object.extension) {
+                    if (!Array.isArray(object.extension))
+                        throw TypeError(".google.protobuf.FileDescriptorProto.extension: array expected");
+                    message.extension = [];
+                    for (var i = 0; i < object.extension.length; ++i) {
+                        if (typeof object.extension[i] !== "object")
+                            throw TypeError(".google.protobuf.FileDescriptorProto.extension: object expected");
+                        message.extension[i] = $root.google.protobuf.FieldDescriptorProto.fromObject(object.extension[i]);
+                    }
+                }
+                if (object.options != null) {
+                    if (typeof object.options !== "object")
+                        throw TypeError(".google.protobuf.FileDescriptorProto.options: object expected");
+                    message.options = $root.google.protobuf.FileOptions.fromObject(object.options);
+                }
+                if (object.sourceCodeInfo != null) {
+                    if (typeof object.sourceCodeInfo !== "object")
+                        throw TypeError(".google.protobuf.FileDescriptorProto.sourceCodeInfo: object expected");
+                    message.sourceCodeInfo = $root.google.protobuf.SourceCodeInfo.fromObject(object.sourceCodeInfo);
+                }
+                if (object.syntax != null)
+                    message.syntax = String(object.syntax);
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a FileDescriptorProto message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.FileDescriptorProto
+             * @static
+             * @param {google.protobuf.FileDescriptorProto} message FileDescriptorProto
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            FileDescriptorProto.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults) {
+                    object.dependency = [];
+                    object.messageType = [];
+                    object.enumType = [];
+                    object.service = [];
+                    object.extension = [];
+                    object.publicDependency = [];
+                    object.weakDependency = [];
+                }
+                if (options.defaults) {
+                    object.name = "";
+                    object["package"] = "";
+                    object.options = null;
+                    object.sourceCodeInfo = null;
+                    object.syntax = "";
+                }
+                if (message.name != null && message.hasOwnProperty("name"))
+                    object.name = message.name;
+                if (message["package"] != null && message.hasOwnProperty("package"))
+                    object["package"] = message["package"];
+                if (message.dependency && message.dependency.length) {
+                    object.dependency = [];
+                    for (var j = 0; j < message.dependency.length; ++j)
+                        object.dependency[j] = message.dependency[j];
+                }
+                if (message.messageType && message.messageType.length) {
+                    object.messageType = [];
+                    for (var j = 0; j < message.messageType.length; ++j)
+                        object.messageType[j] = $root.google.protobuf.DescriptorProto.toObject(message.messageType[j], options);
+                }
+                if (message.enumType && message.enumType.length) {
+                    object.enumType = [];
+                    for (var j = 0; j < message.enumType.length; ++j)
+                        object.enumType[j] = $root.google.protobuf.EnumDescriptorProto.toObject(message.enumType[j], options);
+                }
+                if (message.service && message.service.length) {
+                    object.service = [];
+                    for (var j = 0; j < message.service.length; ++j)
+                        object.service[j] = $root.google.protobuf.ServiceDescriptorProto.toObject(message.service[j], options);
+                }
+                if (message.extension && message.extension.length) {
+                    object.extension = [];
+                    for (var j = 0; j < message.extension.length; ++j)
+                        object.extension[j] = $root.google.protobuf.FieldDescriptorProto.toObject(message.extension[j], options);
+                }
+                if (message.options != null && message.hasOwnProperty("options"))
+                    object.options = $root.google.protobuf.FileOptions.toObject(message.options, options);
+                if (message.sourceCodeInfo != null && message.hasOwnProperty("sourceCodeInfo"))
+                    object.sourceCodeInfo = $root.google.protobuf.SourceCodeInfo.toObject(message.sourceCodeInfo, options);
+                if (message.publicDependency && message.publicDependency.length) {
+                    object.publicDependency = [];
+                    for (var j = 0; j < message.publicDependency.length; ++j)
+                        object.publicDependency[j] = message.publicDependency[j];
+                }
+                if (message.weakDependency && message.weakDependency.length) {
+                    object.weakDependency = [];
+                    for (var j = 0; j < message.weakDependency.length; ++j)
+                        object.weakDependency[j] = message.weakDependency[j];
+                }
+                if (message.syntax != null && message.hasOwnProperty("syntax"))
+                    object.syntax = message.syntax;
+                return object;
+            };
+
+            /**
+             * Converts this FileDescriptorProto to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.FileDescriptorProto
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            FileDescriptorProto.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for FileDescriptorProto
+             * @function getTypeUrl
+             * @memberof google.protobuf.FileDescriptorProto
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            FileDescriptorProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.FileDescriptorProto";
+            };
+
+            return FileDescriptorProto;
+        })();
+
+        protobuf.DescriptorProto = (function() {
+
+            /**
+             * Properties of a DescriptorProto.
+             * @memberof google.protobuf
+             * @interface IDescriptorProto
+             * @property {string|null} [name] DescriptorProto name
+             * @property {Array.<google.protobuf.IFieldDescriptorProto>|null} [field] DescriptorProto field
+             * @property {Array.<google.protobuf.IFieldDescriptorProto>|null} [extension] DescriptorProto extension
+             * @property {Array.<google.protobuf.IDescriptorProto>|null} [nestedType] DescriptorProto nestedType
+             * @property {Array.<google.protobuf.IEnumDescriptorProto>|null} [enumType] DescriptorProto enumType
+             * @property {Array.<google.protobuf.DescriptorProto.IExtensionRange>|null} [extensionRange] DescriptorProto extensionRange
+             * @property {Array.<google.protobuf.IOneofDescriptorProto>|null} [oneofDecl] DescriptorProto oneofDecl
+             * @property {google.protobuf.IMessageOptions|null} [options] DescriptorProto options
+             * @property {Array.<google.protobuf.DescriptorProto.IReservedRange>|null} [reservedRange] DescriptorProto reservedRange
+             * @property {Array.<string>|null} [reservedName] DescriptorProto reservedName
+             */
+
+            /**
+             * Constructs a new DescriptorProto.
+             * @memberof google.protobuf
+             * @classdesc Represents a DescriptorProto.
+             * @implements IDescriptorProto
+             * @constructor
+             * @param {google.protobuf.IDescriptorProto=} [properties] Properties to set
+             */
+            function DescriptorProto(properties) {
+                this.field = [];
+                this.extension = [];
+                this.nestedType = [];
+                this.enumType = [];
+                this.extensionRange = [];
+                this.oneofDecl = [];
+                this.reservedRange = [];
+                this.reservedName = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * DescriptorProto name.
+             * @member {string} name
+             * @memberof google.protobuf.DescriptorProto
+             * @instance
+             */
+            DescriptorProto.prototype.name = "";
+
+            /**
+             * DescriptorProto field.
+             * @member {Array.<google.protobuf.IFieldDescriptorProto>} field
+             * @memberof google.protobuf.DescriptorProto
+             * @instance
+             */
+            DescriptorProto.prototype.field = $util.emptyArray;
+
+            /**
+             * DescriptorProto extension.
+             * @member {Array.<google.protobuf.IFieldDescriptorProto>} extension
+             * @memberof google.protobuf.DescriptorProto
+             * @instance
+             */
+            DescriptorProto.prototype.extension = $util.emptyArray;
+
+            /**
+             * DescriptorProto nestedType.
+             * @member {Array.<google.protobuf.IDescriptorProto>} nestedType
+             * @memberof google.protobuf.DescriptorProto
+             * @instance
+             */
+            DescriptorProto.prototype.nestedType = $util.emptyArray;
+
+            /**
+             * DescriptorProto enumType.
+             * @member {Array.<google.protobuf.IEnumDescriptorProto>} enumType
+             * @memberof google.protobuf.DescriptorProto
+             * @instance
+             */
+            DescriptorProto.prototype.enumType = $util.emptyArray;
+
+            /**
+             * DescriptorProto extensionRange.
+             * @member {Array.<google.protobuf.DescriptorProto.IExtensionRange>} extensionRange
+             * @memberof google.protobuf.DescriptorProto
+             * @instance
+             */
+            DescriptorProto.prototype.extensionRange = $util.emptyArray;
+
+            /**
+             * DescriptorProto oneofDecl.
+             * @member {Array.<google.protobuf.IOneofDescriptorProto>} oneofDecl
+             * @memberof google.protobuf.DescriptorProto
+             * @instance
+             */
+            DescriptorProto.prototype.oneofDecl = $util.emptyArray;
+
+            /**
+             * DescriptorProto options.
+             * @member {google.protobuf.IMessageOptions|null|undefined} options
+             * @memberof google.protobuf.DescriptorProto
+             * @instance
+             */
+            DescriptorProto.prototype.options = null;
+
+            /**
+             * DescriptorProto reservedRange.
+             * @member {Array.<google.protobuf.DescriptorProto.IReservedRange>} reservedRange
+             * @memberof google.protobuf.DescriptorProto
+             * @instance
+             */
+            DescriptorProto.prototype.reservedRange = $util.emptyArray;
+
+            /**
+             * DescriptorProto reservedName.
+             * @member {Array.<string>} reservedName
+             * @memberof google.protobuf.DescriptorProto
+             * @instance
+             */
+            DescriptorProto.prototype.reservedName = $util.emptyArray;
+
+            /**
+             * Creates a new DescriptorProto instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.DescriptorProto
+             * @static
+             * @param {google.protobuf.IDescriptorProto=} [properties] Properties to set
+             * @returns {google.protobuf.DescriptorProto} DescriptorProto instance
+             */
+            DescriptorProto.create = function create(properties) {
+                return new DescriptorProto(properties);
+            };
+
+            /**
+             * Encodes the specified DescriptorProto message. Does not implicitly {@link google.protobuf.DescriptorProto.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.DescriptorProto
+             * @static
+             * @param {google.protobuf.IDescriptorProto} message DescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            DescriptorProto.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.name != null && Object.hasOwnProperty.call(message, "name"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.name);
+                if (message.field != null && message.field.length)
+                    for (var i = 0; i < message.field.length; ++i)
+                        $root.google.protobuf.FieldDescriptorProto.encode(message.field[i], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim();
+                if (message.nestedType != null && message.nestedType.length)
+                    for (var i = 0; i < message.nestedType.length; ++i)
+                        $root.google.protobuf.DescriptorProto.encode(message.nestedType[i], writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim();
+                if (message.enumType != null && message.enumType.length)
+                    for (var i = 0; i < message.enumType.length; ++i)
+                        $root.google.protobuf.EnumDescriptorProto.encode(message.enumType[i], writer.uint32(/* id 4, wireType 2 =*/34).fork()).ldelim();
+                if (message.extensionRange != null && message.extensionRange.length)
+                    for (var i = 0; i < message.extensionRange.length; ++i)
+                        $root.google.protobuf.DescriptorProto.ExtensionRange.encode(message.extensionRange[i], writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim();
+                if (message.extension != null && message.extension.length)
+                    for (var i = 0; i < message.extension.length; ++i)
+                        $root.google.protobuf.FieldDescriptorProto.encode(message.extension[i], writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim();
+                if (message.options != null && Object.hasOwnProperty.call(message, "options"))
+                    $root.google.protobuf.MessageOptions.encode(message.options, writer.uint32(/* id 7, wireType 2 =*/58).fork()).ldelim();
+                if (message.oneofDecl != null && message.oneofDecl.length)
+                    for (var i = 0; i < message.oneofDecl.length; ++i)
+                        $root.google.protobuf.OneofDescriptorProto.encode(message.oneofDecl[i], writer.uint32(/* id 8, wireType 2 =*/66).fork()).ldelim();
+                if (message.reservedRange != null && message.reservedRange.length)
+                    for (var i = 0; i < message.reservedRange.length; ++i)
+                        $root.google.protobuf.DescriptorProto.ReservedRange.encode(message.reservedRange[i], writer.uint32(/* id 9, wireType 2 =*/74).fork()).ldelim();
+                if (message.reservedName != null && message.reservedName.length)
+                    for (var i = 0; i < message.reservedName.length; ++i)
+                        writer.uint32(/* id 10, wireType 2 =*/82).string(message.reservedName[i]);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified DescriptorProto message, length delimited. Does not implicitly {@link google.protobuf.DescriptorProto.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.DescriptorProto
+             * @static
+             * @param {google.protobuf.IDescriptorProto} message DescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            DescriptorProto.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a DescriptorProto message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.DescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.DescriptorProto} DescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            DescriptorProto.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.DescriptorProto();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.name = reader.string();
+                        break;
+                    case 2:
+                        if (!(message.field && message.field.length))
+                            message.field = [];
+                        message.field.push($root.google.protobuf.FieldDescriptorProto.decode(reader, reader.uint32()));
+                        break;
+                    case 6:
+                        if (!(message.extension && message.extension.length))
+                            message.extension = [];
+                        message.extension.push($root.google.protobuf.FieldDescriptorProto.decode(reader, reader.uint32()));
+                        break;
+                    case 3:
+                        if (!(message.nestedType && message.nestedType.length))
+                            message.nestedType = [];
+                        message.nestedType.push($root.google.protobuf.DescriptorProto.decode(reader, reader.uint32()));
+                        break;
+                    case 4:
+                        if (!(message.enumType && message.enumType.length))
+                            message.enumType = [];
+                        message.enumType.push($root.google.protobuf.EnumDescriptorProto.decode(reader, reader.uint32()));
+                        break;
+                    case 5:
+                        if (!(message.extensionRange && message.extensionRange.length))
+                            message.extensionRange = [];
+                        message.extensionRange.push($root.google.protobuf.DescriptorProto.ExtensionRange.decode(reader, reader.uint32()));
+                        break;
+                    case 8:
+                        if (!(message.oneofDecl && message.oneofDecl.length))
+                            message.oneofDecl = [];
+                        message.oneofDecl.push($root.google.protobuf.OneofDescriptorProto.decode(reader, reader.uint32()));
+                        break;
+                    case 7:
+                        message.options = $root.google.protobuf.MessageOptions.decode(reader, reader.uint32());
+                        break;
+                    case 9:
+                        if (!(message.reservedRange && message.reservedRange.length))
+                            message.reservedRange = [];
+                        message.reservedRange.push($root.google.protobuf.DescriptorProto.ReservedRange.decode(reader, reader.uint32()));
+                        break;
+                    case 10:
+                        if (!(message.reservedName && message.reservedName.length))
+                            message.reservedName = [];
+                        message.reservedName.push(reader.string());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a DescriptorProto message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.DescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.DescriptorProto} DescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            DescriptorProto.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a DescriptorProto message.
+             * @function verify
+             * @memberof google.protobuf.DescriptorProto
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            DescriptorProto.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.name != null && message.hasOwnProperty("name"))
+                    if (!$util.isString(message.name))
+                        return "name: string expected";
+                if (message.field != null && message.hasOwnProperty("field")) {
+                    if (!Array.isArray(message.field))
+                        return "field: array expected";
+                    for (var i = 0; i < message.field.length; ++i) {
+                        var error = $root.google.protobuf.FieldDescriptorProto.verify(message.field[i]);
+                        if (error)
+                            return "field." + error;
+                    }
+                }
+                if (message.extension != null && message.hasOwnProperty("extension")) {
+                    if (!Array.isArray(message.extension))
+                        return "extension: array expected";
+                    for (var i = 0; i < message.extension.length; ++i) {
+                        var error = $root.google.protobuf.FieldDescriptorProto.verify(message.extension[i]);
+                        if (error)
+                            return "extension." + error;
+                    }
+                }
+                if (message.nestedType != null && message.hasOwnProperty("nestedType")) {
+                    if (!Array.isArray(message.nestedType))
+                        return "nestedType: array expected";
+                    for (var i = 0; i < message.nestedType.length; ++i) {
+                        var error = $root.google.protobuf.DescriptorProto.verify(message.nestedType[i]);
+                        if (error)
+                            return "nestedType." + error;
+                    }
+                }
+                if (message.enumType != null && message.hasOwnProperty("enumType")) {
+                    if (!Array.isArray(message.enumType))
+                        return "enumType: array expected";
+                    for (var i = 0; i < message.enumType.length; ++i) {
+                        var error = $root.google.protobuf.EnumDescriptorProto.verify(message.enumType[i]);
+                        if (error)
+                            return "enumType." + error;
+                    }
+                }
+                if (message.extensionRange != null && message.hasOwnProperty("extensionRange")) {
+                    if (!Array.isArray(message.extensionRange))
+                        return "extensionRange: array expected";
+                    for (var i = 0; i < message.extensionRange.length; ++i) {
+                        var error = $root.google.protobuf.DescriptorProto.ExtensionRange.verify(message.extensionRange[i]);
+                        if (error)
+                            return "extensionRange." + error;
+                    }
+                }
+                if (message.oneofDecl != null && message.hasOwnProperty("oneofDecl")) {
+                    if (!Array.isArray(message.oneofDecl))
+                        return "oneofDecl: array expected";
+                    for (var i = 0; i < message.oneofDecl.length; ++i) {
+                        var error = $root.google.protobuf.OneofDescriptorProto.verify(message.oneofDecl[i]);
+                        if (error)
+                            return "oneofDecl." + error;
+                    }
+                }
+                if (message.options != null && message.hasOwnProperty("options")) {
+                    var error = $root.google.protobuf.MessageOptions.verify(message.options);
+                    if (error)
+                        return "options." + error;
+                }
+                if (message.reservedRange != null && message.hasOwnProperty("reservedRange")) {
+                    if (!Array.isArray(message.reservedRange))
+                        return "reservedRange: array expected";
+                    for (var i = 0; i < message.reservedRange.length; ++i) {
+                        var error = $root.google.protobuf.DescriptorProto.ReservedRange.verify(message.reservedRange[i]);
+                        if (error)
+                            return "reservedRange." + error;
+                    }
+                }
+                if (message.reservedName != null && message.hasOwnProperty("reservedName")) {
+                    if (!Array.isArray(message.reservedName))
+                        return "reservedName: array expected";
+                    for (var i = 0; i < message.reservedName.length; ++i)
+                        if (!$util.isString(message.reservedName[i]))
+                            return "reservedName: string[] expected";
+                }
+                return null;
+            };
+
+            /**
+             * Creates a DescriptorProto message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.DescriptorProto
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.DescriptorProto} DescriptorProto
+             */
+            DescriptorProto.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.DescriptorProto)
+                    return object;
+                var message = new $root.google.protobuf.DescriptorProto();
+                if (object.name != null)
+                    message.name = String(object.name);
+                if (object.field) {
+                    if (!Array.isArray(object.field))
+                        throw TypeError(".google.protobuf.DescriptorProto.field: array expected");
+                    message.field = [];
+                    for (var i = 0; i < object.field.length; ++i) {
+                        if (typeof object.field[i] !== "object")
+                            throw TypeError(".google.protobuf.DescriptorProto.field: object expected");
+                        message.field[i] = $root.google.protobuf.FieldDescriptorProto.fromObject(object.field[i]);
+                    }
+                }
+                if (object.extension) {
+                    if (!Array.isArray(object.extension))
+                        throw TypeError(".google.protobuf.DescriptorProto.extension: array expected");
+                    message.extension = [];
+                    for (var i = 0; i < object.extension.length; ++i) {
+                        if (typeof object.extension[i] !== "object")
+                            throw TypeError(".google.protobuf.DescriptorProto.extension: object expected");
+                        message.extension[i] = $root.google.protobuf.FieldDescriptorProto.fromObject(object.extension[i]);
+                    }
+                }
+                if (object.nestedType) {
+                    if (!Array.isArray(object.nestedType))
+                        throw TypeError(".google.protobuf.DescriptorProto.nestedType: array expected");
+                    message.nestedType = [];
+                    for (var i = 0; i < object.nestedType.length; ++i) {
+                        if (typeof object.nestedType[i] !== "object")
+                            throw TypeError(".google.protobuf.DescriptorProto.nestedType: object expected");
+                        message.nestedType[i] = $root.google.protobuf.DescriptorProto.fromObject(object.nestedType[i]);
+                    }
+                }
+                if (object.enumType) {
+                    if (!Array.isArray(object.enumType))
+                        throw TypeError(".google.protobuf.DescriptorProto.enumType: array expected");
+                    message.enumType = [];
+                    for (var i = 0; i < object.enumType.length; ++i) {
+                        if (typeof object.enumType[i] !== "object")
+                            throw TypeError(".google.protobuf.DescriptorProto.enumType: object expected");
+                        message.enumType[i] = $root.google.protobuf.EnumDescriptorProto.fromObject(object.enumType[i]);
+                    }
+                }
+                if (object.extensionRange) {
+                    if (!Array.isArray(object.extensionRange))
+                        throw TypeError(".google.protobuf.DescriptorProto.extensionRange: array expected");
+                    message.extensionRange = [];
+                    for (var i = 0; i < object.extensionRange.length; ++i) {
+                        if (typeof object.extensionRange[i] !== "object")
+                            throw TypeError(".google.protobuf.DescriptorProto.extensionRange: object expected");
+                        message.extensionRange[i] = $root.google.protobuf.DescriptorProto.ExtensionRange.fromObject(object.extensionRange[i]);
+                    }
+                }
+                if (object.oneofDecl) {
+                    if (!Array.isArray(object.oneofDecl))
+                        throw TypeError(".google.protobuf.DescriptorProto.oneofDecl: array expected");
+                    message.oneofDecl = [];
+                    for (var i = 0; i < object.oneofDecl.length; ++i) {
+                        if (typeof object.oneofDecl[i] !== "object")
+                            throw TypeError(".google.protobuf.DescriptorProto.oneofDecl: object expected");
+                        message.oneofDecl[i] = $root.google.protobuf.OneofDescriptorProto.fromObject(object.oneofDecl[i]);
+                    }
+                }
+                if (object.options != null) {
+                    if (typeof object.options !== "object")
+                        throw TypeError(".google.protobuf.DescriptorProto.options: object expected");
+                    message.options = $root.google.protobuf.MessageOptions.fromObject(object.options);
+                }
+                if (object.reservedRange) {
+                    if (!Array.isArray(object.reservedRange))
+                        throw TypeError(".google.protobuf.DescriptorProto.reservedRange: array expected");
+                    message.reservedRange = [];
+                    for (var i = 0; i < object.reservedRange.length; ++i) {
+                        if (typeof object.reservedRange[i] !== "object")
+                            throw TypeError(".google.protobuf.DescriptorProto.reservedRange: object expected");
+                        message.reservedRange[i] = $root.google.protobuf.DescriptorProto.ReservedRange.fromObject(object.reservedRange[i]);
+                    }
+                }
+                if (object.reservedName) {
+                    if (!Array.isArray(object.reservedName))
+                        throw TypeError(".google.protobuf.DescriptorProto.reservedName: array expected");
+                    message.reservedName = [];
+                    for (var i = 0; i < object.reservedName.length; ++i)
+                        message.reservedName[i] = String(object.reservedName[i]);
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a DescriptorProto message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.DescriptorProto
+             * @static
+             * @param {google.protobuf.DescriptorProto} message DescriptorProto
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            DescriptorProto.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults) {
+                    object.field = [];
+                    object.nestedType = [];
+                    object.enumType = [];
+                    object.extensionRange = [];
+                    object.extension = [];
+                    object.oneofDecl = [];
+                    object.reservedRange = [];
+                    object.reservedName = [];
+                }
+                if (options.defaults) {
+                    object.name = "";
+                    object.options = null;
+                }
+                if (message.name != null && message.hasOwnProperty("name"))
+                    object.name = message.name;
+                if (message.field && message.field.length) {
+                    object.field = [];
+                    for (var j = 0; j < message.field.length; ++j)
+                        object.field[j] = $root.google.protobuf.FieldDescriptorProto.toObject(message.field[j], options);
+                }
+                if (message.nestedType && message.nestedType.length) {
+                    object.nestedType = [];
+                    for (var j = 0; j < message.nestedType.length; ++j)
+                        object.nestedType[j] = $root.google.protobuf.DescriptorProto.toObject(message.nestedType[j], options);
+                }
+                if (message.enumType && message.enumType.length) {
+                    object.enumType = [];
+                    for (var j = 0; j < message.enumType.length; ++j)
+                        object.enumType[j] = $root.google.protobuf.EnumDescriptorProto.toObject(message.enumType[j], options);
+                }
+                if (message.extensionRange && message.extensionRange.length) {
+                    object.extensionRange = [];
+                    for (var j = 0; j < message.extensionRange.length; ++j)
+                        object.extensionRange[j] = $root.google.protobuf.DescriptorProto.ExtensionRange.toObject(message.extensionRange[j], options);
+                }
+                if (message.extension && message.extension.length) {
+                    object.extension = [];
+                    for (var j = 0; j < message.extension.length; ++j)
+                        object.extension[j] = $root.google.protobuf.FieldDescriptorProto.toObject(message.extension[j], options);
+                }
+                if (message.options != null && message.hasOwnProperty("options"))
+                    object.options = $root.google.protobuf.MessageOptions.toObject(message.options, options);
+                if (message.oneofDecl && message.oneofDecl.length) {
+                    object.oneofDecl = [];
+                    for (var j = 0; j < message.oneofDecl.length; ++j)
+                        object.oneofDecl[j] = $root.google.protobuf.OneofDescriptorProto.toObject(message.oneofDecl[j], options);
+                }
+                if (message.reservedRange && message.reservedRange.length) {
+                    object.reservedRange = [];
+                    for (var j = 0; j < message.reservedRange.length; ++j)
+                        object.reservedRange[j] = $root.google.protobuf.DescriptorProto.ReservedRange.toObject(message.reservedRange[j], options);
+                }
+                if (message.reservedName && message.reservedName.length) {
+                    object.reservedName = [];
+                    for (var j = 0; j < message.reservedName.length; ++j)
+                        object.reservedName[j] = message.reservedName[j];
+                }
+                return object;
+            };
+
+            /**
+             * Converts this DescriptorProto to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.DescriptorProto
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            DescriptorProto.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for DescriptorProto
+             * @function getTypeUrl
+             * @memberof google.protobuf.DescriptorProto
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            DescriptorProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.DescriptorProto";
+            };
+
+            DescriptorProto.ExtensionRange = (function() {
+
+                /**
+                 * Properties of an ExtensionRange.
+                 * @memberof google.protobuf.DescriptorProto
+                 * @interface IExtensionRange
+                 * @property {number|null} [start] ExtensionRange start
+                 * @property {number|null} [end] ExtensionRange end
+                 */
+
+                /**
+                 * Constructs a new ExtensionRange.
+                 * @memberof google.protobuf.DescriptorProto
+                 * @classdesc Represents an ExtensionRange.
+                 * @implements IExtensionRange
+                 * @constructor
+                 * @param {google.protobuf.DescriptorProto.IExtensionRange=} [properties] Properties to set
+                 */
+                function ExtensionRange(properties) {
+                    if (properties)
+                        for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                            if (properties[keys[i]] != null)
+                                this[keys[i]] = properties[keys[i]];
+                }
+
+                /**
+                 * ExtensionRange start.
+                 * @member {number} start
+                 * @memberof google.protobuf.DescriptorProto.ExtensionRange
+                 * @instance
+                 */
+                ExtensionRange.prototype.start = 0;
+
+                /**
+                 * ExtensionRange end.
+                 * @member {number} end
+                 * @memberof google.protobuf.DescriptorProto.ExtensionRange
+                 * @instance
+                 */
+                ExtensionRange.prototype.end = 0;
+
+                /**
+                 * Creates a new ExtensionRange instance using the specified properties.
+                 * @function create
+                 * @memberof google.protobuf.DescriptorProto.ExtensionRange
+                 * @static
+                 * @param {google.protobuf.DescriptorProto.IExtensionRange=} [properties] Properties to set
+                 * @returns {google.protobuf.DescriptorProto.ExtensionRange} ExtensionRange instance
+                 */
+                ExtensionRange.create = function create(properties) {
+                    return new ExtensionRange(properties);
+                };
+
+                /**
+                 * Encodes the specified ExtensionRange message. Does not implicitly {@link google.protobuf.DescriptorProto.ExtensionRange.verify|verify} messages.
+                 * @function encode
+                 * @memberof google.protobuf.DescriptorProto.ExtensionRange
+                 * @static
+                 * @param {google.protobuf.DescriptorProto.IExtensionRange} message ExtensionRange message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                ExtensionRange.encode = function encode(message, writer) {
+                    if (!writer)
+                        writer = $Writer.create();
+                    if (message.start != null && Object.hasOwnProperty.call(message, "start"))
+                        writer.uint32(/* id 1, wireType 0 =*/8).int32(message.start);
+                    if (message.end != null && Object.hasOwnProperty.call(message, "end"))
+                        writer.uint32(/* id 2, wireType 0 =*/16).int32(message.end);
+                    return writer;
+                };
+
+                /**
+                 * Encodes the specified ExtensionRange message, length delimited. Does not implicitly {@link google.protobuf.DescriptorProto.ExtensionRange.verify|verify} messages.
+                 * @function encodeDelimited
+                 * @memberof google.protobuf.DescriptorProto.ExtensionRange
+                 * @static
+                 * @param {google.protobuf.DescriptorProto.IExtensionRange} message ExtensionRange message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                ExtensionRange.encodeDelimited = function encodeDelimited(message, writer) {
+                    return this.encode(message, writer).ldelim();
+                };
+
+                /**
+                 * Decodes an ExtensionRange message from the specified reader or buffer.
+                 * @function decode
+                 * @memberof google.protobuf.DescriptorProto.ExtensionRange
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @param {number} [length] Message length if known beforehand
+                 * @returns {google.protobuf.DescriptorProto.ExtensionRange} ExtensionRange
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                ExtensionRange.decode = function decode(reader, length) {
+                    if (!(reader instanceof $Reader))
+                        reader = $Reader.create(reader);
+                    var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.DescriptorProto.ExtensionRange();
+                    while (reader.pos < end) {
+                        var tag = reader.uint32();
+                        switch (tag >>> 3) {
+                        case 1:
+                            message.start = reader.int32();
+                            break;
+                        case 2:
+                            message.end = reader.int32();
+                            break;
+                        default:
+                            reader.skipType(tag & 7);
+                            break;
+                        }
+                    }
+                    return message;
+                };
+
+                /**
+                 * Decodes an ExtensionRange message from the specified reader or buffer, length delimited.
+                 * @function decodeDelimited
+                 * @memberof google.protobuf.DescriptorProto.ExtensionRange
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @returns {google.protobuf.DescriptorProto.ExtensionRange} ExtensionRange
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                ExtensionRange.decodeDelimited = function decodeDelimited(reader) {
+                    if (!(reader instanceof $Reader))
+                        reader = new $Reader(reader);
+                    return this.decode(reader, reader.uint32());
+                };
+
+                /**
+                 * Verifies an ExtensionRange message.
+                 * @function verify
+                 * @memberof google.protobuf.DescriptorProto.ExtensionRange
+                 * @static
+                 * @param {Object.<string,*>} message Plain object to verify
+                 * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                 */
+                ExtensionRange.verify = function verify(message) {
+                    if (typeof message !== "object" || message === null)
+                        return "object expected";
+                    if (message.start != null && message.hasOwnProperty("start"))
+                        if (!$util.isInteger(message.start))
+                            return "start: integer expected";
+                    if (message.end != null && message.hasOwnProperty("end"))
+                        if (!$util.isInteger(message.end))
+                            return "end: integer expected";
+                    return null;
+                };
+
+                /**
+                 * Creates an ExtensionRange message from a plain object. Also converts values to their respective internal types.
+                 * @function fromObject
+                 * @memberof google.protobuf.DescriptorProto.ExtensionRange
+                 * @static
+                 * @param {Object.<string,*>} object Plain object
+                 * @returns {google.protobuf.DescriptorProto.ExtensionRange} ExtensionRange
+                 */
+                ExtensionRange.fromObject = function fromObject(object) {
+                    if (object instanceof $root.google.protobuf.DescriptorProto.ExtensionRange)
+                        return object;
+                    var message = new $root.google.protobuf.DescriptorProto.ExtensionRange();
+                    if (object.start != null)
+                        message.start = object.start | 0;
+                    if (object.end != null)
+                        message.end = object.end | 0;
+                    return message;
+                };
+
+                /**
+                 * Creates a plain object from an ExtensionRange message. Also converts values to other types if specified.
+                 * @function toObject
+                 * @memberof google.protobuf.DescriptorProto.ExtensionRange
+                 * @static
+                 * @param {google.protobuf.DescriptorProto.ExtensionRange} message ExtensionRange
+                 * @param {$protobuf.IConversionOptions} [options] Conversion options
+                 * @returns {Object.<string,*>} Plain object
+                 */
+                ExtensionRange.toObject = function toObject(message, options) {
+                    if (!options)
+                        options = {};
+                    var object = {};
+                    if (options.defaults) {
+                        object.start = 0;
+                        object.end = 0;
+                    }
+                    if (message.start != null && message.hasOwnProperty("start"))
+                        object.start = message.start;
+                    if (message.end != null && message.hasOwnProperty("end"))
+                        object.end = message.end;
+                    return object;
+                };
+
+                /**
+                 * Converts this ExtensionRange to JSON.
+                 * @function toJSON
+                 * @memberof google.protobuf.DescriptorProto.ExtensionRange
+                 * @instance
+                 * @returns {Object.<string,*>} JSON object
+                 */
+                ExtensionRange.prototype.toJSON = function toJSON() {
+                    return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                };
+
+                /**
+                 * Gets the default type url for ExtensionRange
+                 * @function getTypeUrl
+                 * @memberof google.protobuf.DescriptorProto.ExtensionRange
+                 * @static
+                 * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                 * @returns {string} The default type url
+                 */
+                ExtensionRange.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                    if (typeUrlPrefix === undefined) {
+                        typeUrlPrefix = "type.googleapis.com";
+                    }
+                    return typeUrlPrefix + "/google.protobuf.DescriptorProto.ExtensionRange";
+                };
+
+                return ExtensionRange;
+            })();
+
+            DescriptorProto.ReservedRange = (function() {
+
+                /**
+                 * Properties of a ReservedRange.
+                 * @memberof google.protobuf.DescriptorProto
+                 * @interface IReservedRange
+                 * @property {number|null} [start] ReservedRange start
+                 * @property {number|null} [end] ReservedRange end
+                 */
+
+                /**
+                 * Constructs a new ReservedRange.
+                 * @memberof google.protobuf.DescriptorProto
+                 * @classdesc Represents a ReservedRange.
+                 * @implements IReservedRange
+                 * @constructor
+                 * @param {google.protobuf.DescriptorProto.IReservedRange=} [properties] Properties to set
+                 */
+                function ReservedRange(properties) {
+                    if (properties)
+                        for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                            if (properties[keys[i]] != null)
+                                this[keys[i]] = properties[keys[i]];
+                }
+
+                /**
+                 * ReservedRange start.
+                 * @member {number} start
+                 * @memberof google.protobuf.DescriptorProto.ReservedRange
+                 * @instance
+                 */
+                ReservedRange.prototype.start = 0;
+
+                /**
+                 * ReservedRange end.
+                 * @member {number} end
+                 * @memberof google.protobuf.DescriptorProto.ReservedRange
+                 * @instance
+                 */
+                ReservedRange.prototype.end = 0;
+
+                /**
+                 * Creates a new ReservedRange instance using the specified properties.
+                 * @function create
+                 * @memberof google.protobuf.DescriptorProto.ReservedRange
+                 * @static
+                 * @param {google.protobuf.DescriptorProto.IReservedRange=} [properties] Properties to set
+                 * @returns {google.protobuf.DescriptorProto.ReservedRange} ReservedRange instance
+                 */
+                ReservedRange.create = function create(properties) {
+                    return new ReservedRange(properties);
+                };
+
+                /**
+                 * Encodes the specified ReservedRange message. Does not implicitly {@link google.protobuf.DescriptorProto.ReservedRange.verify|verify} messages.
+                 * @function encode
+                 * @memberof google.protobuf.DescriptorProto.ReservedRange
+                 * @static
+                 * @param {google.protobuf.DescriptorProto.IReservedRange} message ReservedRange message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                ReservedRange.encode = function encode(message, writer) {
+                    if (!writer)
+                        writer = $Writer.create();
+                    if (message.start != null && Object.hasOwnProperty.call(message, "start"))
+                        writer.uint32(/* id 1, wireType 0 =*/8).int32(message.start);
+                    if (message.end != null && Object.hasOwnProperty.call(message, "end"))
+                        writer.uint32(/* id 2, wireType 0 =*/16).int32(message.end);
+                    return writer;
+                };
+
+                /**
+                 * Encodes the specified ReservedRange message, length delimited. Does not implicitly {@link google.protobuf.DescriptorProto.ReservedRange.verify|verify} messages.
+                 * @function encodeDelimited
+                 * @memberof google.protobuf.DescriptorProto.ReservedRange
+                 * @static
+                 * @param {google.protobuf.DescriptorProto.IReservedRange} message ReservedRange message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                ReservedRange.encodeDelimited = function encodeDelimited(message, writer) {
+                    return this.encode(message, writer).ldelim();
+                };
+
+                /**
+                 * Decodes a ReservedRange message from the specified reader or buffer.
+                 * @function decode
+                 * @memberof google.protobuf.DescriptorProto.ReservedRange
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @param {number} [length] Message length if known beforehand
+                 * @returns {google.protobuf.DescriptorProto.ReservedRange} ReservedRange
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                ReservedRange.decode = function decode(reader, length) {
+                    if (!(reader instanceof $Reader))
+                        reader = $Reader.create(reader);
+                    var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.DescriptorProto.ReservedRange();
+                    while (reader.pos < end) {
+                        var tag = reader.uint32();
+                        switch (tag >>> 3) {
+                        case 1:
+                            message.start = reader.int32();
+                            break;
+                        case 2:
+                            message.end = reader.int32();
+                            break;
+                        default:
+                            reader.skipType(tag & 7);
+                            break;
+                        }
+                    }
+                    return message;
+                };
+
+                /**
+                 * Decodes a ReservedRange message from the specified reader or buffer, length delimited.
+                 * @function decodeDelimited
+                 * @memberof google.protobuf.DescriptorProto.ReservedRange
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @returns {google.protobuf.DescriptorProto.ReservedRange} ReservedRange
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                ReservedRange.decodeDelimited = function decodeDelimited(reader) {
+                    if (!(reader instanceof $Reader))
+                        reader = new $Reader(reader);
+                    return this.decode(reader, reader.uint32());
+                };
+
+                /**
+                 * Verifies a ReservedRange message.
+                 * @function verify
+                 * @memberof google.protobuf.DescriptorProto.ReservedRange
+                 * @static
+                 * @param {Object.<string,*>} message Plain object to verify
+                 * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                 */
+                ReservedRange.verify = function verify(message) {
+                    if (typeof message !== "object" || message === null)
+                        return "object expected";
+                    if (message.start != null && message.hasOwnProperty("start"))
+                        if (!$util.isInteger(message.start))
+                            return "start: integer expected";
+                    if (message.end != null && message.hasOwnProperty("end"))
+                        if (!$util.isInteger(message.end))
+                            return "end: integer expected";
+                    return null;
+                };
+
+                /**
+                 * Creates a ReservedRange message from a plain object. Also converts values to their respective internal types.
+                 * @function fromObject
+                 * @memberof google.protobuf.DescriptorProto.ReservedRange
+                 * @static
+                 * @param {Object.<string,*>} object Plain object
+                 * @returns {google.protobuf.DescriptorProto.ReservedRange} ReservedRange
+                 */
+                ReservedRange.fromObject = function fromObject(object) {
+                    if (object instanceof $root.google.protobuf.DescriptorProto.ReservedRange)
+                        return object;
+                    var message = new $root.google.protobuf.DescriptorProto.ReservedRange();
+                    if (object.start != null)
+                        message.start = object.start | 0;
+                    if (object.end != null)
+                        message.end = object.end | 0;
+                    return message;
+                };
+
+                /**
+                 * Creates a plain object from a ReservedRange message. Also converts values to other types if specified.
+                 * @function toObject
+                 * @memberof google.protobuf.DescriptorProto.ReservedRange
+                 * @static
+                 * @param {google.protobuf.DescriptorProto.ReservedRange} message ReservedRange
+                 * @param {$protobuf.IConversionOptions} [options] Conversion options
+                 * @returns {Object.<string,*>} Plain object
+                 */
+                ReservedRange.toObject = function toObject(message, options) {
+                    if (!options)
+                        options = {};
+                    var object = {};
+                    if (options.defaults) {
+                        object.start = 0;
+                        object.end = 0;
+                    }
+                    if (message.start != null && message.hasOwnProperty("start"))
+                        object.start = message.start;
+                    if (message.end != null && message.hasOwnProperty("end"))
+                        object.end = message.end;
+                    return object;
+                };
+
+                /**
+                 * Converts this ReservedRange to JSON.
+                 * @function toJSON
+                 * @memberof google.protobuf.DescriptorProto.ReservedRange
+                 * @instance
+                 * @returns {Object.<string,*>} JSON object
+                 */
+                ReservedRange.prototype.toJSON = function toJSON() {
+                    return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                };
+
+                /**
+                 * Gets the default type url for ReservedRange
+                 * @function getTypeUrl
+                 * @memberof google.protobuf.DescriptorProto.ReservedRange
+                 * @static
+                 * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                 * @returns {string} The default type url
+                 */
+                ReservedRange.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                    if (typeUrlPrefix === undefined) {
+                        typeUrlPrefix = "type.googleapis.com";
+                    }
+                    return typeUrlPrefix + "/google.protobuf.DescriptorProto.ReservedRange";
+                };
+
+                return ReservedRange;
+            })();
+
+            return DescriptorProto;
+        })();
+
+        protobuf.FieldDescriptorProto = (function() {
+
+            /**
+             * Properties of a FieldDescriptorProto.
+             * @memberof google.protobuf
+             * @interface IFieldDescriptorProto
+             * @property {string|null} [name] FieldDescriptorProto name
+             * @property {number|null} [number] FieldDescriptorProto number
+             * @property {google.protobuf.FieldDescriptorProto.Label|null} [label] FieldDescriptorProto label
+             * @property {google.protobuf.FieldDescriptorProto.Type|null} [type] FieldDescriptorProto type
+             * @property {string|null} [typeName] FieldDescriptorProto typeName
+             * @property {string|null} [extendee] FieldDescriptorProto extendee
+             * @property {string|null} [defaultValue] FieldDescriptorProto defaultValue
+             * @property {number|null} [oneofIndex] FieldDescriptorProto oneofIndex
+             * @property {string|null} [jsonName] FieldDescriptorProto jsonName
+             * @property {google.protobuf.IFieldOptions|null} [options] FieldDescriptorProto options
+             */
+
+            /**
+             * Constructs a new FieldDescriptorProto.
+             * @memberof google.protobuf
+             * @classdesc Represents a FieldDescriptorProto.
+             * @implements IFieldDescriptorProto
+             * @constructor
+             * @param {google.protobuf.IFieldDescriptorProto=} [properties] Properties to set
+             */
+            function FieldDescriptorProto(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * FieldDescriptorProto name.
+             * @member {string} name
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @instance
+             */
+            FieldDescriptorProto.prototype.name = "";
+
+            /**
+             * FieldDescriptorProto number.
+             * @member {number} number
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @instance
+             */
+            FieldDescriptorProto.prototype.number = 0;
+
+            /**
+             * FieldDescriptorProto label.
+             * @member {google.protobuf.FieldDescriptorProto.Label} label
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @instance
+             */
+            FieldDescriptorProto.prototype.label = 1;
+
+            /**
+             * FieldDescriptorProto type.
+             * @member {google.protobuf.FieldDescriptorProto.Type} type
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @instance
+             */
+            FieldDescriptorProto.prototype.type = 1;
+
+            /**
+             * FieldDescriptorProto typeName.
+             * @member {string} typeName
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @instance
+             */
+            FieldDescriptorProto.prototype.typeName = "";
+
+            /**
+             * FieldDescriptorProto extendee.
+             * @member {string} extendee
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @instance
+             */
+            FieldDescriptorProto.prototype.extendee = "";
+
+            /**
+             * FieldDescriptorProto defaultValue.
+             * @member {string} defaultValue
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @instance
+             */
+            FieldDescriptorProto.prototype.defaultValue = "";
+
+            /**
+             * FieldDescriptorProto oneofIndex.
+             * @member {number} oneofIndex
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @instance
+             */
+            FieldDescriptorProto.prototype.oneofIndex = 0;
+
+            /**
+             * FieldDescriptorProto jsonName.
+             * @member {string} jsonName
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @instance
+             */
+            FieldDescriptorProto.prototype.jsonName = "";
+
+            /**
+             * FieldDescriptorProto options.
+             * @member {google.protobuf.IFieldOptions|null|undefined} options
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @instance
+             */
+            FieldDescriptorProto.prototype.options = null;
+
+            /**
+             * Creates a new FieldDescriptorProto instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @static
+             * @param {google.protobuf.IFieldDescriptorProto=} [properties] Properties to set
+             * @returns {google.protobuf.FieldDescriptorProto} FieldDescriptorProto instance
+             */
+            FieldDescriptorProto.create = function create(properties) {
+                return new FieldDescriptorProto(properties);
+            };
+
+            /**
+             * Encodes the specified FieldDescriptorProto message. Does not implicitly {@link google.protobuf.FieldDescriptorProto.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @static
+             * @param {google.protobuf.IFieldDescriptorProto} message FieldDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            FieldDescriptorProto.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.name != null && Object.hasOwnProperty.call(message, "name"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.name);
+                if (message.extendee != null && Object.hasOwnProperty.call(message, "extendee"))
+                    writer.uint32(/* id 2, wireType 2 =*/18).string(message.extendee);
+                if (message.number != null && Object.hasOwnProperty.call(message, "number"))
+                    writer.uint32(/* id 3, wireType 0 =*/24).int32(message.number);
+                if (message.label != null && Object.hasOwnProperty.call(message, "label"))
+                    writer.uint32(/* id 4, wireType 0 =*/32).int32(message.label);
+                if (message.type != null && Object.hasOwnProperty.call(message, "type"))
+                    writer.uint32(/* id 5, wireType 0 =*/40).int32(message.type);
+                if (message.typeName != null && Object.hasOwnProperty.call(message, "typeName"))
+                    writer.uint32(/* id 6, wireType 2 =*/50).string(message.typeName);
+                if (message.defaultValue != null && Object.hasOwnProperty.call(message, "defaultValue"))
+                    writer.uint32(/* id 7, wireType 2 =*/58).string(message.defaultValue);
+                if (message.options != null && Object.hasOwnProperty.call(message, "options"))
+                    $root.google.protobuf.FieldOptions.encode(message.options, writer.uint32(/* id 8, wireType 2 =*/66).fork()).ldelim();
+                if (message.oneofIndex != null && Object.hasOwnProperty.call(message, "oneofIndex"))
+                    writer.uint32(/* id 9, wireType 0 =*/72).int32(message.oneofIndex);
+                if (message.jsonName != null && Object.hasOwnProperty.call(message, "jsonName"))
+                    writer.uint32(/* id 10, wireType 2 =*/82).string(message.jsonName);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified FieldDescriptorProto message, length delimited. Does not implicitly {@link google.protobuf.FieldDescriptorProto.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @static
+             * @param {google.protobuf.IFieldDescriptorProto} message FieldDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            FieldDescriptorProto.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a FieldDescriptorProto message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.FieldDescriptorProto} FieldDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            FieldDescriptorProto.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.FieldDescriptorProto();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.name = reader.string();
+                        break;
+                    case 3:
+                        message.number = reader.int32();
+                        break;
+                    case 4:
+                        message.label = reader.int32();
+                        break;
+                    case 5:
+                        message.type = reader.int32();
+                        break;
+                    case 6:
+                        message.typeName = reader.string();
+                        break;
+                    case 2:
+                        message.extendee = reader.string();
+                        break;
+                    case 7:
+                        message.defaultValue = reader.string();
+                        break;
+                    case 9:
+                        message.oneofIndex = reader.int32();
+                        break;
+                    case 10:
+                        message.jsonName = reader.string();
+                        break;
+                    case 8:
+                        message.options = $root.google.protobuf.FieldOptions.decode(reader, reader.uint32());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a FieldDescriptorProto message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.FieldDescriptorProto} FieldDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            FieldDescriptorProto.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a FieldDescriptorProto message.
+             * @function verify
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            FieldDescriptorProto.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.name != null && message.hasOwnProperty("name"))
+                    if (!$util.isString(message.name))
+                        return "name: string expected";
+                if (message.number != null && message.hasOwnProperty("number"))
+                    if (!$util.isInteger(message.number))
+                        return "number: integer expected";
+                if (message.label != null && message.hasOwnProperty("label"))
+                    switch (message.label) {
+                    default:
+                        return "label: enum value expected";
+                    case 1:
+                    case 2:
+                    case 3:
+                        break;
+                    }
+                if (message.type != null && message.hasOwnProperty("type"))
+                    switch (message.type) {
+                    default:
+                        return "type: enum value expected";
+                    case 1:
+                    case 2:
+                    case 3:
+                    case 4:
+                    case 5:
+                    case 6:
+                    case 7:
+                    case 8:
+                    case 9:
+                    case 10:
+                    case 11:
+                    case 12:
+                    case 13:
+                    case 14:
+                    case 15:
+                    case 16:
+                    case 17:
+                    case 18:
+                        break;
+                    }
+                if (message.typeName != null && message.hasOwnProperty("typeName"))
+                    if (!$util.isString(message.typeName))
+                        return "typeName: string expected";
+                if (message.extendee != null && message.hasOwnProperty("extendee"))
+                    if (!$util.isString(message.extendee))
+                        return "extendee: string expected";
+                if (message.defaultValue != null && message.hasOwnProperty("defaultValue"))
+                    if (!$util.isString(message.defaultValue))
+                        return "defaultValue: string expected";
+                if (message.oneofIndex != null && message.hasOwnProperty("oneofIndex"))
+                    if (!$util.isInteger(message.oneofIndex))
+                        return "oneofIndex: integer expected";
+                if (message.jsonName != null && message.hasOwnProperty("jsonName"))
+                    if (!$util.isString(message.jsonName))
+                        return "jsonName: string expected";
+                if (message.options != null && message.hasOwnProperty("options")) {
+                    var error = $root.google.protobuf.FieldOptions.verify(message.options);
+                    if (error)
+                        return "options." + error;
+                }
+                return null;
+            };
+
+            /**
+             * Creates a FieldDescriptorProto message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.FieldDescriptorProto} FieldDescriptorProto
+             */
+            FieldDescriptorProto.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.FieldDescriptorProto)
+                    return object;
+                var message = new $root.google.protobuf.FieldDescriptorProto();
+                if (object.name != null)
+                    message.name = String(object.name);
+                if (object.number != null)
+                    message.number = object.number | 0;
+                switch (object.label) {
+                case "LABEL_OPTIONAL":
+                case 1:
+                    message.label = 1;
+                    break;
+                case "LABEL_REQUIRED":
+                case 2:
+                    message.label = 2;
+                    break;
+                case "LABEL_REPEATED":
+                case 3:
+                    message.label = 3;
+                    break;
+                }
+                switch (object.type) {
+                case "TYPE_DOUBLE":
+                case 1:
+                    message.type = 1;
+                    break;
+                case "TYPE_FLOAT":
+                case 2:
+                    message.type = 2;
+                    break;
+                case "TYPE_INT64":
+                case 3:
+                    message.type = 3;
+                    break;
+                case "TYPE_UINT64":
+                case 4:
+                    message.type = 4;
+                    break;
+                case "TYPE_INT32":
+                case 5:
+                    message.type = 5;
+                    break;
+                case "TYPE_FIXED64":
+                case 6:
+                    message.type = 6;
+                    break;
+                case "TYPE_FIXED32":
+                case 7:
+                    message.type = 7;
+                    break;
+                case "TYPE_BOOL":
+                case 8:
+                    message.type = 8;
+                    break;
+                case "TYPE_STRING":
+                case 9:
+                    message.type = 9;
+                    break;
+                case "TYPE_GROUP":
+                case 10:
+                    message.type = 10;
+                    break;
+                case "TYPE_MESSAGE":
+                case 11:
+                    message.type = 11;
+                    break;
+                case "TYPE_BYTES":
+                case 12:
+                    message.type = 12;
+                    break;
+                case "TYPE_UINT32":
+                case 13:
+                    message.type = 13;
+                    break;
+                case "TYPE_ENUM":
+                case 14:
+                    message.type = 14;
+                    break;
+                case "TYPE_SFIXED32":
+                case 15:
+                    message.type = 15;
+                    break;
+                case "TYPE_SFIXED64":
+                case 16:
+                    message.type = 16;
+                    break;
+                case "TYPE_SINT32":
+                case 17:
+                    message.type = 17;
+                    break;
+                case "TYPE_SINT64":
+                case 18:
+                    message.type = 18;
+                    break;
+                }
+                if (object.typeName != null)
+                    message.typeName = String(object.typeName);
+                if (object.extendee != null)
+                    message.extendee = String(object.extendee);
+                if (object.defaultValue != null)
+                    message.defaultValue = String(object.defaultValue);
+                if (object.oneofIndex != null)
+                    message.oneofIndex = object.oneofIndex | 0;
+                if (object.jsonName != null)
+                    message.jsonName = String(object.jsonName);
+                if (object.options != null) {
+                    if (typeof object.options !== "object")
+                        throw TypeError(".google.protobuf.FieldDescriptorProto.options: object expected");
+                    message.options = $root.google.protobuf.FieldOptions.fromObject(object.options);
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a FieldDescriptorProto message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @static
+             * @param {google.protobuf.FieldDescriptorProto} message FieldDescriptorProto
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            FieldDescriptorProto.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults) {
+                    object.name = "";
+                    object.extendee = "";
+                    object.number = 0;
+                    object.label = options.enums === String ? "LABEL_OPTIONAL" : 1;
+                    object.type = options.enums === String ? "TYPE_DOUBLE" : 1;
+                    object.typeName = "";
+                    object.defaultValue = "";
+                    object.options = null;
+                    object.oneofIndex = 0;
+                    object.jsonName = "";
+                }
+                if (message.name != null && message.hasOwnProperty("name"))
+                    object.name = message.name;
+                if (message.extendee != null && message.hasOwnProperty("extendee"))
+                    object.extendee = message.extendee;
+                if (message.number != null && message.hasOwnProperty("number"))
+                    object.number = message.number;
+                if (message.label != null && message.hasOwnProperty("label"))
+                    object.label = options.enums === String ? $root.google.protobuf.FieldDescriptorProto.Label[message.label] : message.label;
+                if (message.type != null && message.hasOwnProperty("type"))
+                    object.type = options.enums === String ? $root.google.protobuf.FieldDescriptorProto.Type[message.type] : message.type;
+                if (message.typeName != null && message.hasOwnProperty("typeName"))
+                    object.typeName = message.typeName;
+                if (message.defaultValue != null && message.hasOwnProperty("defaultValue"))
+                    object.defaultValue = message.defaultValue;
+                if (message.options != null && message.hasOwnProperty("options"))
+                    object.options = $root.google.protobuf.FieldOptions.toObject(message.options, options);
+                if (message.oneofIndex != null && message.hasOwnProperty("oneofIndex"))
+                    object.oneofIndex = message.oneofIndex;
+                if (message.jsonName != null && message.hasOwnProperty("jsonName"))
+                    object.jsonName = message.jsonName;
+                return object;
+            };
+
+            /**
+             * Converts this FieldDescriptorProto to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            FieldDescriptorProto.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for FieldDescriptorProto
+             * @function getTypeUrl
+             * @memberof google.protobuf.FieldDescriptorProto
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            FieldDescriptorProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.FieldDescriptorProto";
+            };
+
+            /**
+             * Type enum.
+             * @name google.protobuf.FieldDescriptorProto.Type
+             * @enum {number}
+             * @property {number} TYPE_DOUBLE=1 TYPE_DOUBLE value
+             * @property {number} TYPE_FLOAT=2 TYPE_FLOAT value
+             * @property {number} TYPE_INT64=3 TYPE_INT64 value
+             * @property {number} TYPE_UINT64=4 TYPE_UINT64 value
+             * @property {number} TYPE_INT32=5 TYPE_INT32 value
+             * @property {number} TYPE_FIXED64=6 TYPE_FIXED64 value
+             * @property {number} TYPE_FIXED32=7 TYPE_FIXED32 value
+             * @property {number} TYPE_BOOL=8 TYPE_BOOL value
+             * @property {number} TYPE_STRING=9 TYPE_STRING value
+             * @property {number} TYPE_GROUP=10 TYPE_GROUP value
+             * @property {number} TYPE_MESSAGE=11 TYPE_MESSAGE value
+             * @property {number} TYPE_BYTES=12 TYPE_BYTES value
+             * @property {number} TYPE_UINT32=13 TYPE_UINT32 value
+             * @property {number} TYPE_ENUM=14 TYPE_ENUM value
+             * @property {number} TYPE_SFIXED32=15 TYPE_SFIXED32 value
+             * @property {number} TYPE_SFIXED64=16 TYPE_SFIXED64 value
+             * @property {number} TYPE_SINT32=17 TYPE_SINT32 value
+             * @property {number} TYPE_SINT64=18 TYPE_SINT64 value
+             */
+            FieldDescriptorProto.Type = (function() {
+                var valuesById = {}, values = Object.create(valuesById);
+                values[valuesById[1] = "TYPE_DOUBLE"] = 1;
+                values[valuesById[2] = "TYPE_FLOAT"] = 2;
+                values[valuesById[3] = "TYPE_INT64"] = 3;
+                values[valuesById[4] = "TYPE_UINT64"] = 4;
+                values[valuesById[5] = "TYPE_INT32"] = 5;
+                values[valuesById[6] = "TYPE_FIXED64"] = 6;
+                values[valuesById[7] = "TYPE_FIXED32"] = 7;
+                values[valuesById[8] = "TYPE_BOOL"] = 8;
+                values[valuesById[9] = "TYPE_STRING"] = 9;
+                values[valuesById[10] = "TYPE_GROUP"] = 10;
+                values[valuesById[11] = "TYPE_MESSAGE"] = 11;
+                values[valuesById[12] = "TYPE_BYTES"] = 12;
+                values[valuesById[13] = "TYPE_UINT32"] = 13;
+                values[valuesById[14] = "TYPE_ENUM"] = 14;
+                values[valuesById[15] = "TYPE_SFIXED32"] = 15;
+                values[valuesById[16] = "TYPE_SFIXED64"] = 16;
+                values[valuesById[17] = "TYPE_SINT32"] = 17;
+                values[valuesById[18] = "TYPE_SINT64"] = 18;
+                return values;
+            })();
+
+            /**
+             * Label enum.
+             * @name google.protobuf.FieldDescriptorProto.Label
+             * @enum {number}
+             * @property {number} LABEL_OPTIONAL=1 LABEL_OPTIONAL value
+             * @property {number} LABEL_REQUIRED=2 LABEL_REQUIRED value
+             * @property {number} LABEL_REPEATED=3 LABEL_REPEATED value
+             */
+            FieldDescriptorProto.Label = (function() {
+                var valuesById = {}, values = Object.create(valuesById);
+                values[valuesById[1] = "LABEL_OPTIONAL"] = 1;
+                values[valuesById[2] = "LABEL_REQUIRED"] = 2;
+                values[valuesById[3] = "LABEL_REPEATED"] = 3;
+                return values;
+            })();
+
+            return FieldDescriptorProto;
+        })();
+
+        protobuf.OneofDescriptorProto = (function() {
+
+            /**
+             * Properties of an OneofDescriptorProto.
+             * @memberof google.protobuf
+             * @interface IOneofDescriptorProto
+             * @property {string|null} [name] OneofDescriptorProto name
+             * @property {google.protobuf.IOneofOptions|null} [options] OneofDescriptorProto options
+             */
+
+            /**
+             * Constructs a new OneofDescriptorProto.
+             * @memberof google.protobuf
+             * @classdesc Represents an OneofDescriptorProto.
+             * @implements IOneofDescriptorProto
+             * @constructor
+             * @param {google.protobuf.IOneofDescriptorProto=} [properties] Properties to set
+             */
+            function OneofDescriptorProto(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * OneofDescriptorProto name.
+             * @member {string} name
+             * @memberof google.protobuf.OneofDescriptorProto
+             * @instance
+             */
+            OneofDescriptorProto.prototype.name = "";
+
+            /**
+             * OneofDescriptorProto options.
+             * @member {google.protobuf.IOneofOptions|null|undefined} options
+             * @memberof google.protobuf.OneofDescriptorProto
+             * @instance
+             */
+            OneofDescriptorProto.prototype.options = null;
+
+            /**
+             * Creates a new OneofDescriptorProto instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.OneofDescriptorProto
+             * @static
+             * @param {google.protobuf.IOneofDescriptorProto=} [properties] Properties to set
+             * @returns {google.protobuf.OneofDescriptorProto} OneofDescriptorProto instance
+             */
+            OneofDescriptorProto.create = function create(properties) {
+                return new OneofDescriptorProto(properties);
+            };
+
+            /**
+             * Encodes the specified OneofDescriptorProto message. Does not implicitly {@link google.protobuf.OneofDescriptorProto.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.OneofDescriptorProto
+             * @static
+             * @param {google.protobuf.IOneofDescriptorProto} message OneofDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            OneofDescriptorProto.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.name != null && Object.hasOwnProperty.call(message, "name"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.name);
+                if (message.options != null && Object.hasOwnProperty.call(message, "options"))
+                    $root.google.protobuf.OneofOptions.encode(message.options, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified OneofDescriptorProto message, length delimited. Does not implicitly {@link google.protobuf.OneofDescriptorProto.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.OneofDescriptorProto
+             * @static
+             * @param {google.protobuf.IOneofDescriptorProto} message OneofDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            OneofDescriptorProto.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes an OneofDescriptorProto message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.OneofDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.OneofDescriptorProto} OneofDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            OneofDescriptorProto.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.OneofDescriptorProto();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.name = reader.string();
+                        break;
+                    case 2:
+                        message.options = $root.google.protobuf.OneofOptions.decode(reader, reader.uint32());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes an OneofDescriptorProto message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.OneofDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.OneofDescriptorProto} OneofDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            OneofDescriptorProto.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies an OneofDescriptorProto message.
+             * @function verify
+             * @memberof google.protobuf.OneofDescriptorProto
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            OneofDescriptorProto.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.name != null && message.hasOwnProperty("name"))
+                    if (!$util.isString(message.name))
+                        return "name: string expected";
+                if (message.options != null && message.hasOwnProperty("options")) {
+                    var error = $root.google.protobuf.OneofOptions.verify(message.options);
+                    if (error)
+                        return "options." + error;
+                }
+                return null;
+            };
+
+            /**
+             * Creates an OneofDescriptorProto message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.OneofDescriptorProto
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.OneofDescriptorProto} OneofDescriptorProto
+             */
+            OneofDescriptorProto.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.OneofDescriptorProto)
+                    return object;
+                var message = new $root.google.protobuf.OneofDescriptorProto();
+                if (object.name != null)
+                    message.name = String(object.name);
+                if (object.options != null) {
+                    if (typeof object.options !== "object")
+                        throw TypeError(".google.protobuf.OneofDescriptorProto.options: object expected");
+                    message.options = $root.google.protobuf.OneofOptions.fromObject(object.options);
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from an OneofDescriptorProto message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.OneofDescriptorProto
+             * @static
+             * @param {google.protobuf.OneofDescriptorProto} message OneofDescriptorProto
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            OneofDescriptorProto.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults) {
+                    object.name = "";
+                    object.options = null;
+                }
+                if (message.name != null && message.hasOwnProperty("name"))
+                    object.name = message.name;
+                if (message.options != null && message.hasOwnProperty("options"))
+                    object.options = $root.google.protobuf.OneofOptions.toObject(message.options, options);
+                return object;
+            };
+
+            /**
+             * Converts this OneofDescriptorProto to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.OneofDescriptorProto
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            OneofDescriptorProto.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for OneofDescriptorProto
+             * @function getTypeUrl
+             * @memberof google.protobuf.OneofDescriptorProto
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            OneofDescriptorProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.OneofDescriptorProto";
+            };
+
+            return OneofDescriptorProto;
+        })();
+
+        protobuf.EnumDescriptorProto = (function() {
+
+            /**
+             * Properties of an EnumDescriptorProto.
+             * @memberof google.protobuf
+             * @interface IEnumDescriptorProto
+             * @property {string|null} [name] EnumDescriptorProto name
+             * @property {Array.<google.protobuf.IEnumValueDescriptorProto>|null} [value] EnumDescriptorProto value
+             * @property {google.protobuf.IEnumOptions|null} [options] EnumDescriptorProto options
+             */
+
+            /**
+             * Constructs a new EnumDescriptorProto.
+             * @memberof google.protobuf
+             * @classdesc Represents an EnumDescriptorProto.
+             * @implements IEnumDescriptorProto
+             * @constructor
+             * @param {google.protobuf.IEnumDescriptorProto=} [properties] Properties to set
+             */
+            function EnumDescriptorProto(properties) {
+                this.value = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * EnumDescriptorProto name.
+             * @member {string} name
+             * @memberof google.protobuf.EnumDescriptorProto
+             * @instance
+             */
+            EnumDescriptorProto.prototype.name = "";
+
+            /**
+             * EnumDescriptorProto value.
+             * @member {Array.<google.protobuf.IEnumValueDescriptorProto>} value
+             * @memberof google.protobuf.EnumDescriptorProto
+             * @instance
+             */
+            EnumDescriptorProto.prototype.value = $util.emptyArray;
+
+            /**
+             * EnumDescriptorProto options.
+             * @member {google.protobuf.IEnumOptions|null|undefined} options
+             * @memberof google.protobuf.EnumDescriptorProto
+             * @instance
+             */
+            EnumDescriptorProto.prototype.options = null;
+
+            /**
+             * Creates a new EnumDescriptorProto instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.EnumDescriptorProto
+             * @static
+             * @param {google.protobuf.IEnumDescriptorProto=} [properties] Properties to set
+             * @returns {google.protobuf.EnumDescriptorProto} EnumDescriptorProto instance
+             */
+            EnumDescriptorProto.create = function create(properties) {
+                return new EnumDescriptorProto(properties);
+            };
+
+            /**
+             * Encodes the specified EnumDescriptorProto message. Does not implicitly {@link google.protobuf.EnumDescriptorProto.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.EnumDescriptorProto
+             * @static
+             * @param {google.protobuf.IEnumDescriptorProto} message EnumDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            EnumDescriptorProto.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.name != null && Object.hasOwnProperty.call(message, "name"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.name);
+                if (message.value != null && message.value.length)
+                    for (var i = 0; i < message.value.length; ++i)
+                        $root.google.protobuf.EnumValueDescriptorProto.encode(message.value[i], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim();
+                if (message.options != null && Object.hasOwnProperty.call(message, "options"))
+                    $root.google.protobuf.EnumOptions.encode(message.options, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified EnumDescriptorProto message, length delimited. Does not implicitly {@link google.protobuf.EnumDescriptorProto.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.EnumDescriptorProto
+             * @static
+             * @param {google.protobuf.IEnumDescriptorProto} message EnumDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            EnumDescriptorProto.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes an EnumDescriptorProto message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.EnumDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.EnumDescriptorProto} EnumDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            EnumDescriptorProto.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.EnumDescriptorProto();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.name = reader.string();
+                        break;
+                    case 2:
+                        if (!(message.value && message.value.length))
+                            message.value = [];
+                        message.value.push($root.google.protobuf.EnumValueDescriptorProto.decode(reader, reader.uint32()));
+                        break;
+                    case 3:
+                        message.options = $root.google.protobuf.EnumOptions.decode(reader, reader.uint32());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes an EnumDescriptorProto message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.EnumDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.EnumDescriptorProto} EnumDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            EnumDescriptorProto.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies an EnumDescriptorProto message.
+             * @function verify
+             * @memberof google.protobuf.EnumDescriptorProto
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            EnumDescriptorProto.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.name != null && message.hasOwnProperty("name"))
+                    if (!$util.isString(message.name))
+                        return "name: string expected";
+                if (message.value != null && message.hasOwnProperty("value")) {
+                    if (!Array.isArray(message.value))
+                        return "value: array expected";
+                    for (var i = 0; i < message.value.length; ++i) {
+                        var error = $root.google.protobuf.EnumValueDescriptorProto.verify(message.value[i]);
+                        if (error)
+                            return "value." + error;
+                    }
+                }
+                if (message.options != null && message.hasOwnProperty("options")) {
+                    var error = $root.google.protobuf.EnumOptions.verify(message.options);
+                    if (error)
+                        return "options." + error;
+                }
+                return null;
+            };
+
+            /**
+             * Creates an EnumDescriptorProto message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.EnumDescriptorProto
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.EnumDescriptorProto} EnumDescriptorProto
+             */
+            EnumDescriptorProto.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.EnumDescriptorProto)
+                    return object;
+                var message = new $root.google.protobuf.EnumDescriptorProto();
+                if (object.name != null)
+                    message.name = String(object.name);
+                if (object.value) {
+                    if (!Array.isArray(object.value))
+                        throw TypeError(".google.protobuf.EnumDescriptorProto.value: array expected");
+                    message.value = [];
+                    for (var i = 0; i < object.value.length; ++i) {
+                        if (typeof object.value[i] !== "object")
+                            throw TypeError(".google.protobuf.EnumDescriptorProto.value: object expected");
+                        message.value[i] = $root.google.protobuf.EnumValueDescriptorProto.fromObject(object.value[i]);
+                    }
+                }
+                if (object.options != null) {
+                    if (typeof object.options !== "object")
+                        throw TypeError(".google.protobuf.EnumDescriptorProto.options: object expected");
+                    message.options = $root.google.protobuf.EnumOptions.fromObject(object.options);
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from an EnumDescriptorProto message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.EnumDescriptorProto
+             * @static
+             * @param {google.protobuf.EnumDescriptorProto} message EnumDescriptorProto
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            EnumDescriptorProto.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.value = [];
+                if (options.defaults) {
+                    object.name = "";
+                    object.options = null;
+                }
+                if (message.name != null && message.hasOwnProperty("name"))
+                    object.name = message.name;
+                if (message.value && message.value.length) {
+                    object.value = [];
+                    for (var j = 0; j < message.value.length; ++j)
+                        object.value[j] = $root.google.protobuf.EnumValueDescriptorProto.toObject(message.value[j], options);
+                }
+                if (message.options != null && message.hasOwnProperty("options"))
+                    object.options = $root.google.protobuf.EnumOptions.toObject(message.options, options);
+                return object;
+            };
+
+            /**
+             * Converts this EnumDescriptorProto to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.EnumDescriptorProto
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            EnumDescriptorProto.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for EnumDescriptorProto
+             * @function getTypeUrl
+             * @memberof google.protobuf.EnumDescriptorProto
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            EnumDescriptorProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.EnumDescriptorProto";
+            };
+
+            return EnumDescriptorProto;
+        })();
+
+        protobuf.EnumValueDescriptorProto = (function() {
+
+            /**
+             * Properties of an EnumValueDescriptorProto.
+             * @memberof google.protobuf
+             * @interface IEnumValueDescriptorProto
+             * @property {string|null} [name] EnumValueDescriptorProto name
+             * @property {number|null} [number] EnumValueDescriptorProto number
+             * @property {google.protobuf.IEnumValueOptions|null} [options] EnumValueDescriptorProto options
+             */
+
+            /**
+             * Constructs a new EnumValueDescriptorProto.
+             * @memberof google.protobuf
+             * @classdesc Represents an EnumValueDescriptorProto.
+             * @implements IEnumValueDescriptorProto
+             * @constructor
+             * @param {google.protobuf.IEnumValueDescriptorProto=} [properties] Properties to set
+             */
+            function EnumValueDescriptorProto(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * EnumValueDescriptorProto name.
+             * @member {string} name
+             * @memberof google.protobuf.EnumValueDescriptorProto
+             * @instance
+             */
+            EnumValueDescriptorProto.prototype.name = "";
+
+            /**
+             * EnumValueDescriptorProto number.
+             * @member {number} number
+             * @memberof google.protobuf.EnumValueDescriptorProto
+             * @instance
+             */
+            EnumValueDescriptorProto.prototype.number = 0;
+
+            /**
+             * EnumValueDescriptorProto options.
+             * @member {google.protobuf.IEnumValueOptions|null|undefined} options
+             * @memberof google.protobuf.EnumValueDescriptorProto
+             * @instance
+             */
+            EnumValueDescriptorProto.prototype.options = null;
+
+            /**
+             * Creates a new EnumValueDescriptorProto instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.EnumValueDescriptorProto
+             * @static
+             * @param {google.protobuf.IEnumValueDescriptorProto=} [properties] Properties to set
+             * @returns {google.protobuf.EnumValueDescriptorProto} EnumValueDescriptorProto instance
+             */
+            EnumValueDescriptorProto.create = function create(properties) {
+                return new EnumValueDescriptorProto(properties);
+            };
+
+            /**
+             * Encodes the specified EnumValueDescriptorProto message. Does not implicitly {@link google.protobuf.EnumValueDescriptorProto.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.EnumValueDescriptorProto
+             * @static
+             * @param {google.protobuf.IEnumValueDescriptorProto} message EnumValueDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            EnumValueDescriptorProto.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.name != null && Object.hasOwnProperty.call(message, "name"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.name);
+                if (message.number != null && Object.hasOwnProperty.call(message, "number"))
+                    writer.uint32(/* id 2, wireType 0 =*/16).int32(message.number);
+                if (message.options != null && Object.hasOwnProperty.call(message, "options"))
+                    $root.google.protobuf.EnumValueOptions.encode(message.options, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified EnumValueDescriptorProto message, length delimited. Does not implicitly {@link google.protobuf.EnumValueDescriptorProto.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.EnumValueDescriptorProto
+             * @static
+             * @param {google.protobuf.IEnumValueDescriptorProto} message EnumValueDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            EnumValueDescriptorProto.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes an EnumValueDescriptorProto message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.EnumValueDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.EnumValueDescriptorProto} EnumValueDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            EnumValueDescriptorProto.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.EnumValueDescriptorProto();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.name = reader.string();
+                        break;
+                    case 2:
+                        message.number = reader.int32();
+                        break;
+                    case 3:
+                        message.options = $root.google.protobuf.EnumValueOptions.decode(reader, reader.uint32());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes an EnumValueDescriptorProto message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.EnumValueDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.EnumValueDescriptorProto} EnumValueDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            EnumValueDescriptorProto.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies an EnumValueDescriptorProto message.
+             * @function verify
+             * @memberof google.protobuf.EnumValueDescriptorProto
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            EnumValueDescriptorProto.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.name != null && message.hasOwnProperty("name"))
+                    if (!$util.isString(message.name))
+                        return "name: string expected";
+                if (message.number != null && message.hasOwnProperty("number"))
+                    if (!$util.isInteger(message.number))
+                        return "number: integer expected";
+                if (message.options != null && message.hasOwnProperty("options")) {
+                    var error = $root.google.protobuf.EnumValueOptions.verify(message.options);
+                    if (error)
+                        return "options." + error;
+                }
+                return null;
+            };
+
+            /**
+             * Creates an EnumValueDescriptorProto message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.EnumValueDescriptorProto
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.EnumValueDescriptorProto} EnumValueDescriptorProto
+             */
+            EnumValueDescriptorProto.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.EnumValueDescriptorProto)
+                    return object;
+                var message = new $root.google.protobuf.EnumValueDescriptorProto();
+                if (object.name != null)
+                    message.name = String(object.name);
+                if (object.number != null)
+                    message.number = object.number | 0;
+                if (object.options != null) {
+                    if (typeof object.options !== "object")
+                        throw TypeError(".google.protobuf.EnumValueDescriptorProto.options: object expected");
+                    message.options = $root.google.protobuf.EnumValueOptions.fromObject(object.options);
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from an EnumValueDescriptorProto message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.EnumValueDescriptorProto
+             * @static
+             * @param {google.protobuf.EnumValueDescriptorProto} message EnumValueDescriptorProto
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            EnumValueDescriptorProto.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults) {
+                    object.name = "";
+                    object.number = 0;
+                    object.options = null;
+                }
+                if (message.name != null && message.hasOwnProperty("name"))
+                    object.name = message.name;
+                if (message.number != null && message.hasOwnProperty("number"))
+                    object.number = message.number;
+                if (message.options != null && message.hasOwnProperty("options"))
+                    object.options = $root.google.protobuf.EnumValueOptions.toObject(message.options, options);
+                return object;
+            };
+
+            /**
+             * Converts this EnumValueDescriptorProto to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.EnumValueDescriptorProto
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            EnumValueDescriptorProto.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for EnumValueDescriptorProto
+             * @function getTypeUrl
+             * @memberof google.protobuf.EnumValueDescriptorProto
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            EnumValueDescriptorProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.EnumValueDescriptorProto";
+            };
+
+            return EnumValueDescriptorProto;
+        })();
+
+        protobuf.ServiceDescriptorProto = (function() {
+
+            /**
+             * Properties of a ServiceDescriptorProto.
+             * @memberof google.protobuf
+             * @interface IServiceDescriptorProto
+             * @property {string|null} [name] ServiceDescriptorProto name
+             * @property {Array.<google.protobuf.IMethodDescriptorProto>|null} [method] ServiceDescriptorProto method
+             * @property {google.protobuf.IServiceOptions|null} [options] ServiceDescriptorProto options
+             */
+
+            /**
+             * Constructs a new ServiceDescriptorProto.
+             * @memberof google.protobuf
+             * @classdesc Represents a ServiceDescriptorProto.
+             * @implements IServiceDescriptorProto
+             * @constructor
+             * @param {google.protobuf.IServiceDescriptorProto=} [properties] Properties to set
+             */
+            function ServiceDescriptorProto(properties) {
+                this.method = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * ServiceDescriptorProto name.
+             * @member {string} name
+             * @memberof google.protobuf.ServiceDescriptorProto
+             * @instance
+             */
+            ServiceDescriptorProto.prototype.name = "";
+
+            /**
+             * ServiceDescriptorProto method.
+             * @member {Array.<google.protobuf.IMethodDescriptorProto>} method
+             * @memberof google.protobuf.ServiceDescriptorProto
+             * @instance
+             */
+            ServiceDescriptorProto.prototype.method = $util.emptyArray;
+
+            /**
+             * ServiceDescriptorProto options.
+             * @member {google.protobuf.IServiceOptions|null|undefined} options
+             * @memberof google.protobuf.ServiceDescriptorProto
+             * @instance
+             */
+            ServiceDescriptorProto.prototype.options = null;
+
+            /**
+             * Creates a new ServiceDescriptorProto instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.ServiceDescriptorProto
+             * @static
+             * @param {google.protobuf.IServiceDescriptorProto=} [properties] Properties to set
+             * @returns {google.protobuf.ServiceDescriptorProto} ServiceDescriptorProto instance
+             */
+            ServiceDescriptorProto.create = function create(properties) {
+                return new ServiceDescriptorProto(properties);
+            };
+
+            /**
+             * Encodes the specified ServiceDescriptorProto message. Does not implicitly {@link google.protobuf.ServiceDescriptorProto.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.ServiceDescriptorProto
+             * @static
+             * @param {google.protobuf.IServiceDescriptorProto} message ServiceDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            ServiceDescriptorProto.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.name != null && Object.hasOwnProperty.call(message, "name"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.name);
+                if (message.method != null && message.method.length)
+                    for (var i = 0; i < message.method.length; ++i)
+                        $root.google.protobuf.MethodDescriptorProto.encode(message.method[i], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim();
+                if (message.options != null && Object.hasOwnProperty.call(message, "options"))
+                    $root.google.protobuf.ServiceOptions.encode(message.options, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified ServiceDescriptorProto message, length delimited. Does not implicitly {@link google.protobuf.ServiceDescriptorProto.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.ServiceDescriptorProto
+             * @static
+             * @param {google.protobuf.IServiceDescriptorProto} message ServiceDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            ServiceDescriptorProto.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a ServiceDescriptorProto message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.ServiceDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.ServiceDescriptorProto} ServiceDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            ServiceDescriptorProto.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.ServiceDescriptorProto();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.name = reader.string();
+                        break;
+                    case 2:
+                        if (!(message.method && message.method.length))
+                            message.method = [];
+                        message.method.push($root.google.protobuf.MethodDescriptorProto.decode(reader, reader.uint32()));
+                        break;
+                    case 3:
+                        message.options = $root.google.protobuf.ServiceOptions.decode(reader, reader.uint32());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a ServiceDescriptorProto message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.ServiceDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.ServiceDescriptorProto} ServiceDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            ServiceDescriptorProto.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a ServiceDescriptorProto message.
+             * @function verify
+             * @memberof google.protobuf.ServiceDescriptorProto
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            ServiceDescriptorProto.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.name != null && message.hasOwnProperty("name"))
+                    if (!$util.isString(message.name))
+                        return "name: string expected";
+                if (message.method != null && message.hasOwnProperty("method")) {
+                    if (!Array.isArray(message.method))
+                        return "method: array expected";
+                    for (var i = 0; i < message.method.length; ++i) {
+                        var error = $root.google.protobuf.MethodDescriptorProto.verify(message.method[i]);
+                        if (error)
+                            return "method." + error;
+                    }
+                }
+                if (message.options != null && message.hasOwnProperty("options")) {
+                    var error = $root.google.protobuf.ServiceOptions.verify(message.options);
+                    if (error)
+                        return "options." + error;
+                }
+                return null;
+            };
+
+            /**
+             * Creates a ServiceDescriptorProto message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.ServiceDescriptorProto
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.ServiceDescriptorProto} ServiceDescriptorProto
+             */
+            ServiceDescriptorProto.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.ServiceDescriptorProto)
+                    return object;
+                var message = new $root.google.protobuf.ServiceDescriptorProto();
+                if (object.name != null)
+                    message.name = String(object.name);
+                if (object.method) {
+                    if (!Array.isArray(object.method))
+                        throw TypeError(".google.protobuf.ServiceDescriptorProto.method: array expected");
+                    message.method = [];
+                    for (var i = 0; i < object.method.length; ++i) {
+                        if (typeof object.method[i] !== "object")
+                            throw TypeError(".google.protobuf.ServiceDescriptorProto.method: object expected");
+                        message.method[i] = $root.google.protobuf.MethodDescriptorProto.fromObject(object.method[i]);
+                    }
+                }
+                if (object.options != null) {
+                    if (typeof object.options !== "object")
+                        throw TypeError(".google.protobuf.ServiceDescriptorProto.options: object expected");
+                    message.options = $root.google.protobuf.ServiceOptions.fromObject(object.options);
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a ServiceDescriptorProto message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.ServiceDescriptorProto
+             * @static
+             * @param {google.protobuf.ServiceDescriptorProto} message ServiceDescriptorProto
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            ServiceDescriptorProto.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.method = [];
+                if (options.defaults) {
+                    object.name = "";
+                    object.options = null;
+                }
+                if (message.name != null && message.hasOwnProperty("name"))
+                    object.name = message.name;
+                if (message.method && message.method.length) {
+                    object.method = [];
+                    for (var j = 0; j < message.method.length; ++j)
+                        object.method[j] = $root.google.protobuf.MethodDescriptorProto.toObject(message.method[j], options);
+                }
+                if (message.options != null && message.hasOwnProperty("options"))
+                    object.options = $root.google.protobuf.ServiceOptions.toObject(message.options, options);
+                return object;
+            };
+
+            /**
+             * Converts this ServiceDescriptorProto to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.ServiceDescriptorProto
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            ServiceDescriptorProto.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for ServiceDescriptorProto
+             * @function getTypeUrl
+             * @memberof google.protobuf.ServiceDescriptorProto
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            ServiceDescriptorProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.ServiceDescriptorProto";
+            };
+
+            return ServiceDescriptorProto;
+        })();
+
+        protobuf.MethodDescriptorProto = (function() {
+
+            /**
+             * Properties of a MethodDescriptorProto.
+             * @memberof google.protobuf
+             * @interface IMethodDescriptorProto
+             * @property {string|null} [name] MethodDescriptorProto name
+             * @property {string|null} [inputType] MethodDescriptorProto inputType
+             * @property {string|null} [outputType] MethodDescriptorProto outputType
+             * @property {google.protobuf.IMethodOptions|null} [options] MethodDescriptorProto options
+             * @property {boolean|null} [clientStreaming] MethodDescriptorProto clientStreaming
+             * @property {boolean|null} [serverStreaming] MethodDescriptorProto serverStreaming
+             */
+
+            /**
+             * Constructs a new MethodDescriptorProto.
+             * @memberof google.protobuf
+             * @classdesc Represents a MethodDescriptorProto.
+             * @implements IMethodDescriptorProto
+             * @constructor
+             * @param {google.protobuf.IMethodDescriptorProto=} [properties] Properties to set
+             */
+            function MethodDescriptorProto(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * MethodDescriptorProto name.
+             * @member {string} name
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @instance
+             */
+            MethodDescriptorProto.prototype.name = "";
+
+            /**
+             * MethodDescriptorProto inputType.
+             * @member {string} inputType
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @instance
+             */
+            MethodDescriptorProto.prototype.inputType = "";
+
+            /**
+             * MethodDescriptorProto outputType.
+             * @member {string} outputType
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @instance
+             */
+            MethodDescriptorProto.prototype.outputType = "";
+
+            /**
+             * MethodDescriptorProto options.
+             * @member {google.protobuf.IMethodOptions|null|undefined} options
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @instance
+             */
+            MethodDescriptorProto.prototype.options = null;
+
+            /**
+             * MethodDescriptorProto clientStreaming.
+             * @member {boolean} clientStreaming
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @instance
+             */
+            MethodDescriptorProto.prototype.clientStreaming = false;
+
+            /**
+             * MethodDescriptorProto serverStreaming.
+             * @member {boolean} serverStreaming
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @instance
+             */
+            MethodDescriptorProto.prototype.serverStreaming = false;
+
+            /**
+             * Creates a new MethodDescriptorProto instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @static
+             * @param {google.protobuf.IMethodDescriptorProto=} [properties] Properties to set
+             * @returns {google.protobuf.MethodDescriptorProto} MethodDescriptorProto instance
+             */
+            MethodDescriptorProto.create = function create(properties) {
+                return new MethodDescriptorProto(properties);
+            };
+
+            /**
+             * Encodes the specified MethodDescriptorProto message. Does not implicitly {@link google.protobuf.MethodDescriptorProto.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @static
+             * @param {google.protobuf.IMethodDescriptorProto} message MethodDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            MethodDescriptorProto.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.name != null && Object.hasOwnProperty.call(message, "name"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.name);
+                if (message.inputType != null && Object.hasOwnProperty.call(message, "inputType"))
+                    writer.uint32(/* id 2, wireType 2 =*/18).string(message.inputType);
+                if (message.outputType != null && Object.hasOwnProperty.call(message, "outputType"))
+                    writer.uint32(/* id 3, wireType 2 =*/26).string(message.outputType);
+                if (message.options != null && Object.hasOwnProperty.call(message, "options"))
+                    $root.google.protobuf.MethodOptions.encode(message.options, writer.uint32(/* id 4, wireType 2 =*/34).fork()).ldelim();
+                if (message.clientStreaming != null && Object.hasOwnProperty.call(message, "clientStreaming"))
+                    writer.uint32(/* id 5, wireType 0 =*/40).bool(message.clientStreaming);
+                if (message.serverStreaming != null && Object.hasOwnProperty.call(message, "serverStreaming"))
+                    writer.uint32(/* id 6, wireType 0 =*/48).bool(message.serverStreaming);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified MethodDescriptorProto message, length delimited. Does not implicitly {@link google.protobuf.MethodDescriptorProto.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @static
+             * @param {google.protobuf.IMethodDescriptorProto} message MethodDescriptorProto message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            MethodDescriptorProto.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a MethodDescriptorProto message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.MethodDescriptorProto} MethodDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            MethodDescriptorProto.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.MethodDescriptorProto();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.name = reader.string();
+                        break;
+                    case 2:
+                        message.inputType = reader.string();
+                        break;
+                    case 3:
+                        message.outputType = reader.string();
+                        break;
+                    case 4:
+                        message.options = $root.google.protobuf.MethodOptions.decode(reader, reader.uint32());
+                        break;
+                    case 5:
+                        message.clientStreaming = reader.bool();
+                        break;
+                    case 6:
+                        message.serverStreaming = reader.bool();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a MethodDescriptorProto message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.MethodDescriptorProto} MethodDescriptorProto
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            MethodDescriptorProto.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a MethodDescriptorProto message.
+             * @function verify
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            MethodDescriptorProto.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.name != null && message.hasOwnProperty("name"))
+                    if (!$util.isString(message.name))
+                        return "name: string expected";
+                if (message.inputType != null && message.hasOwnProperty("inputType"))
+                    if (!$util.isString(message.inputType))
+                        return "inputType: string expected";
+                if (message.outputType != null && message.hasOwnProperty("outputType"))
+                    if (!$util.isString(message.outputType))
+                        return "outputType: string expected";
+                if (message.options != null && message.hasOwnProperty("options")) {
+                    var error = $root.google.protobuf.MethodOptions.verify(message.options);
+                    if (error)
+                        return "options." + error;
+                }
+                if (message.clientStreaming != null && message.hasOwnProperty("clientStreaming"))
+                    if (typeof message.clientStreaming !== "boolean")
+                        return "clientStreaming: boolean expected";
+                if (message.serverStreaming != null && message.hasOwnProperty("serverStreaming"))
+                    if (typeof message.serverStreaming !== "boolean")
+                        return "serverStreaming: boolean expected";
+                return null;
+            };
+
+            /**
+             * Creates a MethodDescriptorProto message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.MethodDescriptorProto} MethodDescriptorProto
+             */
+            MethodDescriptorProto.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.MethodDescriptorProto)
+                    return object;
+                var message = new $root.google.protobuf.MethodDescriptorProto();
+                if (object.name != null)
+                    message.name = String(object.name);
+                if (object.inputType != null)
+                    message.inputType = String(object.inputType);
+                if (object.outputType != null)
+                    message.outputType = String(object.outputType);
+                if (object.options != null) {
+                    if (typeof object.options !== "object")
+                        throw TypeError(".google.protobuf.MethodDescriptorProto.options: object expected");
+                    message.options = $root.google.protobuf.MethodOptions.fromObject(object.options);
+                }
+                if (object.clientStreaming != null)
+                    message.clientStreaming = Boolean(object.clientStreaming);
+                if (object.serverStreaming != null)
+                    message.serverStreaming = Boolean(object.serverStreaming);
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a MethodDescriptorProto message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @static
+             * @param {google.protobuf.MethodDescriptorProto} message MethodDescriptorProto
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            MethodDescriptorProto.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.defaults) {
+                    object.name = "";
+                    object.inputType = "";
+                    object.outputType = "";
+                    object.options = null;
+                    object.clientStreaming = false;
+                    object.serverStreaming = false;
+                }
+                if (message.name != null && message.hasOwnProperty("name"))
+                    object.name = message.name;
+                if (message.inputType != null && message.hasOwnProperty("inputType"))
+                    object.inputType = message.inputType;
+                if (message.outputType != null && message.hasOwnProperty("outputType"))
+                    object.outputType = message.outputType;
+                if (message.options != null && message.hasOwnProperty("options"))
+                    object.options = $root.google.protobuf.MethodOptions.toObject(message.options, options);
+                if (message.clientStreaming != null && message.hasOwnProperty("clientStreaming"))
+                    object.clientStreaming = message.clientStreaming;
+                if (message.serverStreaming != null && message.hasOwnProperty("serverStreaming"))
+                    object.serverStreaming = message.serverStreaming;
+                return object;
+            };
+
+            /**
+             * Converts this MethodDescriptorProto to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            MethodDescriptorProto.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for MethodDescriptorProto
+             * @function getTypeUrl
+             * @memberof google.protobuf.MethodDescriptorProto
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            MethodDescriptorProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.MethodDescriptorProto";
+            };
+
+            return MethodDescriptorProto;
+        })();
+
+        protobuf.FileOptions = (function() {
+
+            /**
+             * Properties of a FileOptions.
+             * @memberof google.protobuf
+             * @interface IFileOptions
+             * @property {string|null} [javaPackage] FileOptions javaPackage
+             * @property {string|null} [javaOuterClassname] FileOptions javaOuterClassname
+             * @property {boolean|null} [javaMultipleFiles] FileOptions javaMultipleFiles
+             * @property {boolean|null} [javaGenerateEqualsAndHash] FileOptions javaGenerateEqualsAndHash
+             * @property {boolean|null} [javaStringCheckUtf8] FileOptions javaStringCheckUtf8
+             * @property {google.protobuf.FileOptions.OptimizeMode|null} [optimizeFor] FileOptions optimizeFor
+             * @property {string|null} [goPackage] FileOptions goPackage
+             * @property {boolean|null} [ccGenericServices] FileOptions ccGenericServices
+             * @property {boolean|null} [javaGenericServices] FileOptions javaGenericServices
+             * @property {boolean|null} [pyGenericServices] FileOptions pyGenericServices
+             * @property {boolean|null} [deprecated] FileOptions deprecated
+             * @property {boolean|null} [ccEnableArenas] FileOptions ccEnableArenas
+             * @property {string|null} [objcClassPrefix] FileOptions objcClassPrefix
+             * @property {string|null} [csharpNamespace] FileOptions csharpNamespace
+             * @property {Array.<google.protobuf.IUninterpretedOption>|null} [uninterpretedOption] FileOptions uninterpretedOption
+             */
+
+            /**
+             * Constructs a new FileOptions.
+             * @memberof google.protobuf
+             * @classdesc Represents a FileOptions.
+             * @implements IFileOptions
+             * @constructor
+             * @param {google.protobuf.IFileOptions=} [properties] Properties to set
+             */
+            function FileOptions(properties) {
+                this.uninterpretedOption = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * FileOptions javaPackage.
+             * @member {string} javaPackage
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.javaPackage = "";
+
+            /**
+             * FileOptions javaOuterClassname.
+             * @member {string} javaOuterClassname
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.javaOuterClassname = "";
+
+            /**
+             * FileOptions javaMultipleFiles.
+             * @member {boolean} javaMultipleFiles
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.javaMultipleFiles = false;
+
+            /**
+             * FileOptions javaGenerateEqualsAndHash.
+             * @member {boolean} javaGenerateEqualsAndHash
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.javaGenerateEqualsAndHash = false;
+
+            /**
+             * FileOptions javaStringCheckUtf8.
+             * @member {boolean} javaStringCheckUtf8
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.javaStringCheckUtf8 = false;
+
+            /**
+             * FileOptions optimizeFor.
+             * @member {google.protobuf.FileOptions.OptimizeMode} optimizeFor
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.optimizeFor = 1;
+
+            /**
+             * FileOptions goPackage.
+             * @member {string} goPackage
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.goPackage = "";
+
+            /**
+             * FileOptions ccGenericServices.
+             * @member {boolean} ccGenericServices
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.ccGenericServices = false;
+
+            /**
+             * FileOptions javaGenericServices.
+             * @member {boolean} javaGenericServices
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.javaGenericServices = false;
+
+            /**
+             * FileOptions pyGenericServices.
+             * @member {boolean} pyGenericServices
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.pyGenericServices = false;
+
+            /**
+             * FileOptions deprecated.
+             * @member {boolean} deprecated
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.deprecated = false;
+
+            /**
+             * FileOptions ccEnableArenas.
+             * @member {boolean} ccEnableArenas
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.ccEnableArenas = false;
+
+            /**
+             * FileOptions objcClassPrefix.
+             * @member {string} objcClassPrefix
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.objcClassPrefix = "";
+
+            /**
+             * FileOptions csharpNamespace.
+             * @member {string} csharpNamespace
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.csharpNamespace = "";
+
+            /**
+             * FileOptions uninterpretedOption.
+             * @member {Array.<google.protobuf.IUninterpretedOption>} uninterpretedOption
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             */
+            FileOptions.prototype.uninterpretedOption = $util.emptyArray;
+
+            /**
+             * Creates a new FileOptions instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.FileOptions
+             * @static
+             * @param {google.protobuf.IFileOptions=} [properties] Properties to set
+             * @returns {google.protobuf.FileOptions} FileOptions instance
+             */
+            FileOptions.create = function create(properties) {
+                return new FileOptions(properties);
+            };
+
+            /**
+             * Encodes the specified FileOptions message. Does not implicitly {@link google.protobuf.FileOptions.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.FileOptions
+             * @static
+             * @param {google.protobuf.IFileOptions} message FileOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            FileOptions.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.javaPackage != null && Object.hasOwnProperty.call(message, "javaPackage"))
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.javaPackage);
+                if (message.javaOuterClassname != null && Object.hasOwnProperty.call(message, "javaOuterClassname"))
+                    writer.uint32(/* id 8, wireType 2 =*/66).string(message.javaOuterClassname);
+                if (message.optimizeFor != null && Object.hasOwnProperty.call(message, "optimizeFor"))
+                    writer.uint32(/* id 9, wireType 0 =*/72).int32(message.optimizeFor);
+                if (message.javaMultipleFiles != null && Object.hasOwnProperty.call(message, "javaMultipleFiles"))
+                    writer.uint32(/* id 10, wireType 0 =*/80).bool(message.javaMultipleFiles);
+                if (message.goPackage != null && Object.hasOwnProperty.call(message, "goPackage"))
+                    writer.uint32(/* id 11, wireType 2 =*/90).string(message.goPackage);
+                if (message.ccGenericServices != null && Object.hasOwnProperty.call(message, "ccGenericServices"))
+                    writer.uint32(/* id 16, wireType 0 =*/128).bool(message.ccGenericServices);
+                if (message.javaGenericServices != null && Object.hasOwnProperty.call(message, "javaGenericServices"))
+                    writer.uint32(/* id 17, wireType 0 =*/136).bool(message.javaGenericServices);
+                if (message.pyGenericServices != null && Object.hasOwnProperty.call(message, "pyGenericServices"))
+                    writer.uint32(/* id 18, wireType 0 =*/144).bool(message.pyGenericServices);
+                if (message.javaGenerateEqualsAndHash != null && Object.hasOwnProperty.call(message, "javaGenerateEqualsAndHash"))
+                    writer.uint32(/* id 20, wireType 0 =*/160).bool(message.javaGenerateEqualsAndHash);
+                if (message.deprecated != null && Object.hasOwnProperty.call(message, "deprecated"))
+                    writer.uint32(/* id 23, wireType 0 =*/184).bool(message.deprecated);
+                if (message.javaStringCheckUtf8 != null && Object.hasOwnProperty.call(message, "javaStringCheckUtf8"))
+                    writer.uint32(/* id 27, wireType 0 =*/216).bool(message.javaStringCheckUtf8);
+                if (message.ccEnableArenas != null && Object.hasOwnProperty.call(message, "ccEnableArenas"))
+                    writer.uint32(/* id 31, wireType 0 =*/248).bool(message.ccEnableArenas);
+                if (message.objcClassPrefix != null && Object.hasOwnProperty.call(message, "objcClassPrefix"))
+                    writer.uint32(/* id 36, wireType 2 =*/290).string(message.objcClassPrefix);
+                if (message.csharpNamespace != null && Object.hasOwnProperty.call(message, "csharpNamespace"))
+                    writer.uint32(/* id 37, wireType 2 =*/298).string(message.csharpNamespace);
+                if (message.uninterpretedOption != null && message.uninterpretedOption.length)
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i)
+                        $root.google.protobuf.UninterpretedOption.encode(message.uninterpretedOption[i], writer.uint32(/* id 999, wireType 2 =*/7994).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified FileOptions message, length delimited. Does not implicitly {@link google.protobuf.FileOptions.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.FileOptions
+             * @static
+             * @param {google.protobuf.IFileOptions} message FileOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            FileOptions.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a FileOptions message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.FileOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.FileOptions} FileOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            FileOptions.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.FileOptions();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.javaPackage = reader.string();
+                        break;
+                    case 8:
+                        message.javaOuterClassname = reader.string();
+                        break;
+                    case 10:
+                        message.javaMultipleFiles = reader.bool();
+                        break;
+                    case 20:
+                        message.javaGenerateEqualsAndHash = reader.bool();
+                        break;
+                    case 27:
+                        message.javaStringCheckUtf8 = reader.bool();
+                        break;
+                    case 9:
+                        message.optimizeFor = reader.int32();
+                        break;
+                    case 11:
+                        message.goPackage = reader.string();
+                        break;
+                    case 16:
+                        message.ccGenericServices = reader.bool();
+                        break;
+                    case 17:
+                        message.javaGenericServices = reader.bool();
+                        break;
+                    case 18:
+                        message.pyGenericServices = reader.bool();
+                        break;
+                    case 23:
+                        message.deprecated = reader.bool();
+                        break;
+                    case 31:
+                        message.ccEnableArenas = reader.bool();
+                        break;
+                    case 36:
+                        message.objcClassPrefix = reader.string();
+                        break;
+                    case 37:
+                        message.csharpNamespace = reader.string();
+                        break;
+                    case 999:
+                        if (!(message.uninterpretedOption && message.uninterpretedOption.length))
+                            message.uninterpretedOption = [];
+                        message.uninterpretedOption.push($root.google.protobuf.UninterpretedOption.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a FileOptions message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.FileOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.FileOptions} FileOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            FileOptions.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a FileOptions message.
+             * @function verify
+             * @memberof google.protobuf.FileOptions
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            FileOptions.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.javaPackage != null && message.hasOwnProperty("javaPackage"))
+                    if (!$util.isString(message.javaPackage))
+                        return "javaPackage: string expected";
+                if (message.javaOuterClassname != null && message.hasOwnProperty("javaOuterClassname"))
+                    if (!$util.isString(message.javaOuterClassname))
+                        return "javaOuterClassname: string expected";
+                if (message.javaMultipleFiles != null && message.hasOwnProperty("javaMultipleFiles"))
+                    if (typeof message.javaMultipleFiles !== "boolean")
+                        return "javaMultipleFiles: boolean expected";
+                if (message.javaGenerateEqualsAndHash != null && message.hasOwnProperty("javaGenerateEqualsAndHash"))
+                    if (typeof message.javaGenerateEqualsAndHash !== "boolean")
+                        return "javaGenerateEqualsAndHash: boolean expected";
+                if (message.javaStringCheckUtf8 != null && message.hasOwnProperty("javaStringCheckUtf8"))
+                    if (typeof message.javaStringCheckUtf8 !== "boolean")
+                        return "javaStringCheckUtf8: boolean expected";
+                if (message.optimizeFor != null && message.hasOwnProperty("optimizeFor"))
+                    switch (message.optimizeFor) {
+                    default:
+                        return "optimizeFor: enum value expected";
+                    case 1:
+                    case 2:
+                    case 3:
+                        break;
+                    }
+                if (message.goPackage != null && message.hasOwnProperty("goPackage"))
+                    if (!$util.isString(message.goPackage))
+                        return "goPackage: string expected";
+                if (message.ccGenericServices != null && message.hasOwnProperty("ccGenericServices"))
+                    if (typeof message.ccGenericServices !== "boolean")
+                        return "ccGenericServices: boolean expected";
+                if (message.javaGenericServices != null && message.hasOwnProperty("javaGenericServices"))
+                    if (typeof message.javaGenericServices !== "boolean")
+                        return "javaGenericServices: boolean expected";
+                if (message.pyGenericServices != null && message.hasOwnProperty("pyGenericServices"))
+                    if (typeof message.pyGenericServices !== "boolean")
+                        return "pyGenericServices: boolean expected";
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    if (typeof message.deprecated !== "boolean")
+                        return "deprecated: boolean expected";
+                if (message.ccEnableArenas != null && message.hasOwnProperty("ccEnableArenas"))
+                    if (typeof message.ccEnableArenas !== "boolean")
+                        return "ccEnableArenas: boolean expected";
+                if (message.objcClassPrefix != null && message.hasOwnProperty("objcClassPrefix"))
+                    if (!$util.isString(message.objcClassPrefix))
+                        return "objcClassPrefix: string expected";
+                if (message.csharpNamespace != null && message.hasOwnProperty("csharpNamespace"))
+                    if (!$util.isString(message.csharpNamespace))
+                        return "csharpNamespace: string expected";
+                if (message.uninterpretedOption != null && message.hasOwnProperty("uninterpretedOption")) {
+                    if (!Array.isArray(message.uninterpretedOption))
+                        return "uninterpretedOption: array expected";
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i) {
+                        var error = $root.google.protobuf.UninterpretedOption.verify(message.uninterpretedOption[i]);
+                        if (error)
+                            return "uninterpretedOption." + error;
+                    }
+                }
+                return null;
+            };
+
+            /**
+             * Creates a FileOptions message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.FileOptions
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.FileOptions} FileOptions
+             */
+            FileOptions.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.FileOptions)
+                    return object;
+                var message = new $root.google.protobuf.FileOptions();
+                if (object.javaPackage != null)
+                    message.javaPackage = String(object.javaPackage);
+                if (object.javaOuterClassname != null)
+                    message.javaOuterClassname = String(object.javaOuterClassname);
+                if (object.javaMultipleFiles != null)
+                    message.javaMultipleFiles = Boolean(object.javaMultipleFiles);
+                if (object.javaGenerateEqualsAndHash != null)
+                    message.javaGenerateEqualsAndHash = Boolean(object.javaGenerateEqualsAndHash);
+                if (object.javaStringCheckUtf8 != null)
+                    message.javaStringCheckUtf8 = Boolean(object.javaStringCheckUtf8);
+                switch (object.optimizeFor) {
+                case "SPEED":
+                case 1:
+                    message.optimizeFor = 1;
+                    break;
+                case "CODE_SIZE":
+                case 2:
+                    message.optimizeFor = 2;
+                    break;
+                case "LITE_RUNTIME":
+                case 3:
+                    message.optimizeFor = 3;
+                    break;
+                }
+                if (object.goPackage != null)
+                    message.goPackage = String(object.goPackage);
+                if (object.ccGenericServices != null)
+                    message.ccGenericServices = Boolean(object.ccGenericServices);
+                if (object.javaGenericServices != null)
+                    message.javaGenericServices = Boolean(object.javaGenericServices);
+                if (object.pyGenericServices != null)
+                    message.pyGenericServices = Boolean(object.pyGenericServices);
+                if (object.deprecated != null)
+                    message.deprecated = Boolean(object.deprecated);
+                if (object.ccEnableArenas != null)
+                    message.ccEnableArenas = Boolean(object.ccEnableArenas);
+                if (object.objcClassPrefix != null)
+                    message.objcClassPrefix = String(object.objcClassPrefix);
+                if (object.csharpNamespace != null)
+                    message.csharpNamespace = String(object.csharpNamespace);
+                if (object.uninterpretedOption) {
+                    if (!Array.isArray(object.uninterpretedOption))
+                        throw TypeError(".google.protobuf.FileOptions.uninterpretedOption: array expected");
+                    message.uninterpretedOption = [];
+                    for (var i = 0; i < object.uninterpretedOption.length; ++i) {
+                        if (typeof object.uninterpretedOption[i] !== "object")
+                            throw TypeError(".google.protobuf.FileOptions.uninterpretedOption: object expected");
+                        message.uninterpretedOption[i] = $root.google.protobuf.UninterpretedOption.fromObject(object.uninterpretedOption[i]);
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a FileOptions message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.FileOptions
+             * @static
+             * @param {google.protobuf.FileOptions} message FileOptions
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            FileOptions.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.uninterpretedOption = [];
+                if (options.defaults) {
+                    object.javaPackage = "";
+                    object.javaOuterClassname = "";
+                    object.optimizeFor = options.enums === String ? "SPEED" : 1;
+                    object.javaMultipleFiles = false;
+                    object.goPackage = "";
+                    object.ccGenericServices = false;
+                    object.javaGenericServices = false;
+                    object.pyGenericServices = false;
+                    object.javaGenerateEqualsAndHash = false;
+                    object.deprecated = false;
+                    object.javaStringCheckUtf8 = false;
+                    object.ccEnableArenas = false;
+                    object.objcClassPrefix = "";
+                    object.csharpNamespace = "";
+                }
+                if (message.javaPackage != null && message.hasOwnProperty("javaPackage"))
+                    object.javaPackage = message.javaPackage;
+                if (message.javaOuterClassname != null && message.hasOwnProperty("javaOuterClassname"))
+                    object.javaOuterClassname = message.javaOuterClassname;
+                if (message.optimizeFor != null && message.hasOwnProperty("optimizeFor"))
+                    object.optimizeFor = options.enums === String ? $root.google.protobuf.FileOptions.OptimizeMode[message.optimizeFor] : message.optimizeFor;
+                if (message.javaMultipleFiles != null && message.hasOwnProperty("javaMultipleFiles"))
+                    object.javaMultipleFiles = message.javaMultipleFiles;
+                if (message.goPackage != null && message.hasOwnProperty("goPackage"))
+                    object.goPackage = message.goPackage;
+                if (message.ccGenericServices != null && message.hasOwnProperty("ccGenericServices"))
+                    object.ccGenericServices = message.ccGenericServices;
+                if (message.javaGenericServices != null && message.hasOwnProperty("javaGenericServices"))
+                    object.javaGenericServices = message.javaGenericServices;
+                if (message.pyGenericServices != null && message.hasOwnProperty("pyGenericServices"))
+                    object.pyGenericServices = message.pyGenericServices;
+                if (message.javaGenerateEqualsAndHash != null && message.hasOwnProperty("javaGenerateEqualsAndHash"))
+                    object.javaGenerateEqualsAndHash = message.javaGenerateEqualsAndHash;
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    object.deprecated = message.deprecated;
+                if (message.javaStringCheckUtf8 != null && message.hasOwnProperty("javaStringCheckUtf8"))
+                    object.javaStringCheckUtf8 = message.javaStringCheckUtf8;
+                if (message.ccEnableArenas != null && message.hasOwnProperty("ccEnableArenas"))
+                    object.ccEnableArenas = message.ccEnableArenas;
+                if (message.objcClassPrefix != null && message.hasOwnProperty("objcClassPrefix"))
+                    object.objcClassPrefix = message.objcClassPrefix;
+                if (message.csharpNamespace != null && message.hasOwnProperty("csharpNamespace"))
+                    object.csharpNamespace = message.csharpNamespace;
+                if (message.uninterpretedOption && message.uninterpretedOption.length) {
+                    object.uninterpretedOption = [];
+                    for (var j = 0; j < message.uninterpretedOption.length; ++j)
+                        object.uninterpretedOption[j] = $root.google.protobuf.UninterpretedOption.toObject(message.uninterpretedOption[j], options);
+                }
+                return object;
+            };
+
+            /**
+             * Converts this FileOptions to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.FileOptions
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            FileOptions.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for FileOptions
+             * @function getTypeUrl
+             * @memberof google.protobuf.FileOptions
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            FileOptions.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.FileOptions";
+            };
+
+            /**
+             * OptimizeMode enum.
+             * @name google.protobuf.FileOptions.OptimizeMode
+             * @enum {number}
+             * @property {number} SPEED=1 SPEED value
+             * @property {number} CODE_SIZE=2 CODE_SIZE value
+             * @property {number} LITE_RUNTIME=3 LITE_RUNTIME value
+             */
+            FileOptions.OptimizeMode = (function() {
+                var valuesById = {}, values = Object.create(valuesById);
+                values[valuesById[1] = "SPEED"] = 1;
+                values[valuesById[2] = "CODE_SIZE"] = 2;
+                values[valuesById[3] = "LITE_RUNTIME"] = 3;
+                return values;
+            })();
+
+            return FileOptions;
+        })();
+
+        protobuf.MessageOptions = (function() {
+
+            /**
+             * Properties of a MessageOptions.
+             * @memberof google.protobuf
+             * @interface IMessageOptions
+             * @property {boolean|null} [messageSetWireFormat] MessageOptions messageSetWireFormat
+             * @property {boolean|null} [noStandardDescriptorAccessor] MessageOptions noStandardDescriptorAccessor
+             * @property {boolean|null} [deprecated] MessageOptions deprecated
+             * @property {boolean|null} [mapEntry] MessageOptions mapEntry
+             * @property {Array.<google.protobuf.IUninterpretedOption>|null} [uninterpretedOption] MessageOptions uninterpretedOption
+             */
+
+            /**
+             * Constructs a new MessageOptions.
+             * @memberof google.protobuf
+             * @classdesc Represents a MessageOptions.
+             * @implements IMessageOptions
+             * @constructor
+             * @param {google.protobuf.IMessageOptions=} [properties] Properties to set
+             */
+            function MessageOptions(properties) {
+                this.uninterpretedOption = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * MessageOptions messageSetWireFormat.
+             * @member {boolean} messageSetWireFormat
+             * @memberof google.protobuf.MessageOptions
+             * @instance
+             */
+            MessageOptions.prototype.messageSetWireFormat = false;
+
+            /**
+             * MessageOptions noStandardDescriptorAccessor.
+             * @member {boolean} noStandardDescriptorAccessor
+             * @memberof google.protobuf.MessageOptions
+             * @instance
+             */
+            MessageOptions.prototype.noStandardDescriptorAccessor = false;
+
+            /**
+             * MessageOptions deprecated.
+             * @member {boolean} deprecated
+             * @memberof google.protobuf.MessageOptions
+             * @instance
+             */
+            MessageOptions.prototype.deprecated = false;
+
+            /**
+             * MessageOptions mapEntry.
+             * @member {boolean} mapEntry
+             * @memberof google.protobuf.MessageOptions
+             * @instance
+             */
+            MessageOptions.prototype.mapEntry = false;
+
+            /**
+             * MessageOptions uninterpretedOption.
+             * @member {Array.<google.protobuf.IUninterpretedOption>} uninterpretedOption
+             * @memberof google.protobuf.MessageOptions
+             * @instance
+             */
+            MessageOptions.prototype.uninterpretedOption = $util.emptyArray;
+
+            /**
+             * Creates a new MessageOptions instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.MessageOptions
+             * @static
+             * @param {google.protobuf.IMessageOptions=} [properties] Properties to set
+             * @returns {google.protobuf.MessageOptions} MessageOptions instance
+             */
+            MessageOptions.create = function create(properties) {
+                return new MessageOptions(properties);
+            };
+
+            /**
+             * Encodes the specified MessageOptions message. Does not implicitly {@link google.protobuf.MessageOptions.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.MessageOptions
+             * @static
+             * @param {google.protobuf.IMessageOptions} message MessageOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            MessageOptions.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.messageSetWireFormat != null && Object.hasOwnProperty.call(message, "messageSetWireFormat"))
+                    writer.uint32(/* id 1, wireType 0 =*/8).bool(message.messageSetWireFormat);
+                if (message.noStandardDescriptorAccessor != null && Object.hasOwnProperty.call(message, "noStandardDescriptorAccessor"))
+                    writer.uint32(/* id 2, wireType 0 =*/16).bool(message.noStandardDescriptorAccessor);
+                if (message.deprecated != null && Object.hasOwnProperty.call(message, "deprecated"))
+                    writer.uint32(/* id 3, wireType 0 =*/24).bool(message.deprecated);
+                if (message.mapEntry != null && Object.hasOwnProperty.call(message, "mapEntry"))
+                    writer.uint32(/* id 7, wireType 0 =*/56).bool(message.mapEntry);
+                if (message.uninterpretedOption != null && message.uninterpretedOption.length)
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i)
+                        $root.google.protobuf.UninterpretedOption.encode(message.uninterpretedOption[i], writer.uint32(/* id 999, wireType 2 =*/7994).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified MessageOptions message, length delimited. Does not implicitly {@link google.protobuf.MessageOptions.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.MessageOptions
+             * @static
+             * @param {google.protobuf.IMessageOptions} message MessageOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            MessageOptions.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a MessageOptions message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.MessageOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.MessageOptions} MessageOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            MessageOptions.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.MessageOptions();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.messageSetWireFormat = reader.bool();
+                        break;
+                    case 2:
+                        message.noStandardDescriptorAccessor = reader.bool();
+                        break;
+                    case 3:
+                        message.deprecated = reader.bool();
+                        break;
+                    case 7:
+                        message.mapEntry = reader.bool();
+                        break;
+                    case 999:
+                        if (!(message.uninterpretedOption && message.uninterpretedOption.length))
+                            message.uninterpretedOption = [];
+                        message.uninterpretedOption.push($root.google.protobuf.UninterpretedOption.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a MessageOptions message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.MessageOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.MessageOptions} MessageOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            MessageOptions.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a MessageOptions message.
+             * @function verify
+             * @memberof google.protobuf.MessageOptions
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            MessageOptions.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.messageSetWireFormat != null && message.hasOwnProperty("messageSetWireFormat"))
+                    if (typeof message.messageSetWireFormat !== "boolean")
+                        return "messageSetWireFormat: boolean expected";
+                if (message.noStandardDescriptorAccessor != null && message.hasOwnProperty("noStandardDescriptorAccessor"))
+                    if (typeof message.noStandardDescriptorAccessor !== "boolean")
+                        return "noStandardDescriptorAccessor: boolean expected";
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    if (typeof message.deprecated !== "boolean")
+                        return "deprecated: boolean expected";
+                if (message.mapEntry != null && message.hasOwnProperty("mapEntry"))
+                    if (typeof message.mapEntry !== "boolean")
+                        return "mapEntry: boolean expected";
+                if (message.uninterpretedOption != null && message.hasOwnProperty("uninterpretedOption")) {
+                    if (!Array.isArray(message.uninterpretedOption))
+                        return "uninterpretedOption: array expected";
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i) {
+                        var error = $root.google.protobuf.UninterpretedOption.verify(message.uninterpretedOption[i]);
+                        if (error)
+                            return "uninterpretedOption." + error;
+                    }
+                }
+                return null;
+            };
+
+            /**
+             * Creates a MessageOptions message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.MessageOptions
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.MessageOptions} MessageOptions
+             */
+            MessageOptions.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.MessageOptions)
+                    return object;
+                var message = new $root.google.protobuf.MessageOptions();
+                if (object.messageSetWireFormat != null)
+                    message.messageSetWireFormat = Boolean(object.messageSetWireFormat);
+                if (object.noStandardDescriptorAccessor != null)
+                    message.noStandardDescriptorAccessor = Boolean(object.noStandardDescriptorAccessor);
+                if (object.deprecated != null)
+                    message.deprecated = Boolean(object.deprecated);
+                if (object.mapEntry != null)
+                    message.mapEntry = Boolean(object.mapEntry);
+                if (object.uninterpretedOption) {
+                    if (!Array.isArray(object.uninterpretedOption))
+                        throw TypeError(".google.protobuf.MessageOptions.uninterpretedOption: array expected");
+                    message.uninterpretedOption = [];
+                    for (var i = 0; i < object.uninterpretedOption.length; ++i) {
+                        if (typeof object.uninterpretedOption[i] !== "object")
+                            throw TypeError(".google.protobuf.MessageOptions.uninterpretedOption: object expected");
+                        message.uninterpretedOption[i] = $root.google.protobuf.UninterpretedOption.fromObject(object.uninterpretedOption[i]);
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a MessageOptions message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.MessageOptions
+             * @static
+             * @param {google.protobuf.MessageOptions} message MessageOptions
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            MessageOptions.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.uninterpretedOption = [];
+                if (options.defaults) {
+                    object.messageSetWireFormat = false;
+                    object.noStandardDescriptorAccessor = false;
+                    object.deprecated = false;
+                    object.mapEntry = false;
+                }
+                if (message.messageSetWireFormat != null && message.hasOwnProperty("messageSetWireFormat"))
+                    object.messageSetWireFormat = message.messageSetWireFormat;
+                if (message.noStandardDescriptorAccessor != null && message.hasOwnProperty("noStandardDescriptorAccessor"))
+                    object.noStandardDescriptorAccessor = message.noStandardDescriptorAccessor;
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    object.deprecated = message.deprecated;
+                if (message.mapEntry != null && message.hasOwnProperty("mapEntry"))
+                    object.mapEntry = message.mapEntry;
+                if (message.uninterpretedOption && message.uninterpretedOption.length) {
+                    object.uninterpretedOption = [];
+                    for (var j = 0; j < message.uninterpretedOption.length; ++j)
+                        object.uninterpretedOption[j] = $root.google.protobuf.UninterpretedOption.toObject(message.uninterpretedOption[j], options);
+                }
+                return object;
+            };
+
+            /**
+             * Converts this MessageOptions to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.MessageOptions
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            MessageOptions.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for MessageOptions
+             * @function getTypeUrl
+             * @memberof google.protobuf.MessageOptions
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            MessageOptions.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.MessageOptions";
+            };
+
+            return MessageOptions;
+        })();
+
+        protobuf.FieldOptions = (function() {
+
+            /**
+             * Properties of a FieldOptions.
+             * @memberof google.protobuf
+             * @interface IFieldOptions
+             * @property {google.protobuf.FieldOptions.CType|null} [ctype] FieldOptions ctype
+             * @property {boolean|null} [packed] FieldOptions packed
+             * @property {google.protobuf.FieldOptions.JSType|null} [jstype] FieldOptions jstype
+             * @property {boolean|null} [lazy] FieldOptions lazy
+             * @property {boolean|null} [deprecated] FieldOptions deprecated
+             * @property {boolean|null} [weak] FieldOptions weak
+             * @property {Array.<google.protobuf.IUninterpretedOption>|null} [uninterpretedOption] FieldOptions uninterpretedOption
+             */
+
+            /**
+             * Constructs a new FieldOptions.
+             * @memberof google.protobuf
+             * @classdesc Represents a FieldOptions.
+             * @implements IFieldOptions
+             * @constructor
+             * @param {google.protobuf.IFieldOptions=} [properties] Properties to set
+             */
+            function FieldOptions(properties) {
+                this.uninterpretedOption = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * FieldOptions ctype.
+             * @member {google.protobuf.FieldOptions.CType} ctype
+             * @memberof google.protobuf.FieldOptions
+             * @instance
+             */
+            FieldOptions.prototype.ctype = 0;
+
+            /**
+             * FieldOptions packed.
+             * @member {boolean} packed
+             * @memberof google.protobuf.FieldOptions
+             * @instance
+             */
+            FieldOptions.prototype.packed = false;
+
+            /**
+             * FieldOptions jstype.
+             * @member {google.protobuf.FieldOptions.JSType} jstype
+             * @memberof google.protobuf.FieldOptions
+             * @instance
+             */
+            FieldOptions.prototype.jstype = 0;
+
+            /**
+             * FieldOptions lazy.
+             * @member {boolean} lazy
+             * @memberof google.protobuf.FieldOptions
+             * @instance
+             */
+            FieldOptions.prototype.lazy = false;
+
+            /**
+             * FieldOptions deprecated.
+             * @member {boolean} deprecated
+             * @memberof google.protobuf.FieldOptions
+             * @instance
+             */
+            FieldOptions.prototype.deprecated = false;
+
+            /**
+             * FieldOptions weak.
+             * @member {boolean} weak
+             * @memberof google.protobuf.FieldOptions
+             * @instance
+             */
+            FieldOptions.prototype.weak = false;
+
+            /**
+             * FieldOptions uninterpretedOption.
+             * @member {Array.<google.protobuf.IUninterpretedOption>} uninterpretedOption
+             * @memberof google.protobuf.FieldOptions
+             * @instance
+             */
+            FieldOptions.prototype.uninterpretedOption = $util.emptyArray;
+
+            /**
+             * Creates a new FieldOptions instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.FieldOptions
+             * @static
+             * @param {google.protobuf.IFieldOptions=} [properties] Properties to set
+             * @returns {google.protobuf.FieldOptions} FieldOptions instance
+             */
+            FieldOptions.create = function create(properties) {
+                return new FieldOptions(properties);
+            };
+
+            /**
+             * Encodes the specified FieldOptions message. Does not implicitly {@link google.protobuf.FieldOptions.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.FieldOptions
+             * @static
+             * @param {google.protobuf.IFieldOptions} message FieldOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            FieldOptions.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.ctype != null && Object.hasOwnProperty.call(message, "ctype"))
+                    writer.uint32(/* id 1, wireType 0 =*/8).int32(message.ctype);
+                if (message.packed != null && Object.hasOwnProperty.call(message, "packed"))
+                    writer.uint32(/* id 2, wireType 0 =*/16).bool(message.packed);
+                if (message.deprecated != null && Object.hasOwnProperty.call(message, "deprecated"))
+                    writer.uint32(/* id 3, wireType 0 =*/24).bool(message.deprecated);
+                if (message.lazy != null && Object.hasOwnProperty.call(message, "lazy"))
+                    writer.uint32(/* id 5, wireType 0 =*/40).bool(message.lazy);
+                if (message.jstype != null && Object.hasOwnProperty.call(message, "jstype"))
+                    writer.uint32(/* id 6, wireType 0 =*/48).int32(message.jstype);
+                if (message.weak != null && Object.hasOwnProperty.call(message, "weak"))
+                    writer.uint32(/* id 10, wireType 0 =*/80).bool(message.weak);
+                if (message.uninterpretedOption != null && message.uninterpretedOption.length)
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i)
+                        $root.google.protobuf.UninterpretedOption.encode(message.uninterpretedOption[i], writer.uint32(/* id 999, wireType 2 =*/7994).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified FieldOptions message, length delimited. Does not implicitly {@link google.protobuf.FieldOptions.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.FieldOptions
+             * @static
+             * @param {google.protobuf.IFieldOptions} message FieldOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            FieldOptions.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a FieldOptions message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.FieldOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.FieldOptions} FieldOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            FieldOptions.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.FieldOptions();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.ctype = reader.int32();
+                        break;
+                    case 2:
+                        message.packed = reader.bool();
+                        break;
+                    case 6:
+                        message.jstype = reader.int32();
+                        break;
+                    case 5:
+                        message.lazy = reader.bool();
+                        break;
+                    case 3:
+                        message.deprecated = reader.bool();
+                        break;
+                    case 10:
+                        message.weak = reader.bool();
+                        break;
+                    case 999:
+                        if (!(message.uninterpretedOption && message.uninterpretedOption.length))
+                            message.uninterpretedOption = [];
+                        message.uninterpretedOption.push($root.google.protobuf.UninterpretedOption.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a FieldOptions message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.FieldOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.FieldOptions} FieldOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            FieldOptions.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a FieldOptions message.
+             * @function verify
+             * @memberof google.protobuf.FieldOptions
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            FieldOptions.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.ctype != null && message.hasOwnProperty("ctype"))
+                    switch (message.ctype) {
+                    default:
+                        return "ctype: enum value expected";
+                    case 0:
+                    case 1:
+                    case 2:
+                        break;
+                    }
+                if (message.packed != null && message.hasOwnProperty("packed"))
+                    if (typeof message.packed !== "boolean")
+                        return "packed: boolean expected";
+                if (message.jstype != null && message.hasOwnProperty("jstype"))
+                    switch (message.jstype) {
+                    default:
+                        return "jstype: enum value expected";
+                    case 0:
+                    case 1:
+                    case 2:
+                        break;
+                    }
+                if (message.lazy != null && message.hasOwnProperty("lazy"))
+                    if (typeof message.lazy !== "boolean")
+                        return "lazy: boolean expected";
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    if (typeof message.deprecated !== "boolean")
+                        return "deprecated: boolean expected";
+                if (message.weak != null && message.hasOwnProperty("weak"))
+                    if (typeof message.weak !== "boolean")
+                        return "weak: boolean expected";
+                if (message.uninterpretedOption != null && message.hasOwnProperty("uninterpretedOption")) {
+                    if (!Array.isArray(message.uninterpretedOption))
+                        return "uninterpretedOption: array expected";
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i) {
+                        var error = $root.google.protobuf.UninterpretedOption.verify(message.uninterpretedOption[i]);
+                        if (error)
+                            return "uninterpretedOption." + error;
+                    }
+                }
+                return null;
+            };
+
+            /**
+             * Creates a FieldOptions message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.FieldOptions
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.FieldOptions} FieldOptions
+             */
+            FieldOptions.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.FieldOptions)
+                    return object;
+                var message = new $root.google.protobuf.FieldOptions();
+                switch (object.ctype) {
+                case "STRING":
+                case 0:
+                    message.ctype = 0;
+                    break;
+                case "CORD":
+                case 1:
+                    message.ctype = 1;
+                    break;
+                case "STRING_PIECE":
+                case 2:
+                    message.ctype = 2;
+                    break;
+                }
+                if (object.packed != null)
+                    message.packed = Boolean(object.packed);
+                switch (object.jstype) {
+                case "JS_NORMAL":
+                case 0:
+                    message.jstype = 0;
+                    break;
+                case "JS_STRING":
+                case 1:
+                    message.jstype = 1;
+                    break;
+                case "JS_NUMBER":
+                case 2:
+                    message.jstype = 2;
+                    break;
+                }
+                if (object.lazy != null)
+                    message.lazy = Boolean(object.lazy);
+                if (object.deprecated != null)
+                    message.deprecated = Boolean(object.deprecated);
+                if (object.weak != null)
+                    message.weak = Boolean(object.weak);
+                if (object.uninterpretedOption) {
+                    if (!Array.isArray(object.uninterpretedOption))
+                        throw TypeError(".google.protobuf.FieldOptions.uninterpretedOption: array expected");
+                    message.uninterpretedOption = [];
+                    for (var i = 0; i < object.uninterpretedOption.length; ++i) {
+                        if (typeof object.uninterpretedOption[i] !== "object")
+                            throw TypeError(".google.protobuf.FieldOptions.uninterpretedOption: object expected");
+                        message.uninterpretedOption[i] = $root.google.protobuf.UninterpretedOption.fromObject(object.uninterpretedOption[i]);
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a FieldOptions message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.FieldOptions
+             * @static
+             * @param {google.protobuf.FieldOptions} message FieldOptions
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            FieldOptions.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.uninterpretedOption = [];
+                if (options.defaults) {
+                    object.ctype = options.enums === String ? "STRING" : 0;
+                    object.packed = false;
+                    object.deprecated = false;
+                    object.lazy = false;
+                    object.jstype = options.enums === String ? "JS_NORMAL" : 0;
+                    object.weak = false;
+                }
+                if (message.ctype != null && message.hasOwnProperty("ctype"))
+                    object.ctype = options.enums === String ? $root.google.protobuf.FieldOptions.CType[message.ctype] : message.ctype;
+                if (message.packed != null && message.hasOwnProperty("packed"))
+                    object.packed = message.packed;
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    object.deprecated = message.deprecated;
+                if (message.lazy != null && message.hasOwnProperty("lazy"))
+                    object.lazy = message.lazy;
+                if (message.jstype != null && message.hasOwnProperty("jstype"))
+                    object.jstype = options.enums === String ? $root.google.protobuf.FieldOptions.JSType[message.jstype] : message.jstype;
+                if (message.weak != null && message.hasOwnProperty("weak"))
+                    object.weak = message.weak;
+                if (message.uninterpretedOption && message.uninterpretedOption.length) {
+                    object.uninterpretedOption = [];
+                    for (var j = 0; j < message.uninterpretedOption.length; ++j)
+                        object.uninterpretedOption[j] = $root.google.protobuf.UninterpretedOption.toObject(message.uninterpretedOption[j], options);
+                }
+                return object;
+            };
+
+            /**
+             * Converts this FieldOptions to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.FieldOptions
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            FieldOptions.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for FieldOptions
+             * @function getTypeUrl
+             * @memberof google.protobuf.FieldOptions
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            FieldOptions.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.FieldOptions";
+            };
+
+            /**
+             * CType enum.
+             * @name google.protobuf.FieldOptions.CType
+             * @enum {number}
+             * @property {number} STRING=0 STRING value
+             * @property {number} CORD=1 CORD value
+             * @property {number} STRING_PIECE=2 STRING_PIECE value
+             */
+            FieldOptions.CType = (function() {
+                var valuesById = {}, values = Object.create(valuesById);
+                values[valuesById[0] = "STRING"] = 0;
+                values[valuesById[1] = "CORD"] = 1;
+                values[valuesById[2] = "STRING_PIECE"] = 2;
+                return values;
+            })();
+
+            /**
+             * JSType enum.
+             * @name google.protobuf.FieldOptions.JSType
+             * @enum {number}
+             * @property {number} JS_NORMAL=0 JS_NORMAL value
+             * @property {number} JS_STRING=1 JS_STRING value
+             * @property {number} JS_NUMBER=2 JS_NUMBER value
+             */
+            FieldOptions.JSType = (function() {
+                var valuesById = {}, values = Object.create(valuesById);
+                values[valuesById[0] = "JS_NORMAL"] = 0;
+                values[valuesById[1] = "JS_STRING"] = 1;
+                values[valuesById[2] = "JS_NUMBER"] = 2;
+                return values;
+            })();
+
+            return FieldOptions;
+        })();
+
+        protobuf.OneofOptions = (function() {
+
+            /**
+             * Properties of an OneofOptions.
+             * @memberof google.protobuf
+             * @interface IOneofOptions
+             * @property {Array.<google.protobuf.IUninterpretedOption>|null} [uninterpretedOption] OneofOptions uninterpretedOption
+             */
+
+            /**
+             * Constructs a new OneofOptions.
+             * @memberof google.protobuf
+             * @classdesc Represents an OneofOptions.
+             * @implements IOneofOptions
+             * @constructor
+             * @param {google.protobuf.IOneofOptions=} [properties] Properties to set
+             */
+            function OneofOptions(properties) {
+                this.uninterpretedOption = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * OneofOptions uninterpretedOption.
+             * @member {Array.<google.protobuf.IUninterpretedOption>} uninterpretedOption
+             * @memberof google.protobuf.OneofOptions
+             * @instance
+             */
+            OneofOptions.prototype.uninterpretedOption = $util.emptyArray;
+
+            /**
+             * Creates a new OneofOptions instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.OneofOptions
+             * @static
+             * @param {google.protobuf.IOneofOptions=} [properties] Properties to set
+             * @returns {google.protobuf.OneofOptions} OneofOptions instance
+             */
+            OneofOptions.create = function create(properties) {
+                return new OneofOptions(properties);
+            };
+
+            /**
+             * Encodes the specified OneofOptions message. Does not implicitly {@link google.protobuf.OneofOptions.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.OneofOptions
+             * @static
+             * @param {google.protobuf.IOneofOptions} message OneofOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            OneofOptions.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.uninterpretedOption != null && message.uninterpretedOption.length)
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i)
+                        $root.google.protobuf.UninterpretedOption.encode(message.uninterpretedOption[i], writer.uint32(/* id 999, wireType 2 =*/7994).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified OneofOptions message, length delimited. Does not implicitly {@link google.protobuf.OneofOptions.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.OneofOptions
+             * @static
+             * @param {google.protobuf.IOneofOptions} message OneofOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            OneofOptions.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes an OneofOptions message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.OneofOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.OneofOptions} OneofOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            OneofOptions.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.OneofOptions();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 999:
+                        if (!(message.uninterpretedOption && message.uninterpretedOption.length))
+                            message.uninterpretedOption = [];
+                        message.uninterpretedOption.push($root.google.protobuf.UninterpretedOption.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes an OneofOptions message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.OneofOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.OneofOptions} OneofOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            OneofOptions.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies an OneofOptions message.
+             * @function verify
+             * @memberof google.protobuf.OneofOptions
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            OneofOptions.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.uninterpretedOption != null && message.hasOwnProperty("uninterpretedOption")) {
+                    if (!Array.isArray(message.uninterpretedOption))
+                        return "uninterpretedOption: array expected";
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i) {
+                        var error = $root.google.protobuf.UninterpretedOption.verify(message.uninterpretedOption[i]);
+                        if (error)
+                            return "uninterpretedOption." + error;
+                    }
+                }
+                return null;
+            };
+
+            /**
+             * Creates an OneofOptions message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.OneofOptions
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.OneofOptions} OneofOptions
+             */
+            OneofOptions.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.OneofOptions)
+                    return object;
+                var message = new $root.google.protobuf.OneofOptions();
+                if (object.uninterpretedOption) {
+                    if (!Array.isArray(object.uninterpretedOption))
+                        throw TypeError(".google.protobuf.OneofOptions.uninterpretedOption: array expected");
+                    message.uninterpretedOption = [];
+                    for (var i = 0; i < object.uninterpretedOption.length; ++i) {
+                        if (typeof object.uninterpretedOption[i] !== "object")
+                            throw TypeError(".google.protobuf.OneofOptions.uninterpretedOption: object expected");
+                        message.uninterpretedOption[i] = $root.google.protobuf.UninterpretedOption.fromObject(object.uninterpretedOption[i]);
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from an OneofOptions message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.OneofOptions
+             * @static
+             * @param {google.protobuf.OneofOptions} message OneofOptions
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            OneofOptions.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.uninterpretedOption = [];
+                if (message.uninterpretedOption && message.uninterpretedOption.length) {
+                    object.uninterpretedOption = [];
+                    for (var j = 0; j < message.uninterpretedOption.length; ++j)
+                        object.uninterpretedOption[j] = $root.google.protobuf.UninterpretedOption.toObject(message.uninterpretedOption[j], options);
+                }
+                return object;
+            };
+
+            /**
+             * Converts this OneofOptions to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.OneofOptions
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            OneofOptions.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for OneofOptions
+             * @function getTypeUrl
+             * @memberof google.protobuf.OneofOptions
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            OneofOptions.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.OneofOptions";
+            };
+
+            return OneofOptions;
+        })();
+
+        protobuf.EnumOptions = (function() {
+
+            /**
+             * Properties of an EnumOptions.
+             * @memberof google.protobuf
+             * @interface IEnumOptions
+             * @property {boolean|null} [allowAlias] EnumOptions allowAlias
+             * @property {boolean|null} [deprecated] EnumOptions deprecated
+             * @property {Array.<google.protobuf.IUninterpretedOption>|null} [uninterpretedOption] EnumOptions uninterpretedOption
+             * @property {string|null} [".jspb.test.IsExtension.simpleOption"] EnumOptions .jspb.test.IsExtension.simpleOption
+             */
+
+            /**
+             * Constructs a new EnumOptions.
+             * @memberof google.protobuf
+             * @classdesc Represents an EnumOptions.
+             * @implements IEnumOptions
+             * @constructor
+             * @param {google.protobuf.IEnumOptions=} [properties] Properties to set
+             */
+            function EnumOptions(properties) {
+                this.uninterpretedOption = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * EnumOptions allowAlias.
+             * @member {boolean} allowAlias
+             * @memberof google.protobuf.EnumOptions
+             * @instance
+             */
+            EnumOptions.prototype.allowAlias = false;
+
+            /**
+             * EnumOptions deprecated.
+             * @member {boolean} deprecated
+             * @memberof google.protobuf.EnumOptions
+             * @instance
+             */
+            EnumOptions.prototype.deprecated = false;
+
+            /**
+             * EnumOptions uninterpretedOption.
+             * @member {Array.<google.protobuf.IUninterpretedOption>} uninterpretedOption
+             * @memberof google.protobuf.EnumOptions
+             * @instance
+             */
+            EnumOptions.prototype.uninterpretedOption = $util.emptyArray;
+
+            /**
+             * EnumOptions .jspb.test.IsExtension.simpleOption.
+             * @member {string} .jspb.test.IsExtension.simpleOption
+             * @memberof google.protobuf.EnumOptions
+             * @instance
+             */
+            EnumOptions.prototype[".jspb.test.IsExtension.simpleOption"] = "";
+
+            /**
+             * Creates a new EnumOptions instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.EnumOptions
+             * @static
+             * @param {google.protobuf.IEnumOptions=} [properties] Properties to set
+             * @returns {google.protobuf.EnumOptions} EnumOptions instance
+             */
+            EnumOptions.create = function create(properties) {
+                return new EnumOptions(properties);
+            };
+
+            /**
+             * Encodes the specified EnumOptions message. Does not implicitly {@link google.protobuf.EnumOptions.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.EnumOptions
+             * @static
+             * @param {google.protobuf.IEnumOptions} message EnumOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            EnumOptions.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.allowAlias != null && Object.hasOwnProperty.call(message, "allowAlias"))
+                    writer.uint32(/* id 2, wireType 0 =*/16).bool(message.allowAlias);
+                if (message.deprecated != null && Object.hasOwnProperty.call(message, "deprecated"))
+                    writer.uint32(/* id 3, wireType 0 =*/24).bool(message.deprecated);
+                if (message.uninterpretedOption != null && message.uninterpretedOption.length)
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i)
+                        $root.google.protobuf.UninterpretedOption.encode(message.uninterpretedOption[i], writer.uint32(/* id 999, wireType 2 =*/7994).fork()).ldelim();
+                if (message[".jspb.test.IsExtension.simpleOption"] != null && Object.hasOwnProperty.call(message, ".jspb.test.IsExtension.simpleOption"))
+                    writer.uint32(/* id 42113038, wireType 2 =*/336904306).string(message[".jspb.test.IsExtension.simpleOption"]);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified EnumOptions message, length delimited. Does not implicitly {@link google.protobuf.EnumOptions.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.EnumOptions
+             * @static
+             * @param {google.protobuf.IEnumOptions} message EnumOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            EnumOptions.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes an EnumOptions message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.EnumOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.EnumOptions} EnumOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            EnumOptions.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.EnumOptions();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 2:
+                        message.allowAlias = reader.bool();
+                        break;
+                    case 3:
+                        message.deprecated = reader.bool();
+                        break;
+                    case 999:
+                        if (!(message.uninterpretedOption && message.uninterpretedOption.length))
+                            message.uninterpretedOption = [];
+                        message.uninterpretedOption.push($root.google.protobuf.UninterpretedOption.decode(reader, reader.uint32()));
+                        break;
+                    case 42113038:
+                        message[".jspb.test.IsExtension.simpleOption"] = reader.string();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes an EnumOptions message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.EnumOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.EnumOptions} EnumOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            EnumOptions.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies an EnumOptions message.
+             * @function verify
+             * @memberof google.protobuf.EnumOptions
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            EnumOptions.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.allowAlias != null && message.hasOwnProperty("allowAlias"))
+                    if (typeof message.allowAlias !== "boolean")
+                        return "allowAlias: boolean expected";
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    if (typeof message.deprecated !== "boolean")
+                        return "deprecated: boolean expected";
+                if (message.uninterpretedOption != null && message.hasOwnProperty("uninterpretedOption")) {
+                    if (!Array.isArray(message.uninterpretedOption))
+                        return "uninterpretedOption: array expected";
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i) {
+                        var error = $root.google.protobuf.UninterpretedOption.verify(message.uninterpretedOption[i]);
+                        if (error)
+                            return "uninterpretedOption." + error;
+                    }
+                }
+                if (message[".jspb.test.IsExtension.simpleOption"] != null && message.hasOwnProperty(".jspb.test.IsExtension.simpleOption"))
+                    if (!$util.isString(message[".jspb.test.IsExtension.simpleOption"]))
+                        return ".jspb.test.IsExtension.simpleOption: string expected";
+                return null;
+            };
+
+            /**
+             * Creates an EnumOptions message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.EnumOptions
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.EnumOptions} EnumOptions
+             */
+            EnumOptions.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.EnumOptions)
+                    return object;
+                var message = new $root.google.protobuf.EnumOptions();
+                if (object.allowAlias != null)
+                    message.allowAlias = Boolean(object.allowAlias);
+                if (object.deprecated != null)
+                    message.deprecated = Boolean(object.deprecated);
+                if (object.uninterpretedOption) {
+                    if (!Array.isArray(object.uninterpretedOption))
+                        throw TypeError(".google.protobuf.EnumOptions.uninterpretedOption: array expected");
+                    message.uninterpretedOption = [];
+                    for (var i = 0; i < object.uninterpretedOption.length; ++i) {
+                        if (typeof object.uninterpretedOption[i] !== "object")
+                            throw TypeError(".google.protobuf.EnumOptions.uninterpretedOption: object expected");
+                        message.uninterpretedOption[i] = $root.google.protobuf.UninterpretedOption.fromObject(object.uninterpretedOption[i]);
+                    }
+                }
+                if (object[".jspb.test.IsExtension.simpleOption"] != null)
+                    message[".jspb.test.IsExtension.simpleOption"] = String(object[".jspb.test.IsExtension.simpleOption"]);
+                return message;
+            };
+
+            /**
+             * Creates a plain object from an EnumOptions message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.EnumOptions
+             * @static
+             * @param {google.protobuf.EnumOptions} message EnumOptions
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            EnumOptions.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.uninterpretedOption = [];
+                if (options.defaults) {
+                    object.allowAlias = false;
+                    object.deprecated = false;
+                    object[".jspb.test.IsExtension.simpleOption"] = "";
+                }
+                if (message.allowAlias != null && message.hasOwnProperty("allowAlias"))
+                    object.allowAlias = message.allowAlias;
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    object.deprecated = message.deprecated;
+                if (message.uninterpretedOption && message.uninterpretedOption.length) {
+                    object.uninterpretedOption = [];
+                    for (var j = 0; j < message.uninterpretedOption.length; ++j)
+                        object.uninterpretedOption[j] = $root.google.protobuf.UninterpretedOption.toObject(message.uninterpretedOption[j], options);
+                }
+                if (message[".jspb.test.IsExtension.simpleOption"] != null && message.hasOwnProperty(".jspb.test.IsExtension.simpleOption"))
+                    object[".jspb.test.IsExtension.simpleOption"] = message[".jspb.test.IsExtension.simpleOption"];
+                return object;
+            };
+
+            /**
+             * Converts this EnumOptions to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.EnumOptions
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            EnumOptions.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for EnumOptions
+             * @function getTypeUrl
+             * @memberof google.protobuf.EnumOptions
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            EnumOptions.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.EnumOptions";
+            };
+
+            return EnumOptions;
+        })();
+
+        protobuf.EnumValueOptions = (function() {
+
+            /**
+             * Properties of an EnumValueOptions.
+             * @memberof google.protobuf
+             * @interface IEnumValueOptions
+             * @property {boolean|null} [deprecated] EnumValueOptions deprecated
+             * @property {Array.<google.protobuf.IUninterpretedOption>|null} [uninterpretedOption] EnumValueOptions uninterpretedOption
+             */
+
+            /**
+             * Constructs a new EnumValueOptions.
+             * @memberof google.protobuf
+             * @classdesc Represents an EnumValueOptions.
+             * @implements IEnumValueOptions
+             * @constructor
+             * @param {google.protobuf.IEnumValueOptions=} [properties] Properties to set
+             */
+            function EnumValueOptions(properties) {
+                this.uninterpretedOption = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * EnumValueOptions deprecated.
+             * @member {boolean} deprecated
+             * @memberof google.protobuf.EnumValueOptions
+             * @instance
+             */
+            EnumValueOptions.prototype.deprecated = false;
+
+            /**
+             * EnumValueOptions uninterpretedOption.
+             * @member {Array.<google.protobuf.IUninterpretedOption>} uninterpretedOption
+             * @memberof google.protobuf.EnumValueOptions
+             * @instance
+             */
+            EnumValueOptions.prototype.uninterpretedOption = $util.emptyArray;
+
+            /**
+             * Creates a new EnumValueOptions instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.EnumValueOptions
+             * @static
+             * @param {google.protobuf.IEnumValueOptions=} [properties] Properties to set
+             * @returns {google.protobuf.EnumValueOptions} EnumValueOptions instance
+             */
+            EnumValueOptions.create = function create(properties) {
+                return new EnumValueOptions(properties);
+            };
+
+            /**
+             * Encodes the specified EnumValueOptions message. Does not implicitly {@link google.protobuf.EnumValueOptions.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.EnumValueOptions
+             * @static
+             * @param {google.protobuf.IEnumValueOptions} message EnumValueOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            EnumValueOptions.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.deprecated != null && Object.hasOwnProperty.call(message, "deprecated"))
+                    writer.uint32(/* id 1, wireType 0 =*/8).bool(message.deprecated);
+                if (message.uninterpretedOption != null && message.uninterpretedOption.length)
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i)
+                        $root.google.protobuf.UninterpretedOption.encode(message.uninterpretedOption[i], writer.uint32(/* id 999, wireType 2 =*/7994).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified EnumValueOptions message, length delimited. Does not implicitly {@link google.protobuf.EnumValueOptions.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.EnumValueOptions
+             * @static
+             * @param {google.protobuf.IEnumValueOptions} message EnumValueOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            EnumValueOptions.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes an EnumValueOptions message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.EnumValueOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.EnumValueOptions} EnumValueOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            EnumValueOptions.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.EnumValueOptions();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.deprecated = reader.bool();
+                        break;
+                    case 999:
+                        if (!(message.uninterpretedOption && message.uninterpretedOption.length))
+                            message.uninterpretedOption = [];
+                        message.uninterpretedOption.push($root.google.protobuf.UninterpretedOption.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes an EnumValueOptions message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.EnumValueOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.EnumValueOptions} EnumValueOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            EnumValueOptions.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies an EnumValueOptions message.
+             * @function verify
+             * @memberof google.protobuf.EnumValueOptions
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            EnumValueOptions.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    if (typeof message.deprecated !== "boolean")
+                        return "deprecated: boolean expected";
+                if (message.uninterpretedOption != null && message.hasOwnProperty("uninterpretedOption")) {
+                    if (!Array.isArray(message.uninterpretedOption))
+                        return "uninterpretedOption: array expected";
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i) {
+                        var error = $root.google.protobuf.UninterpretedOption.verify(message.uninterpretedOption[i]);
+                        if (error)
+                            return "uninterpretedOption." + error;
+                    }
+                }
+                return null;
+            };
+
+            /**
+             * Creates an EnumValueOptions message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.EnumValueOptions
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.EnumValueOptions} EnumValueOptions
+             */
+            EnumValueOptions.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.EnumValueOptions)
+                    return object;
+                var message = new $root.google.protobuf.EnumValueOptions();
+                if (object.deprecated != null)
+                    message.deprecated = Boolean(object.deprecated);
+                if (object.uninterpretedOption) {
+                    if (!Array.isArray(object.uninterpretedOption))
+                        throw TypeError(".google.protobuf.EnumValueOptions.uninterpretedOption: array expected");
+                    message.uninterpretedOption = [];
+                    for (var i = 0; i < object.uninterpretedOption.length; ++i) {
+                        if (typeof object.uninterpretedOption[i] !== "object")
+                            throw TypeError(".google.protobuf.EnumValueOptions.uninterpretedOption: object expected");
+                        message.uninterpretedOption[i] = $root.google.protobuf.UninterpretedOption.fromObject(object.uninterpretedOption[i]);
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from an EnumValueOptions message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.EnumValueOptions
+             * @static
+             * @param {google.protobuf.EnumValueOptions} message EnumValueOptions
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            EnumValueOptions.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.uninterpretedOption = [];
+                if (options.defaults)
+                    object.deprecated = false;
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    object.deprecated = message.deprecated;
+                if (message.uninterpretedOption && message.uninterpretedOption.length) {
+                    object.uninterpretedOption = [];
+                    for (var j = 0; j < message.uninterpretedOption.length; ++j)
+                        object.uninterpretedOption[j] = $root.google.protobuf.UninterpretedOption.toObject(message.uninterpretedOption[j], options);
+                }
+                return object;
+            };
+
+            /**
+             * Converts this EnumValueOptions to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.EnumValueOptions
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            EnumValueOptions.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for EnumValueOptions
+             * @function getTypeUrl
+             * @memberof google.protobuf.EnumValueOptions
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            EnumValueOptions.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.EnumValueOptions";
+            };
+
+            return EnumValueOptions;
+        })();
+
+        protobuf.ServiceOptions = (function() {
+
+            /**
+             * Properties of a ServiceOptions.
+             * @memberof google.protobuf
+             * @interface IServiceOptions
+             * @property {boolean|null} [deprecated] ServiceOptions deprecated
+             * @property {Array.<google.protobuf.IUninterpretedOption>|null} [uninterpretedOption] ServiceOptions uninterpretedOption
+             */
+
+            /**
+             * Constructs a new ServiceOptions.
+             * @memberof google.protobuf
+             * @classdesc Represents a ServiceOptions.
+             * @implements IServiceOptions
+             * @constructor
+             * @param {google.protobuf.IServiceOptions=} [properties] Properties to set
+             */
+            function ServiceOptions(properties) {
+                this.uninterpretedOption = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * ServiceOptions deprecated.
+             * @member {boolean} deprecated
+             * @memberof google.protobuf.ServiceOptions
+             * @instance
+             */
+            ServiceOptions.prototype.deprecated = false;
+
+            /**
+             * ServiceOptions uninterpretedOption.
+             * @member {Array.<google.protobuf.IUninterpretedOption>} uninterpretedOption
+             * @memberof google.protobuf.ServiceOptions
+             * @instance
+             */
+            ServiceOptions.prototype.uninterpretedOption = $util.emptyArray;
+
+            /**
+             * Creates a new ServiceOptions instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.ServiceOptions
+             * @static
+             * @param {google.protobuf.IServiceOptions=} [properties] Properties to set
+             * @returns {google.protobuf.ServiceOptions} ServiceOptions instance
+             */
+            ServiceOptions.create = function create(properties) {
+                return new ServiceOptions(properties);
+            };
+
+            /**
+             * Encodes the specified ServiceOptions message. Does not implicitly {@link google.protobuf.ServiceOptions.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.ServiceOptions
+             * @static
+             * @param {google.protobuf.IServiceOptions} message ServiceOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            ServiceOptions.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.deprecated != null && Object.hasOwnProperty.call(message, "deprecated"))
+                    writer.uint32(/* id 33, wireType 0 =*/264).bool(message.deprecated);
+                if (message.uninterpretedOption != null && message.uninterpretedOption.length)
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i)
+                        $root.google.protobuf.UninterpretedOption.encode(message.uninterpretedOption[i], writer.uint32(/* id 999, wireType 2 =*/7994).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified ServiceOptions message, length delimited. Does not implicitly {@link google.protobuf.ServiceOptions.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.ServiceOptions
+             * @static
+             * @param {google.protobuf.IServiceOptions} message ServiceOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            ServiceOptions.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a ServiceOptions message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.ServiceOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.ServiceOptions} ServiceOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            ServiceOptions.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.ServiceOptions();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 33:
+                        message.deprecated = reader.bool();
+                        break;
+                    case 999:
+                        if (!(message.uninterpretedOption && message.uninterpretedOption.length))
+                            message.uninterpretedOption = [];
+                        message.uninterpretedOption.push($root.google.protobuf.UninterpretedOption.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a ServiceOptions message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.ServiceOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.ServiceOptions} ServiceOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            ServiceOptions.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a ServiceOptions message.
+             * @function verify
+             * @memberof google.protobuf.ServiceOptions
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            ServiceOptions.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    if (typeof message.deprecated !== "boolean")
+                        return "deprecated: boolean expected";
+                if (message.uninterpretedOption != null && message.hasOwnProperty("uninterpretedOption")) {
+                    if (!Array.isArray(message.uninterpretedOption))
+                        return "uninterpretedOption: array expected";
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i) {
+                        var error = $root.google.protobuf.UninterpretedOption.verify(message.uninterpretedOption[i]);
+                        if (error)
+                            return "uninterpretedOption." + error;
+                    }
+                }
+                return null;
+            };
+
+            /**
+             * Creates a ServiceOptions message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.ServiceOptions
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.ServiceOptions} ServiceOptions
+             */
+            ServiceOptions.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.ServiceOptions)
+                    return object;
+                var message = new $root.google.protobuf.ServiceOptions();
+                if (object.deprecated != null)
+                    message.deprecated = Boolean(object.deprecated);
+                if (object.uninterpretedOption) {
+                    if (!Array.isArray(object.uninterpretedOption))
+                        throw TypeError(".google.protobuf.ServiceOptions.uninterpretedOption: array expected");
+                    message.uninterpretedOption = [];
+                    for (var i = 0; i < object.uninterpretedOption.length; ++i) {
+                        if (typeof object.uninterpretedOption[i] !== "object")
+                            throw TypeError(".google.protobuf.ServiceOptions.uninterpretedOption: object expected");
+                        message.uninterpretedOption[i] = $root.google.protobuf.UninterpretedOption.fromObject(object.uninterpretedOption[i]);
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a ServiceOptions message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.ServiceOptions
+             * @static
+             * @param {google.protobuf.ServiceOptions} message ServiceOptions
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            ServiceOptions.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.uninterpretedOption = [];
+                if (options.defaults)
+                    object.deprecated = false;
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    object.deprecated = message.deprecated;
+                if (message.uninterpretedOption && message.uninterpretedOption.length) {
+                    object.uninterpretedOption = [];
+                    for (var j = 0; j < message.uninterpretedOption.length; ++j)
+                        object.uninterpretedOption[j] = $root.google.protobuf.UninterpretedOption.toObject(message.uninterpretedOption[j], options);
+                }
+                return object;
+            };
+
+            /**
+             * Converts this ServiceOptions to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.ServiceOptions
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            ServiceOptions.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for ServiceOptions
+             * @function getTypeUrl
+             * @memberof google.protobuf.ServiceOptions
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            ServiceOptions.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.ServiceOptions";
+            };
+
+            return ServiceOptions;
+        })();
+
+        protobuf.MethodOptions = (function() {
+
+            /**
+             * Properties of a MethodOptions.
+             * @memberof google.protobuf
+             * @interface IMethodOptions
+             * @property {boolean|null} [deprecated] MethodOptions deprecated
+             * @property {google.protobuf.MethodOptions.IdempotencyLevel|null} [idempotencyLevel] MethodOptions idempotencyLevel
+             * @property {Array.<google.protobuf.IUninterpretedOption>|null} [uninterpretedOption] MethodOptions uninterpretedOption
+             */
+
+            /**
+             * Constructs a new MethodOptions.
+             * @memberof google.protobuf
+             * @classdesc Represents a MethodOptions.
+             * @implements IMethodOptions
+             * @constructor
+             * @param {google.protobuf.IMethodOptions=} [properties] Properties to set
+             */
+            function MethodOptions(properties) {
+                this.uninterpretedOption = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * MethodOptions deprecated.
+             * @member {boolean} deprecated
+             * @memberof google.protobuf.MethodOptions
+             * @instance
+             */
+            MethodOptions.prototype.deprecated = false;
+
+            /**
+             * MethodOptions idempotencyLevel.
+             * @member {google.protobuf.MethodOptions.IdempotencyLevel} idempotencyLevel
+             * @memberof google.protobuf.MethodOptions
+             * @instance
+             */
+            MethodOptions.prototype.idempotencyLevel = 0;
+
+            /**
+             * MethodOptions uninterpretedOption.
+             * @member {Array.<google.protobuf.IUninterpretedOption>} uninterpretedOption
+             * @memberof google.protobuf.MethodOptions
+             * @instance
+             */
+            MethodOptions.prototype.uninterpretedOption = $util.emptyArray;
+
+            /**
+             * Creates a new MethodOptions instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.MethodOptions
+             * @static
+             * @param {google.protobuf.IMethodOptions=} [properties] Properties to set
+             * @returns {google.protobuf.MethodOptions} MethodOptions instance
+             */
+            MethodOptions.create = function create(properties) {
+                return new MethodOptions(properties);
+            };
+
+            /**
+             * Encodes the specified MethodOptions message. Does not implicitly {@link google.protobuf.MethodOptions.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.MethodOptions
+             * @static
+             * @param {google.protobuf.IMethodOptions} message MethodOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            MethodOptions.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.deprecated != null && Object.hasOwnProperty.call(message, "deprecated"))
+                    writer.uint32(/* id 33, wireType 0 =*/264).bool(message.deprecated);
+                if (message.idempotencyLevel != null && Object.hasOwnProperty.call(message, "idempotencyLevel"))
+                    writer.uint32(/* id 34, wireType 0 =*/272).int32(message.idempotencyLevel);
+                if (message.uninterpretedOption != null && message.uninterpretedOption.length)
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i)
+                        $root.google.protobuf.UninterpretedOption.encode(message.uninterpretedOption[i], writer.uint32(/* id 999, wireType 2 =*/7994).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified MethodOptions message, length delimited. Does not implicitly {@link google.protobuf.MethodOptions.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.MethodOptions
+             * @static
+             * @param {google.protobuf.IMethodOptions} message MethodOptions message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            MethodOptions.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a MethodOptions message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.MethodOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.MethodOptions} MethodOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            MethodOptions.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.MethodOptions();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 33:
+                        message.deprecated = reader.bool();
+                        break;
+                    case 34:
+                        message.idempotencyLevel = reader.int32();
+                        break;
+                    case 999:
+                        if (!(message.uninterpretedOption && message.uninterpretedOption.length))
+                            message.uninterpretedOption = [];
+                        message.uninterpretedOption.push($root.google.protobuf.UninterpretedOption.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a MethodOptions message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.MethodOptions
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.MethodOptions} MethodOptions
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            MethodOptions.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a MethodOptions message.
+             * @function verify
+             * @memberof google.protobuf.MethodOptions
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            MethodOptions.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    if (typeof message.deprecated !== "boolean")
+                        return "deprecated: boolean expected";
+                if (message.idempotencyLevel != null && message.hasOwnProperty("idempotencyLevel"))
+                    switch (message.idempotencyLevel) {
+                    default:
+                        return "idempotencyLevel: enum value expected";
+                    case 0:
+                    case 1:
+                    case 2:
+                        break;
+                    }
+                if (message.uninterpretedOption != null && message.hasOwnProperty("uninterpretedOption")) {
+                    if (!Array.isArray(message.uninterpretedOption))
+                        return "uninterpretedOption: array expected";
+                    for (var i = 0; i < message.uninterpretedOption.length; ++i) {
+                        var error = $root.google.protobuf.UninterpretedOption.verify(message.uninterpretedOption[i]);
+                        if (error)
+                            return "uninterpretedOption." + error;
+                    }
+                }
+                return null;
+            };
+
+            /**
+             * Creates a MethodOptions message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.MethodOptions
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.MethodOptions} MethodOptions
+             */
+            MethodOptions.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.MethodOptions)
+                    return object;
+                var message = new $root.google.protobuf.MethodOptions();
+                if (object.deprecated != null)
+                    message.deprecated = Boolean(object.deprecated);
+                switch (object.idempotencyLevel) {
+                case "IDEMPOTENCY_UNKNOWN":
+                case 0:
+                    message.idempotencyLevel = 0;
+                    break;
+                case "NO_SIDE_EFFECTS":
+                case 1:
+                    message.idempotencyLevel = 1;
+                    break;
+                case "IDEMPOTENT":
+                case 2:
+                    message.idempotencyLevel = 2;
+                    break;
+                }
+                if (object.uninterpretedOption) {
+                    if (!Array.isArray(object.uninterpretedOption))
+                        throw TypeError(".google.protobuf.MethodOptions.uninterpretedOption: array expected");
+                    message.uninterpretedOption = [];
+                    for (var i = 0; i < object.uninterpretedOption.length; ++i) {
+                        if (typeof object.uninterpretedOption[i] !== "object")
+                            throw TypeError(".google.protobuf.MethodOptions.uninterpretedOption: object expected");
+                        message.uninterpretedOption[i] = $root.google.protobuf.UninterpretedOption.fromObject(object.uninterpretedOption[i]);
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a MethodOptions message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.MethodOptions
+             * @static
+             * @param {google.protobuf.MethodOptions} message MethodOptions
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            MethodOptions.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.uninterpretedOption = [];
+                if (options.defaults) {
+                    object.deprecated = false;
+                    object.idempotencyLevel = options.enums === String ? "IDEMPOTENCY_UNKNOWN" : 0;
+                }
+                if (message.deprecated != null && message.hasOwnProperty("deprecated"))
+                    object.deprecated = message.deprecated;
+                if (message.idempotencyLevel != null && message.hasOwnProperty("idempotencyLevel"))
+                    object.idempotencyLevel = options.enums === String ? $root.google.protobuf.MethodOptions.IdempotencyLevel[message.idempotencyLevel] : message.idempotencyLevel;
+                if (message.uninterpretedOption && message.uninterpretedOption.length) {
+                    object.uninterpretedOption = [];
+                    for (var j = 0; j < message.uninterpretedOption.length; ++j)
+                        object.uninterpretedOption[j] = $root.google.protobuf.UninterpretedOption.toObject(message.uninterpretedOption[j], options);
+                }
+                return object;
+            };
+
+            /**
+             * Converts this MethodOptions to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.MethodOptions
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            MethodOptions.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for MethodOptions
+             * @function getTypeUrl
+             * @memberof google.protobuf.MethodOptions
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            MethodOptions.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.MethodOptions";
+            };
+
+            /**
+             * IdempotencyLevel enum.
+             * @name google.protobuf.MethodOptions.IdempotencyLevel
+             * @enum {number}
+             * @property {number} IDEMPOTENCY_UNKNOWN=0 IDEMPOTENCY_UNKNOWN value
+             * @property {number} NO_SIDE_EFFECTS=1 NO_SIDE_EFFECTS value
+             * @property {number} IDEMPOTENT=2 IDEMPOTENT value
+             */
+            MethodOptions.IdempotencyLevel = (function() {
+                var valuesById = {}, values = Object.create(valuesById);
+                values[valuesById[0] = "IDEMPOTENCY_UNKNOWN"] = 0;
+                values[valuesById[1] = "NO_SIDE_EFFECTS"] = 1;
+                values[valuesById[2] = "IDEMPOTENT"] = 2;
+                return values;
+            })();
+
+            return MethodOptions;
+        })();
+
+        protobuf.UninterpretedOption = (function() {
+
+            /**
+             * Properties of an UninterpretedOption.
+             * @memberof google.protobuf
+             * @interface IUninterpretedOption
+             * @property {Array.<google.protobuf.UninterpretedOption.INamePart>|null} [name] UninterpretedOption name
+             * @property {string|null} [identifierValue] UninterpretedOption identifierValue
+             * @property {number|Long|null} [positiveIntValue] UninterpretedOption positiveIntValue
+             * @property {number|Long|null} [negativeIntValue] UninterpretedOption negativeIntValue
+             * @property {number|null} [doubleValue] UninterpretedOption doubleValue
+             * @property {Uint8Array|null} [stringValue] UninterpretedOption stringValue
+             * @property {string|null} [aggregateValue] UninterpretedOption aggregateValue
+             */
+
+            /**
+             * Constructs a new UninterpretedOption.
+             * @memberof google.protobuf
+             * @classdesc Represents an UninterpretedOption.
+             * @implements IUninterpretedOption
+             * @constructor
+             * @param {google.protobuf.IUninterpretedOption=} [properties] Properties to set
+             */
+            function UninterpretedOption(properties) {
+                this.name = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * UninterpretedOption name.
+             * @member {Array.<google.protobuf.UninterpretedOption.INamePart>} name
+             * @memberof google.protobuf.UninterpretedOption
+             * @instance
+             */
+            UninterpretedOption.prototype.name = $util.emptyArray;
+
+            /**
+             * UninterpretedOption identifierValue.
+             * @member {string} identifierValue
+             * @memberof google.protobuf.UninterpretedOption
+             * @instance
+             */
+            UninterpretedOption.prototype.identifierValue = "";
+
+            /**
+             * UninterpretedOption positiveIntValue.
+             * @member {number|Long} positiveIntValue
+             * @memberof google.protobuf.UninterpretedOption
+             * @instance
+             */
+            UninterpretedOption.prototype.positiveIntValue = $util.Long ? $util.Long.fromBits(0,0,true) : 0;
+
+            /**
+             * UninterpretedOption negativeIntValue.
+             * @member {number|Long} negativeIntValue
+             * @memberof google.protobuf.UninterpretedOption
+             * @instance
+             */
+            UninterpretedOption.prototype.negativeIntValue = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
+
+            /**
+             * UninterpretedOption doubleValue.
+             * @member {number} doubleValue
+             * @memberof google.protobuf.UninterpretedOption
+             * @instance
+             */
+            UninterpretedOption.prototype.doubleValue = 0;
+
+            /**
+             * UninterpretedOption stringValue.
+             * @member {Uint8Array} stringValue
+             * @memberof google.protobuf.UninterpretedOption
+             * @instance
+             */
+            UninterpretedOption.prototype.stringValue = $util.newBuffer([]);
+
+            /**
+             * UninterpretedOption aggregateValue.
+             * @member {string} aggregateValue
+             * @memberof google.protobuf.UninterpretedOption
+             * @instance
+             */
+            UninterpretedOption.prototype.aggregateValue = "";
+
+            /**
+             * Creates a new UninterpretedOption instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.UninterpretedOption
+             * @static
+             * @param {google.protobuf.IUninterpretedOption=} [properties] Properties to set
+             * @returns {google.protobuf.UninterpretedOption} UninterpretedOption instance
+             */
+            UninterpretedOption.create = function create(properties) {
+                return new UninterpretedOption(properties);
+            };
+
+            /**
+             * Encodes the specified UninterpretedOption message. Does not implicitly {@link google.protobuf.UninterpretedOption.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.UninterpretedOption
+             * @static
+             * @param {google.protobuf.IUninterpretedOption} message UninterpretedOption message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            UninterpretedOption.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.name != null && message.name.length)
+                    for (var i = 0; i < message.name.length; ++i)
+                        $root.google.protobuf.UninterpretedOption.NamePart.encode(message.name[i], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim();
+                if (message.identifierValue != null && Object.hasOwnProperty.call(message, "identifierValue"))
+                    writer.uint32(/* id 3, wireType 2 =*/26).string(message.identifierValue);
+                if (message.positiveIntValue != null && Object.hasOwnProperty.call(message, "positiveIntValue"))
+                    writer.uint32(/* id 4, wireType 0 =*/32).uint64(message.positiveIntValue);
+                if (message.negativeIntValue != null && Object.hasOwnProperty.call(message, "negativeIntValue"))
+                    writer.uint32(/* id 5, wireType 0 =*/40).int64(message.negativeIntValue);
+                if (message.doubleValue != null && Object.hasOwnProperty.call(message, "doubleValue"))
+                    writer.uint32(/* id 6, wireType 1 =*/49).double(message.doubleValue);
+                if (message.stringValue != null && Object.hasOwnProperty.call(message, "stringValue"))
+                    writer.uint32(/* id 7, wireType 2 =*/58).bytes(message.stringValue);
+                if (message.aggregateValue != null && Object.hasOwnProperty.call(message, "aggregateValue"))
+                    writer.uint32(/* id 8, wireType 2 =*/66).string(message.aggregateValue);
+                return writer;
+            };
+
+            /**
+             * Encodes the specified UninterpretedOption message, length delimited. Does not implicitly {@link google.protobuf.UninterpretedOption.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.UninterpretedOption
+             * @static
+             * @param {google.protobuf.IUninterpretedOption} message UninterpretedOption message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            UninterpretedOption.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes an UninterpretedOption message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.UninterpretedOption
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.UninterpretedOption} UninterpretedOption
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            UninterpretedOption.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.UninterpretedOption();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 2:
+                        if (!(message.name && message.name.length))
+                            message.name = [];
+                        message.name.push($root.google.protobuf.UninterpretedOption.NamePart.decode(reader, reader.uint32()));
+                        break;
+                    case 3:
+                        message.identifierValue = reader.string();
+                        break;
+                    case 4:
+                        message.positiveIntValue = reader.uint64();
+                        break;
+                    case 5:
+                        message.negativeIntValue = reader.int64();
+                        break;
+                    case 6:
+                        message.doubleValue = reader.double();
+                        break;
+                    case 7:
+                        message.stringValue = reader.bytes();
+                        break;
+                    case 8:
+                        message.aggregateValue = reader.string();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes an UninterpretedOption message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.UninterpretedOption
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.UninterpretedOption} UninterpretedOption
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            UninterpretedOption.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies an UninterpretedOption message.
+             * @function verify
+             * @memberof google.protobuf.UninterpretedOption
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            UninterpretedOption.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.name != null && message.hasOwnProperty("name")) {
+                    if (!Array.isArray(message.name))
+                        return "name: array expected";
+                    for (var i = 0; i < message.name.length; ++i) {
+                        var error = $root.google.protobuf.UninterpretedOption.NamePart.verify(message.name[i]);
+                        if (error)
+                            return "name." + error;
+                    }
+                }
+                if (message.identifierValue != null && message.hasOwnProperty("identifierValue"))
+                    if (!$util.isString(message.identifierValue))
+                        return "identifierValue: string expected";
+                if (message.positiveIntValue != null && message.hasOwnProperty("positiveIntValue"))
+                    if (!$util.isInteger(message.positiveIntValue) && !(message.positiveIntValue && $util.isInteger(message.positiveIntValue.low) && $util.isInteger(message.positiveIntValue.high)))
+                        return "positiveIntValue: integer|Long expected";
+                if (message.negativeIntValue != null && message.hasOwnProperty("negativeIntValue"))
+                    if (!$util.isInteger(message.negativeIntValue) && !(message.negativeIntValue && $util.isInteger(message.negativeIntValue.low) && $util.isInteger(message.negativeIntValue.high)))
+                        return "negativeIntValue: integer|Long expected";
+                if (message.doubleValue != null && message.hasOwnProperty("doubleValue"))
+                    if (typeof message.doubleValue !== "number")
+                        return "doubleValue: number expected";
+                if (message.stringValue != null && message.hasOwnProperty("stringValue"))
+                    if (!(message.stringValue && typeof message.stringValue.length === "number" || $util.isString(message.stringValue)))
+                        return "stringValue: buffer expected";
+                if (message.aggregateValue != null && message.hasOwnProperty("aggregateValue"))
+                    if (!$util.isString(message.aggregateValue))
+                        return "aggregateValue: string expected";
+                return null;
+            };
+
+            /**
+             * Creates an UninterpretedOption message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.UninterpretedOption
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.UninterpretedOption} UninterpretedOption
+             */
+            UninterpretedOption.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.UninterpretedOption)
+                    return object;
+                var message = new $root.google.protobuf.UninterpretedOption();
+                if (object.name) {
+                    if (!Array.isArray(object.name))
+                        throw TypeError(".google.protobuf.UninterpretedOption.name: array expected");
+                    message.name = [];
+                    for (var i = 0; i < object.name.length; ++i) {
+                        if (typeof object.name[i] !== "object")
+                            throw TypeError(".google.protobuf.UninterpretedOption.name: object expected");
+                        message.name[i] = $root.google.protobuf.UninterpretedOption.NamePart.fromObject(object.name[i]);
+                    }
+                }
+                if (object.identifierValue != null)
+                    message.identifierValue = String(object.identifierValue);
+                if (object.positiveIntValue != null)
+                    if ($util.Long)
+                        (message.positiveIntValue = $util.Long.fromValue(object.positiveIntValue)).unsigned = true;
+                    else if (typeof object.positiveIntValue === "string")
+                        message.positiveIntValue = parseInt(object.positiveIntValue, 10);
+                    else if (typeof object.positiveIntValue === "number")
+                        message.positiveIntValue = object.positiveIntValue;
+                    else if (typeof object.positiveIntValue === "object")
+                        message.positiveIntValue = new $util.LongBits(object.positiveIntValue.low >>> 0, object.positiveIntValue.high >>> 0).toNumber(true);
+                if (object.negativeIntValue != null)
+                    if ($util.Long)
+                        (message.negativeIntValue = $util.Long.fromValue(object.negativeIntValue)).unsigned = false;
+                    else if (typeof object.negativeIntValue === "string")
+                        message.negativeIntValue = parseInt(object.negativeIntValue, 10);
+                    else if (typeof object.negativeIntValue === "number")
+                        message.negativeIntValue = object.negativeIntValue;
+                    else if (typeof object.negativeIntValue === "object")
+                        message.negativeIntValue = new $util.LongBits(object.negativeIntValue.low >>> 0, object.negativeIntValue.high >>> 0).toNumber();
+                if (object.doubleValue != null)
+                    message.doubleValue = Number(object.doubleValue);
+                if (object.stringValue != null)
+                    if (typeof object.stringValue === "string")
+                        $util.base64.decode(object.stringValue, message.stringValue = $util.newBuffer($util.base64.length(object.stringValue)), 0);
+                    else if (object.stringValue.length >= 0)
+                        message.stringValue = object.stringValue;
+                if (object.aggregateValue != null)
+                    message.aggregateValue = String(object.aggregateValue);
+                return message;
+            };
+
+            /**
+             * Creates a plain object from an UninterpretedOption message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.UninterpretedOption
+             * @static
+             * @param {google.protobuf.UninterpretedOption} message UninterpretedOption
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            UninterpretedOption.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.name = [];
+                if (options.defaults) {
+                    object.identifierValue = "";
+                    if ($util.Long) {
+                        var long = new $util.Long(0, 0, true);
+                        object.positiveIntValue = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
+                    } else
+                        object.positiveIntValue = options.longs === String ? "0" : 0;
+                    if ($util.Long) {
+                        var long = new $util.Long(0, 0, false);
+                        object.negativeIntValue = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
+                    } else
+                        object.negativeIntValue = options.longs === String ? "0" : 0;
+                    object.doubleValue = 0;
+                    if (options.bytes === String)
+                        object.stringValue = "";
+                    else {
+                        object.stringValue = [];
+                        if (options.bytes !== Array)
+                            object.stringValue = $util.newBuffer(object.stringValue);
+                    }
+                    object.aggregateValue = "";
+                }
+                if (message.name && message.name.length) {
+                    object.name = [];
+                    for (var j = 0; j < message.name.length; ++j)
+                        object.name[j] = $root.google.protobuf.UninterpretedOption.NamePart.toObject(message.name[j], options);
+                }
+                if (message.identifierValue != null && message.hasOwnProperty("identifierValue"))
+                    object.identifierValue = message.identifierValue;
+                if (message.positiveIntValue != null && message.hasOwnProperty("positiveIntValue"))
+                    if (typeof message.positiveIntValue === "number")
+                        object.positiveIntValue = options.longs === String ? String(message.positiveIntValue) : message.positiveIntValue;
+                    else
+                        object.positiveIntValue = options.longs === String ? $util.Long.prototype.toString.call(message.positiveIntValue) : options.longs === Number ? new $util.LongBits(message.positiveIntValue.low >>> 0, message.positiveIntValue.high >>> 0).toNumber(true) : message.positiveIntValue;
+                if (message.negativeIntValue != null && message.hasOwnProperty("negativeIntValue"))
+                    if (typeof message.negativeIntValue === "number")
+                        object.negativeIntValue = options.longs === String ? String(message.negativeIntValue) : message.negativeIntValue;
+                    else
+                        object.negativeIntValue = options.longs === String ? $util.Long.prototype.toString.call(message.negativeIntValue) : options.longs === Number ? new $util.LongBits(message.negativeIntValue.low >>> 0, message.negativeIntValue.high >>> 0).toNumber() : message.negativeIntValue;
+                if (message.doubleValue != null && message.hasOwnProperty("doubleValue"))
+                    object.doubleValue = options.json && !isFinite(message.doubleValue) ? String(message.doubleValue) : message.doubleValue;
+                if (message.stringValue != null && message.hasOwnProperty("stringValue"))
+                    object.stringValue = options.bytes === String ? $util.base64.encode(message.stringValue, 0, message.stringValue.length) : options.bytes === Array ? Array.prototype.slice.call(message.stringValue) : message.stringValue;
+                if (message.aggregateValue != null && message.hasOwnProperty("aggregateValue"))
+                    object.aggregateValue = message.aggregateValue;
+                return object;
+            };
+
+            /**
+             * Converts this UninterpretedOption to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.UninterpretedOption
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            UninterpretedOption.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for UninterpretedOption
+             * @function getTypeUrl
+             * @memberof google.protobuf.UninterpretedOption
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            UninterpretedOption.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.UninterpretedOption";
+            };
+
+            UninterpretedOption.NamePart = (function() {
+
+                /**
+                 * Properties of a NamePart.
+                 * @memberof google.protobuf.UninterpretedOption
+                 * @interface INamePart
+                 * @property {string} namePart NamePart namePart
+                 * @property {boolean} isExtension NamePart isExtension
+                 */
+
+                /**
+                 * Constructs a new NamePart.
+                 * @memberof google.protobuf.UninterpretedOption
+                 * @classdesc Represents a NamePart.
+                 * @implements INamePart
+                 * @constructor
+                 * @param {google.protobuf.UninterpretedOption.INamePart=} [properties] Properties to set
+                 */
+                function NamePart(properties) {
+                    if (properties)
+                        for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                            if (properties[keys[i]] != null)
+                                this[keys[i]] = properties[keys[i]];
+                }
+
+                /**
+                 * NamePart namePart.
+                 * @member {string} namePart
+                 * @memberof google.protobuf.UninterpretedOption.NamePart
+                 * @instance
+                 */
+                NamePart.prototype.namePart = "";
+
+                /**
+                 * NamePart isExtension.
+                 * @member {boolean} isExtension
+                 * @memberof google.protobuf.UninterpretedOption.NamePart
+                 * @instance
+                 */
+                NamePart.prototype.isExtension = false;
+
+                /**
+                 * Creates a new NamePart instance using the specified properties.
+                 * @function create
+                 * @memberof google.protobuf.UninterpretedOption.NamePart
+                 * @static
+                 * @param {google.protobuf.UninterpretedOption.INamePart=} [properties] Properties to set
+                 * @returns {google.protobuf.UninterpretedOption.NamePart} NamePart instance
+                 */
+                NamePart.create = function create(properties) {
+                    return new NamePart(properties);
+                };
+
+                /**
+                 * Encodes the specified NamePart message. Does not implicitly {@link google.protobuf.UninterpretedOption.NamePart.verify|verify} messages.
+                 * @function encode
+                 * @memberof google.protobuf.UninterpretedOption.NamePart
+                 * @static
+                 * @param {google.protobuf.UninterpretedOption.INamePart} message NamePart message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                NamePart.encode = function encode(message, writer) {
+                    if (!writer)
+                        writer = $Writer.create();
+                    writer.uint32(/* id 1, wireType 2 =*/10).string(message.namePart);
+                    writer.uint32(/* id 2, wireType 0 =*/16).bool(message.isExtension);
+                    return writer;
+                };
+
+                /**
+                 * Encodes the specified NamePart message, length delimited. Does not implicitly {@link google.protobuf.UninterpretedOption.NamePart.verify|verify} messages.
+                 * @function encodeDelimited
+                 * @memberof google.protobuf.UninterpretedOption.NamePart
+                 * @static
+                 * @param {google.protobuf.UninterpretedOption.INamePart} message NamePart message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                NamePart.encodeDelimited = function encodeDelimited(message, writer) {
+                    return this.encode(message, writer).ldelim();
+                };
+
+                /**
+                 * Decodes a NamePart message from the specified reader or buffer.
+                 * @function decode
+                 * @memberof google.protobuf.UninterpretedOption.NamePart
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @param {number} [length] Message length if known beforehand
+                 * @returns {google.protobuf.UninterpretedOption.NamePart} NamePart
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                NamePart.decode = function decode(reader, length) {
+                    if (!(reader instanceof $Reader))
+                        reader = $Reader.create(reader);
+                    var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.UninterpretedOption.NamePart();
+                    while (reader.pos < end) {
+                        var tag = reader.uint32();
+                        switch (tag >>> 3) {
+                        case 1:
+                            message.namePart = reader.string();
+                            break;
+                        case 2:
+                            message.isExtension = reader.bool();
+                            break;
+                        default:
+                            reader.skipType(tag & 7);
+                            break;
+                        }
+                    }
+                    if (!message.hasOwnProperty("namePart"))
+                        throw $util.ProtocolError("missing required 'namePart'", { instance: message });
+                    if (!message.hasOwnProperty("isExtension"))
+                        throw $util.ProtocolError("missing required 'isExtension'", { instance: message });
+                    return message;
+                };
+
+                /**
+                 * Decodes a NamePart message from the specified reader or buffer, length delimited.
+                 * @function decodeDelimited
+                 * @memberof google.protobuf.UninterpretedOption.NamePart
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @returns {google.protobuf.UninterpretedOption.NamePart} NamePart
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                NamePart.decodeDelimited = function decodeDelimited(reader) {
+                    if (!(reader instanceof $Reader))
+                        reader = new $Reader(reader);
+                    return this.decode(reader, reader.uint32());
+                };
+
+                /**
+                 * Verifies a NamePart message.
+                 * @function verify
+                 * @memberof google.protobuf.UninterpretedOption.NamePart
+                 * @static
+                 * @param {Object.<string,*>} message Plain object to verify
+                 * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                 */
+                NamePart.verify = function verify(message) {
+                    if (typeof message !== "object" || message === null)
+                        return "object expected";
+                    if (!$util.isString(message.namePart))
+                        return "namePart: string expected";
+                    if (typeof message.isExtension !== "boolean")
+                        return "isExtension: boolean expected";
+                    return null;
+                };
+
+                /**
+                 * Creates a NamePart message from a plain object. Also converts values to their respective internal types.
+                 * @function fromObject
+                 * @memberof google.protobuf.UninterpretedOption.NamePart
+                 * @static
+                 * @param {Object.<string,*>} object Plain object
+                 * @returns {google.protobuf.UninterpretedOption.NamePart} NamePart
+                 */
+                NamePart.fromObject = function fromObject(object) {
+                    if (object instanceof $root.google.protobuf.UninterpretedOption.NamePart)
+                        return object;
+                    var message = new $root.google.protobuf.UninterpretedOption.NamePart();
+                    if (object.namePart != null)
+                        message.namePart = String(object.namePart);
+                    if (object.isExtension != null)
+                        message.isExtension = Boolean(object.isExtension);
+                    return message;
+                };
+
+                /**
+                 * Creates a plain object from a NamePart message. Also converts values to other types if specified.
+                 * @function toObject
+                 * @memberof google.protobuf.UninterpretedOption.NamePart
+                 * @static
+                 * @param {google.protobuf.UninterpretedOption.NamePart} message NamePart
+                 * @param {$protobuf.IConversionOptions} [options] Conversion options
+                 * @returns {Object.<string,*>} Plain object
+                 */
+                NamePart.toObject = function toObject(message, options) {
+                    if (!options)
+                        options = {};
+                    var object = {};
+                    if (options.defaults) {
+                        object.namePart = "";
+                        object.isExtension = false;
+                    }
+                    if (message.namePart != null && message.hasOwnProperty("namePart"))
+                        object.namePart = message.namePart;
+                    if (message.isExtension != null && message.hasOwnProperty("isExtension"))
+                        object.isExtension = message.isExtension;
+                    return object;
+                };
+
+                /**
+                 * Converts this NamePart to JSON.
+                 * @function toJSON
+                 * @memberof google.protobuf.UninterpretedOption.NamePart
+                 * @instance
+                 * @returns {Object.<string,*>} JSON object
+                 */
+                NamePart.prototype.toJSON = function toJSON() {
+                    return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                };
+
+                /**
+                 * Gets the default type url for NamePart
+                 * @function getTypeUrl
+                 * @memberof google.protobuf.UninterpretedOption.NamePart
+                 * @static
+                 * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                 * @returns {string} The default type url
+                 */
+                NamePart.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                    if (typeUrlPrefix === undefined) {
+                        typeUrlPrefix = "type.googleapis.com";
+                    }
+                    return typeUrlPrefix + "/google.protobuf.UninterpretedOption.NamePart";
+                };
+
+                return NamePart;
+            })();
+
+            return UninterpretedOption;
+        })();
+
+        protobuf.SourceCodeInfo = (function() {
+
+            /**
+             * Properties of a SourceCodeInfo.
+             * @memberof google.protobuf
+             * @interface ISourceCodeInfo
+             * @property {Array.<google.protobuf.SourceCodeInfo.ILocation>|null} [location] SourceCodeInfo location
+             */
+
+            /**
+             * Constructs a new SourceCodeInfo.
+             * @memberof google.protobuf
+             * @classdesc Represents a SourceCodeInfo.
+             * @implements ISourceCodeInfo
+             * @constructor
+             * @param {google.protobuf.ISourceCodeInfo=} [properties] Properties to set
+             */
+            function SourceCodeInfo(properties) {
+                this.location = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * SourceCodeInfo location.
+             * @member {Array.<google.protobuf.SourceCodeInfo.ILocation>} location
+             * @memberof google.protobuf.SourceCodeInfo
+             * @instance
+             */
+            SourceCodeInfo.prototype.location = $util.emptyArray;
+
+            /**
+             * Creates a new SourceCodeInfo instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.SourceCodeInfo
+             * @static
+             * @param {google.protobuf.ISourceCodeInfo=} [properties] Properties to set
+             * @returns {google.protobuf.SourceCodeInfo} SourceCodeInfo instance
+             */
+            SourceCodeInfo.create = function create(properties) {
+                return new SourceCodeInfo(properties);
+            };
+
+            /**
+             * Encodes the specified SourceCodeInfo message. Does not implicitly {@link google.protobuf.SourceCodeInfo.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.SourceCodeInfo
+             * @static
+             * @param {google.protobuf.ISourceCodeInfo} message SourceCodeInfo message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            SourceCodeInfo.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.location != null && message.location.length)
+                    for (var i = 0; i < message.location.length; ++i)
+                        $root.google.protobuf.SourceCodeInfo.Location.encode(message.location[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified SourceCodeInfo message, length delimited. Does not implicitly {@link google.protobuf.SourceCodeInfo.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.SourceCodeInfo
+             * @static
+             * @param {google.protobuf.ISourceCodeInfo} message SourceCodeInfo message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            SourceCodeInfo.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a SourceCodeInfo message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.SourceCodeInfo
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.SourceCodeInfo} SourceCodeInfo
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            SourceCodeInfo.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.SourceCodeInfo();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        if (!(message.location && message.location.length))
+                            message.location = [];
+                        message.location.push($root.google.protobuf.SourceCodeInfo.Location.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a SourceCodeInfo message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.SourceCodeInfo
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.SourceCodeInfo} SourceCodeInfo
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            SourceCodeInfo.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a SourceCodeInfo message.
+             * @function verify
+             * @memberof google.protobuf.SourceCodeInfo
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            SourceCodeInfo.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.location != null && message.hasOwnProperty("location")) {
+                    if (!Array.isArray(message.location))
+                        return "location: array expected";
+                    for (var i = 0; i < message.location.length; ++i) {
+                        var error = $root.google.protobuf.SourceCodeInfo.Location.verify(message.location[i]);
+                        if (error)
+                            return "location." + error;
+                    }
+                }
+                return null;
+            };
+
+            /**
+             * Creates a SourceCodeInfo message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.SourceCodeInfo
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.SourceCodeInfo} SourceCodeInfo
+             */
+            SourceCodeInfo.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.SourceCodeInfo)
+                    return object;
+                var message = new $root.google.protobuf.SourceCodeInfo();
+                if (object.location) {
+                    if (!Array.isArray(object.location))
+                        throw TypeError(".google.protobuf.SourceCodeInfo.location: array expected");
+                    message.location = [];
+                    for (var i = 0; i < object.location.length; ++i) {
+                        if (typeof object.location[i] !== "object")
+                            throw TypeError(".google.protobuf.SourceCodeInfo.location: object expected");
+                        message.location[i] = $root.google.protobuf.SourceCodeInfo.Location.fromObject(object.location[i]);
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a SourceCodeInfo message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.SourceCodeInfo
+             * @static
+             * @param {google.protobuf.SourceCodeInfo} message SourceCodeInfo
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            SourceCodeInfo.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.location = [];
+                if (message.location && message.location.length) {
+                    object.location = [];
+                    for (var j = 0; j < message.location.length; ++j)
+                        object.location[j] = $root.google.protobuf.SourceCodeInfo.Location.toObject(message.location[j], options);
+                }
+                return object;
+            };
+
+            /**
+             * Converts this SourceCodeInfo to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.SourceCodeInfo
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            SourceCodeInfo.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for SourceCodeInfo
+             * @function getTypeUrl
+             * @memberof google.protobuf.SourceCodeInfo
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            SourceCodeInfo.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.SourceCodeInfo";
+            };
+
+            SourceCodeInfo.Location = (function() {
+
+                /**
+                 * Properties of a Location.
+                 * @memberof google.protobuf.SourceCodeInfo
+                 * @interface ILocation
+                 * @property {Array.<number>|null} [path] Location path
+                 * @property {Array.<number>|null} [span] Location span
+                 * @property {string|null} [leadingComments] Location leadingComments
+                 * @property {string|null} [trailingComments] Location trailingComments
+                 * @property {Array.<string>|null} [leadingDetachedComments] Location leadingDetachedComments
+                 */
+
+                /**
+                 * Constructs a new Location.
+                 * @memberof google.protobuf.SourceCodeInfo
+                 * @classdesc Represents a Location.
+                 * @implements ILocation
+                 * @constructor
+                 * @param {google.protobuf.SourceCodeInfo.ILocation=} [properties] Properties to set
+                 */
+                function Location(properties) {
+                    this.path = [];
+                    this.span = [];
+                    this.leadingDetachedComments = [];
+                    if (properties)
+                        for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                            if (properties[keys[i]] != null)
+                                this[keys[i]] = properties[keys[i]];
+                }
+
+                /**
+                 * Location path.
+                 * @member {Array.<number>} path
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @instance
+                 */
+                Location.prototype.path = $util.emptyArray;
+
+                /**
+                 * Location span.
+                 * @member {Array.<number>} span
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @instance
+                 */
+                Location.prototype.span = $util.emptyArray;
+
+                /**
+                 * Location leadingComments.
+                 * @member {string} leadingComments
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @instance
+                 */
+                Location.prototype.leadingComments = "";
+
+                /**
+                 * Location trailingComments.
+                 * @member {string} trailingComments
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @instance
+                 */
+                Location.prototype.trailingComments = "";
+
+                /**
+                 * Location leadingDetachedComments.
+                 * @member {Array.<string>} leadingDetachedComments
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @instance
+                 */
+                Location.prototype.leadingDetachedComments = $util.emptyArray;
+
+                /**
+                 * Creates a new Location instance using the specified properties.
+                 * @function create
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @static
+                 * @param {google.protobuf.SourceCodeInfo.ILocation=} [properties] Properties to set
+                 * @returns {google.protobuf.SourceCodeInfo.Location} Location instance
+                 */
+                Location.create = function create(properties) {
+                    return new Location(properties);
+                };
+
+                /**
+                 * Encodes the specified Location message. Does not implicitly {@link google.protobuf.SourceCodeInfo.Location.verify|verify} messages.
+                 * @function encode
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @static
+                 * @param {google.protobuf.SourceCodeInfo.ILocation} message Location message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                Location.encode = function encode(message, writer) {
+                    if (!writer)
+                        writer = $Writer.create();
+                    if (message.path != null && message.path.length) {
+                        writer.uint32(/* id 1, wireType 2 =*/10).fork();
+                        for (var i = 0; i < message.path.length; ++i)
+                            writer.int32(message.path[i]);
+                        writer.ldelim();
+                    }
+                    if (message.span != null && message.span.length) {
+                        writer.uint32(/* id 2, wireType 2 =*/18).fork();
+                        for (var i = 0; i < message.span.length; ++i)
+                            writer.int32(message.span[i]);
+                        writer.ldelim();
+                    }
+                    if (message.leadingComments != null && Object.hasOwnProperty.call(message, "leadingComments"))
+                        writer.uint32(/* id 3, wireType 2 =*/26).string(message.leadingComments);
+                    if (message.trailingComments != null && Object.hasOwnProperty.call(message, "trailingComments"))
+                        writer.uint32(/* id 4, wireType 2 =*/34).string(message.trailingComments);
+                    if (message.leadingDetachedComments != null && message.leadingDetachedComments.length)
+                        for (var i = 0; i < message.leadingDetachedComments.length; ++i)
+                            writer.uint32(/* id 6, wireType 2 =*/50).string(message.leadingDetachedComments[i]);
+                    return writer;
+                };
+
+                /**
+                 * Encodes the specified Location message, length delimited. Does not implicitly {@link google.protobuf.SourceCodeInfo.Location.verify|verify} messages.
+                 * @function encodeDelimited
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @static
+                 * @param {google.protobuf.SourceCodeInfo.ILocation} message Location message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                Location.encodeDelimited = function encodeDelimited(message, writer) {
+                    return this.encode(message, writer).ldelim();
+                };
+
+                /**
+                 * Decodes a Location message from the specified reader or buffer.
+                 * @function decode
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @param {number} [length] Message length if known beforehand
+                 * @returns {google.protobuf.SourceCodeInfo.Location} Location
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                Location.decode = function decode(reader, length) {
+                    if (!(reader instanceof $Reader))
+                        reader = $Reader.create(reader);
+                    var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.SourceCodeInfo.Location();
+                    while (reader.pos < end) {
+                        var tag = reader.uint32();
+                        switch (tag >>> 3) {
+                        case 1:
+                            if (!(message.path && message.path.length))
+                                message.path = [];
+                            if ((tag & 7) === 2) {
+                                var end2 = reader.uint32() + reader.pos;
+                                while (reader.pos < end2)
+                                    message.path.push(reader.int32());
+                            } else
+                                message.path.push(reader.int32());
+                            break;
+                        case 2:
+                            if (!(message.span && message.span.length))
+                                message.span = [];
+                            if ((tag & 7) === 2) {
+                                var end2 = reader.uint32() + reader.pos;
+                                while (reader.pos < end2)
+                                    message.span.push(reader.int32());
+                            } else
+                                message.span.push(reader.int32());
+                            break;
+                        case 3:
+                            message.leadingComments = reader.string();
+                            break;
+                        case 4:
+                            message.trailingComments = reader.string();
+                            break;
+                        case 6:
+                            if (!(message.leadingDetachedComments && message.leadingDetachedComments.length))
+                                message.leadingDetachedComments = [];
+                            message.leadingDetachedComments.push(reader.string());
+                            break;
+                        default:
+                            reader.skipType(tag & 7);
+                            break;
+                        }
+                    }
+                    return message;
+                };
+
+                /**
+                 * Decodes a Location message from the specified reader or buffer, length delimited.
+                 * @function decodeDelimited
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @returns {google.protobuf.SourceCodeInfo.Location} Location
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                Location.decodeDelimited = function decodeDelimited(reader) {
+                    if (!(reader instanceof $Reader))
+                        reader = new $Reader(reader);
+                    return this.decode(reader, reader.uint32());
+                };
+
+                /**
+                 * Verifies a Location message.
+                 * @function verify
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @static
+                 * @param {Object.<string,*>} message Plain object to verify
+                 * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                 */
+                Location.verify = function verify(message) {
+                    if (typeof message !== "object" || message === null)
+                        return "object expected";
+                    if (message.path != null && message.hasOwnProperty("path")) {
+                        if (!Array.isArray(message.path))
+                            return "path: array expected";
+                        for (var i = 0; i < message.path.length; ++i)
+                            if (!$util.isInteger(message.path[i]))
+                                return "path: integer[] expected";
+                    }
+                    if (message.span != null && message.hasOwnProperty("span")) {
+                        if (!Array.isArray(message.span))
+                            return "span: array expected";
+                        for (var i = 0; i < message.span.length; ++i)
+                            if (!$util.isInteger(message.span[i]))
+                                return "span: integer[] expected";
+                    }
+                    if (message.leadingComments != null && message.hasOwnProperty("leadingComments"))
+                        if (!$util.isString(message.leadingComments))
+                            return "leadingComments: string expected";
+                    if (message.trailingComments != null && message.hasOwnProperty("trailingComments"))
+                        if (!$util.isString(message.trailingComments))
+                            return "trailingComments: string expected";
+                    if (message.leadingDetachedComments != null && message.hasOwnProperty("leadingDetachedComments")) {
+                        if (!Array.isArray(message.leadingDetachedComments))
+                            return "leadingDetachedComments: array expected";
+                        for (var i = 0; i < message.leadingDetachedComments.length; ++i)
+                            if (!$util.isString(message.leadingDetachedComments[i]))
+                                return "leadingDetachedComments: string[] expected";
+                    }
+                    return null;
+                };
+
+                /**
+                 * Creates a Location message from a plain object. Also converts values to their respective internal types.
+                 * @function fromObject
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @static
+                 * @param {Object.<string,*>} object Plain object
+                 * @returns {google.protobuf.SourceCodeInfo.Location} Location
+                 */
+                Location.fromObject = function fromObject(object) {
+                    if (object instanceof $root.google.protobuf.SourceCodeInfo.Location)
+                        return object;
+                    var message = new $root.google.protobuf.SourceCodeInfo.Location();
+                    if (object.path) {
+                        if (!Array.isArray(object.path))
+                            throw TypeError(".google.protobuf.SourceCodeInfo.Location.path: array expected");
+                        message.path = [];
+                        for (var i = 0; i < object.path.length; ++i)
+                            message.path[i] = object.path[i] | 0;
+                    }
+                    if (object.span) {
+                        if (!Array.isArray(object.span))
+                            throw TypeError(".google.protobuf.SourceCodeInfo.Location.span: array expected");
+                        message.span = [];
+                        for (var i = 0; i < object.span.length; ++i)
+                            message.span[i] = object.span[i] | 0;
+                    }
+                    if (object.leadingComments != null)
+                        message.leadingComments = String(object.leadingComments);
+                    if (object.trailingComments != null)
+                        message.trailingComments = String(object.trailingComments);
+                    if (object.leadingDetachedComments) {
+                        if (!Array.isArray(object.leadingDetachedComments))
+                            throw TypeError(".google.protobuf.SourceCodeInfo.Location.leadingDetachedComments: array expected");
+                        message.leadingDetachedComments = [];
+                        for (var i = 0; i < object.leadingDetachedComments.length; ++i)
+                            message.leadingDetachedComments[i] = String(object.leadingDetachedComments[i]);
+                    }
+                    return message;
+                };
+
+                /**
+                 * Creates a plain object from a Location message. Also converts values to other types if specified.
+                 * @function toObject
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @static
+                 * @param {google.protobuf.SourceCodeInfo.Location} message Location
+                 * @param {$protobuf.IConversionOptions} [options] Conversion options
+                 * @returns {Object.<string,*>} Plain object
+                 */
+                Location.toObject = function toObject(message, options) {
+                    if (!options)
+                        options = {};
+                    var object = {};
+                    if (options.arrays || options.defaults) {
+                        object.path = [];
+                        object.span = [];
+                        object.leadingDetachedComments = [];
+                    }
+                    if (options.defaults) {
+                        object.leadingComments = "";
+                        object.trailingComments = "";
+                    }
+                    if (message.path && message.path.length) {
+                        object.path = [];
+                        for (var j = 0; j < message.path.length; ++j)
+                            object.path[j] = message.path[j];
+                    }
+                    if (message.span && message.span.length) {
+                        object.span = [];
+                        for (var j = 0; j < message.span.length; ++j)
+                            object.span[j] = message.span[j];
+                    }
+                    if (message.leadingComments != null && message.hasOwnProperty("leadingComments"))
+                        object.leadingComments = message.leadingComments;
+                    if (message.trailingComments != null && message.hasOwnProperty("trailingComments"))
+                        object.trailingComments = message.trailingComments;
+                    if (message.leadingDetachedComments && message.leadingDetachedComments.length) {
+                        object.leadingDetachedComments = [];
+                        for (var j = 0; j < message.leadingDetachedComments.length; ++j)
+                            object.leadingDetachedComments[j] = message.leadingDetachedComments[j];
+                    }
+                    return object;
+                };
+
+                /**
+                 * Converts this Location to JSON.
+                 * @function toJSON
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @instance
+                 * @returns {Object.<string,*>} JSON object
+                 */
+                Location.prototype.toJSON = function toJSON() {
+                    return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                };
+
+                /**
+                 * Gets the default type url for Location
+                 * @function getTypeUrl
+                 * @memberof google.protobuf.SourceCodeInfo.Location
+                 * @static
+                 * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                 * @returns {string} The default type url
+                 */
+                Location.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                    if (typeUrlPrefix === undefined) {
+                        typeUrlPrefix = "type.googleapis.com";
+                    }
+                    return typeUrlPrefix + "/google.protobuf.SourceCodeInfo.Location";
+                };
+
+                return Location;
+            })();
+
+            return SourceCodeInfo;
+        })();
+
+        protobuf.GeneratedCodeInfo = (function() {
+
+            /**
+             * Properties of a GeneratedCodeInfo.
+             * @memberof google.protobuf
+             * @interface IGeneratedCodeInfo
+             * @property {Array.<google.protobuf.GeneratedCodeInfo.IAnnotation>|null} [annotation] GeneratedCodeInfo annotation
+             */
+
+            /**
+             * Constructs a new GeneratedCodeInfo.
+             * @memberof google.protobuf
+             * @classdesc Represents a GeneratedCodeInfo.
+             * @implements IGeneratedCodeInfo
+             * @constructor
+             * @param {google.protobuf.IGeneratedCodeInfo=} [properties] Properties to set
+             */
+            function GeneratedCodeInfo(properties) {
+                this.annotation = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+
+            /**
+             * GeneratedCodeInfo annotation.
+             * @member {Array.<google.protobuf.GeneratedCodeInfo.IAnnotation>} annotation
+             * @memberof google.protobuf.GeneratedCodeInfo
+             * @instance
+             */
+            GeneratedCodeInfo.prototype.annotation = $util.emptyArray;
+
+            /**
+             * Creates a new GeneratedCodeInfo instance using the specified properties.
+             * @function create
+             * @memberof google.protobuf.GeneratedCodeInfo
+             * @static
+             * @param {google.protobuf.IGeneratedCodeInfo=} [properties] Properties to set
+             * @returns {google.protobuf.GeneratedCodeInfo} GeneratedCodeInfo instance
+             */
+            GeneratedCodeInfo.create = function create(properties) {
+                return new GeneratedCodeInfo(properties);
+            };
+
+            /**
+             * Encodes the specified GeneratedCodeInfo message. Does not implicitly {@link google.protobuf.GeneratedCodeInfo.verify|verify} messages.
+             * @function encode
+             * @memberof google.protobuf.GeneratedCodeInfo
+             * @static
+             * @param {google.protobuf.IGeneratedCodeInfo} message GeneratedCodeInfo message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            GeneratedCodeInfo.encode = function encode(message, writer) {
+                if (!writer)
+                    writer = $Writer.create();
+                if (message.annotation != null && message.annotation.length)
+                    for (var i = 0; i < message.annotation.length; ++i)
+                        $root.google.protobuf.GeneratedCodeInfo.Annotation.encode(message.annotation[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim();
+                return writer;
+            };
+
+            /**
+             * Encodes the specified GeneratedCodeInfo message, length delimited. Does not implicitly {@link google.protobuf.GeneratedCodeInfo.verify|verify} messages.
+             * @function encodeDelimited
+             * @memberof google.protobuf.GeneratedCodeInfo
+             * @static
+             * @param {google.protobuf.IGeneratedCodeInfo} message GeneratedCodeInfo message or plain object to encode
+             * @param {$protobuf.Writer} [writer] Writer to encode to
+             * @returns {$protobuf.Writer} Writer
+             */
+            GeneratedCodeInfo.encodeDelimited = function encodeDelimited(message, writer) {
+                return this.encode(message, writer).ldelim();
+            };
+
+            /**
+             * Decodes a GeneratedCodeInfo message from the specified reader or buffer.
+             * @function decode
+             * @memberof google.protobuf.GeneratedCodeInfo
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @param {number} [length] Message length if known beforehand
+             * @returns {google.protobuf.GeneratedCodeInfo} GeneratedCodeInfo
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            GeneratedCodeInfo.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.GeneratedCodeInfo();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        if (!(message.annotation && message.annotation.length))
+                            message.annotation = [];
+                        message.annotation.push($root.google.protobuf.GeneratedCodeInfo.Annotation.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Decodes a GeneratedCodeInfo message from the specified reader or buffer, length delimited.
+             * @function decodeDelimited
+             * @memberof google.protobuf.GeneratedCodeInfo
+             * @static
+             * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+             * @returns {google.protobuf.GeneratedCodeInfo} GeneratedCodeInfo
+             * @throws {Error} If the payload is not a reader or valid buffer
+             * @throws {$protobuf.util.ProtocolError} If required fields are missing
+             */
+            GeneratedCodeInfo.decodeDelimited = function decodeDelimited(reader) {
+                if (!(reader instanceof $Reader))
+                    reader = new $Reader(reader);
+                return this.decode(reader, reader.uint32());
+            };
+
+            /**
+             * Verifies a GeneratedCodeInfo message.
+             * @function verify
+             * @memberof google.protobuf.GeneratedCodeInfo
+             * @static
+             * @param {Object.<string,*>} message Plain object to verify
+             * @returns {string|null} `null` if valid, otherwise the reason why it is not
+             */
+            GeneratedCodeInfo.verify = function verify(message) {
+                if (typeof message !== "object" || message === null)
+                    return "object expected";
+                if (message.annotation != null && message.hasOwnProperty("annotation")) {
+                    if (!Array.isArray(message.annotation))
+                        return "annotation: array expected";
+                    for (var i = 0; i < message.annotation.length; ++i) {
+                        var error = $root.google.protobuf.GeneratedCodeInfo.Annotation.verify(message.annotation[i]);
+                        if (error)
+                            return "annotation." + error;
+                    }
+                }
+                return null;
+            };
+
+            /**
+             * Creates a GeneratedCodeInfo message from a plain object. Also converts values to their respective internal types.
+             * @function fromObject
+             * @memberof google.protobuf.GeneratedCodeInfo
+             * @static
+             * @param {Object.<string,*>} object Plain object
+             * @returns {google.protobuf.GeneratedCodeInfo} GeneratedCodeInfo
+             */
+            GeneratedCodeInfo.fromObject = function fromObject(object) {
+                if (object instanceof $root.google.protobuf.GeneratedCodeInfo)
+                    return object;
+                var message = new $root.google.protobuf.GeneratedCodeInfo();
+                if (object.annotation) {
+                    if (!Array.isArray(object.annotation))
+                        throw TypeError(".google.protobuf.GeneratedCodeInfo.annotation: array expected");
+                    message.annotation = [];
+                    for (var i = 0; i < object.annotation.length; ++i) {
+                        if (typeof object.annotation[i] !== "object")
+                            throw TypeError(".google.protobuf.GeneratedCodeInfo.annotation: object expected");
+                        message.annotation[i] = $root.google.protobuf.GeneratedCodeInfo.Annotation.fromObject(object.annotation[i]);
+                    }
+                }
+                return message;
+            };
+
+            /**
+             * Creates a plain object from a GeneratedCodeInfo message. Also converts values to other types if specified.
+             * @function toObject
+             * @memberof google.protobuf.GeneratedCodeInfo
+             * @static
+             * @param {google.protobuf.GeneratedCodeInfo} message GeneratedCodeInfo
+             * @param {$protobuf.IConversionOptions} [options] Conversion options
+             * @returns {Object.<string,*>} Plain object
+             */
+            GeneratedCodeInfo.toObject = function toObject(message, options) {
+                if (!options)
+                    options = {};
+                var object = {};
+                if (options.arrays || options.defaults)
+                    object.annotation = [];
+                if (message.annotation && message.annotation.length) {
+                    object.annotation = [];
+                    for (var j = 0; j < message.annotation.length; ++j)
+                        object.annotation[j] = $root.google.protobuf.GeneratedCodeInfo.Annotation.toObject(message.annotation[j], options);
+                }
+                return object;
+            };
+
+            /**
+             * Converts this GeneratedCodeInfo to JSON.
+             * @function toJSON
+             * @memberof google.protobuf.GeneratedCodeInfo
+             * @instance
+             * @returns {Object.<string,*>} JSON object
+             */
+            GeneratedCodeInfo.prototype.toJSON = function toJSON() {
+                return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+            };
+
+            /**
+             * Gets the default type url for GeneratedCodeInfo
+             * @function getTypeUrl
+             * @memberof google.protobuf.GeneratedCodeInfo
+             * @static
+             * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+             * @returns {string} The default type url
+             */
+            GeneratedCodeInfo.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                if (typeUrlPrefix === undefined) {
+                    typeUrlPrefix = "type.googleapis.com";
+                }
+                return typeUrlPrefix + "/google.protobuf.GeneratedCodeInfo";
+            };
+
+            GeneratedCodeInfo.Annotation = (function() {
+
+                /**
+                 * Properties of an Annotation.
+                 * @memberof google.protobuf.GeneratedCodeInfo
+                 * @interface IAnnotation
+                 * @property {Array.<number>|null} [path] Annotation path
+                 * @property {string|null} [sourceFile] Annotation sourceFile
+                 * @property {number|null} [begin] Annotation begin
+                 * @property {number|null} [end] Annotation end
+                 */
+
+                /**
+                 * Constructs a new Annotation.
+                 * @memberof google.protobuf.GeneratedCodeInfo
+                 * @classdesc Represents an Annotation.
+                 * @implements IAnnotation
+                 * @constructor
+                 * @param {google.protobuf.GeneratedCodeInfo.IAnnotation=} [properties] Properties to set
+                 */
+                function Annotation(properties) {
+                    this.path = [];
+                    if (properties)
+                        for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                            if (properties[keys[i]] != null)
+                                this[keys[i]] = properties[keys[i]];
+                }
+
+                /**
+                 * Annotation path.
+                 * @member {Array.<number>} path
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @instance
+                 */
+                Annotation.prototype.path = $util.emptyArray;
+
+                /**
+                 * Annotation sourceFile.
+                 * @member {string} sourceFile
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @instance
+                 */
+                Annotation.prototype.sourceFile = "";
+
+                /**
+                 * Annotation begin.
+                 * @member {number} begin
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @instance
+                 */
+                Annotation.prototype.begin = 0;
+
+                /**
+                 * Annotation end.
+                 * @member {number} end
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @instance
+                 */
+                Annotation.prototype.end = 0;
+
+                /**
+                 * Creates a new Annotation instance using the specified properties.
+                 * @function create
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @static
+                 * @param {google.protobuf.GeneratedCodeInfo.IAnnotation=} [properties] Properties to set
+                 * @returns {google.protobuf.GeneratedCodeInfo.Annotation} Annotation instance
+                 */
+                Annotation.create = function create(properties) {
+                    return new Annotation(properties);
+                };
+
+                /**
+                 * Encodes the specified Annotation message. Does not implicitly {@link google.protobuf.GeneratedCodeInfo.Annotation.verify|verify} messages.
+                 * @function encode
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @static
+                 * @param {google.protobuf.GeneratedCodeInfo.IAnnotation} message Annotation message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                Annotation.encode = function encode(message, writer) {
+                    if (!writer)
+                        writer = $Writer.create();
+                    if (message.path != null && message.path.length) {
+                        writer.uint32(/* id 1, wireType 2 =*/10).fork();
+                        for (var i = 0; i < message.path.length; ++i)
+                            writer.int32(message.path[i]);
+                        writer.ldelim();
+                    }
+                    if (message.sourceFile != null && Object.hasOwnProperty.call(message, "sourceFile"))
+                        writer.uint32(/* id 2, wireType 2 =*/18).string(message.sourceFile);
+                    if (message.begin != null && Object.hasOwnProperty.call(message, "begin"))
+                        writer.uint32(/* id 3, wireType 0 =*/24).int32(message.begin);
+                    if (message.end != null && Object.hasOwnProperty.call(message, "end"))
+                        writer.uint32(/* id 4, wireType 0 =*/32).int32(message.end);
+                    return writer;
+                };
+
+                /**
+                 * Encodes the specified Annotation message, length delimited. Does not implicitly {@link google.protobuf.GeneratedCodeInfo.Annotation.verify|verify} messages.
+                 * @function encodeDelimited
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @static
+                 * @param {google.protobuf.GeneratedCodeInfo.IAnnotation} message Annotation message or plain object to encode
+                 * @param {$protobuf.Writer} [writer] Writer to encode to
+                 * @returns {$protobuf.Writer} Writer
+                 */
+                Annotation.encodeDelimited = function encodeDelimited(message, writer) {
+                    return this.encode(message, writer).ldelim();
+                };
+
+                /**
+                 * Decodes an Annotation message from the specified reader or buffer.
+                 * @function decode
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @param {number} [length] Message length if known beforehand
+                 * @returns {google.protobuf.GeneratedCodeInfo.Annotation} Annotation
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                Annotation.decode = function decode(reader, length) {
+                    if (!(reader instanceof $Reader))
+                        reader = $Reader.create(reader);
+                    var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.GeneratedCodeInfo.Annotation();
+                    while (reader.pos < end) {
+                        var tag = reader.uint32();
+                        switch (tag >>> 3) {
+                        case 1:
+                            if (!(message.path && message.path.length))
+                                message.path = [];
+                            if ((tag & 7) === 2) {
+                                var end2 = reader.uint32() + reader.pos;
+                                while (reader.pos < end2)
+                                    message.path.push(reader.int32());
+                            } else
+                                message.path.push(reader.int32());
+                            break;
+                        case 2:
+                            message.sourceFile = reader.string();
+                            break;
+                        case 3:
+                            message.begin = reader.int32();
+                            break;
+                        case 4:
+                            message.end = reader.int32();
+                            break;
+                        default:
+                            reader.skipType(tag & 7);
+                            break;
+                        }
+                    }
+                    return message;
+                };
+
+                /**
+                 * Decodes an Annotation message from the specified reader or buffer, length delimited.
+                 * @function decodeDelimited
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @static
+                 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                 * @returns {google.protobuf.GeneratedCodeInfo.Annotation} Annotation
+                 * @throws {Error} If the payload is not a reader or valid buffer
+                 * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                 */
+                Annotation.decodeDelimited = function decodeDelimited(reader) {
+                    if (!(reader instanceof $Reader))
+                        reader = new $Reader(reader);
+                    return this.decode(reader, reader.uint32());
+                };
+
+                /**
+                 * Verifies an Annotation message.
+                 * @function verify
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @static
+                 * @param {Object.<string,*>} message Plain object to verify
+                 * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                 */
+                Annotation.verify = function verify(message) {
+                    if (typeof message !== "object" || message === null)
+                        return "object expected";
+                    if (message.path != null && message.hasOwnProperty("path")) {
+                        if (!Array.isArray(message.path))
+                            return "path: array expected";
+                        for (var i = 0; i < message.path.length; ++i)
+                            if (!$util.isInteger(message.path[i]))
+                                return "path: integer[] expected";
+                    }
+                    if (message.sourceFile != null && message.hasOwnProperty("sourceFile"))
+                        if (!$util.isString(message.sourceFile))
+                            return "sourceFile: string expected";
+                    if (message.begin != null && message.hasOwnProperty("begin"))
+                        if (!$util.isInteger(message.begin))
+                            return "begin: integer expected";
+                    if (message.end != null && message.hasOwnProperty("end"))
+                        if (!$util.isInteger(message.end))
+                            return "end: integer expected";
+                    return null;
+                };
+
+                /**
+                 * Creates an Annotation message from a plain object. Also converts values to their respective internal types.
+                 * @function fromObject
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @static
+                 * @param {Object.<string,*>} object Plain object
+                 * @returns {google.protobuf.GeneratedCodeInfo.Annotation} Annotation
+                 */
+                Annotation.fromObject = function fromObject(object) {
+                    if (object instanceof $root.google.protobuf.GeneratedCodeInfo.Annotation)
+                        return object;
+                    var message = new $root.google.protobuf.GeneratedCodeInfo.Annotation();
+                    if (object.path) {
+                        if (!Array.isArray(object.path))
+                            throw TypeError(".google.protobuf.GeneratedCodeInfo.Annotation.path: array expected");
+                        message.path = [];
+                        for (var i = 0; i < object.path.length; ++i)
+                            message.path[i] = object.path[i] | 0;
+                    }
+                    if (object.sourceFile != null)
+                        message.sourceFile = String(object.sourceFile);
+                    if (object.begin != null)
+                        message.begin = object.begin | 0;
+                    if (object.end != null)
+                        message.end = object.end | 0;
+                    return message;
+                };
+
+                /**
+                 * Creates a plain object from an Annotation message. Also converts values to other types if specified.
+                 * @function toObject
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @static
+                 * @param {google.protobuf.GeneratedCodeInfo.Annotation} message Annotation
+                 * @param {$protobuf.IConversionOptions} [options] Conversion options
+                 * @returns {Object.<string,*>} Plain object
+                 */
+                Annotation.toObject = function toObject(message, options) {
+                    if (!options)
+                        options = {};
+                    var object = {};
+                    if (options.arrays || options.defaults)
+                        object.path = [];
+                    if (options.defaults) {
+                        object.sourceFile = "";
+                        object.begin = 0;
+                        object.end = 0;
+                    }
+                    if (message.path && message.path.length) {
+                        object.path = [];
+                        for (var j = 0; j < message.path.length; ++j)
+                            object.path[j] = message.path[j];
+                    }
+                    if (message.sourceFile != null && message.hasOwnProperty("sourceFile"))
+                        object.sourceFile = message.sourceFile;
+                    if (message.begin != null && message.hasOwnProperty("begin"))
+                        object.begin = message.begin;
+                    if (message.end != null && message.hasOwnProperty("end"))
+                        object.end = message.end;
+                    return object;
+                };
+
+                /**
+                 * Converts this Annotation to JSON.
+                 * @function toJSON
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @instance
+                 * @returns {Object.<string,*>} JSON object
+                 */
+                Annotation.prototype.toJSON = function toJSON() {
+                    return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                };
+
+                /**
+                 * Gets the default type url for Annotation
+                 * @function getTypeUrl
+                 * @memberof google.protobuf.GeneratedCodeInfo.Annotation
+                 * @static
+                 * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                 * @returns {string} The default type url
+                 */
+                Annotation.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                    if (typeUrlPrefix === undefined) {
+                        typeUrlPrefix = "type.googleapis.com";
+                    }
+                    return typeUrlPrefix + "/google.protobuf.GeneratedCodeInfo.Annotation";
+                };
+
+                return Annotation;
+            })();
+
+            return GeneratedCodeInfo;
+        })();
+
+        return protobuf;
+    })();
+
+    return google;
+})();
+
+module.exports = $root;
diff --git a/tests/data/test.js.ts b/tests/data/test.js.ts
new file mode 100644
index 0000000..67dc6eb
--- /dev/null
+++ b/tests/data/test.js.ts
@@ -0,0 +1,19 @@
+import * as protobuf from "../..";
+import * as test from "./test";
+
+// should encode an object implementing the interface
+let mInterface: test.jspb.test.ISimple1 = { aString: "a-string", aRepeatedString: [ "a", "repeated", "string" ], aBoolean: true };
+let mInterfaceWriter: protobuf.Writer = test.jspb.test.Simple1.encode(mInterface);
+
+// should encode a message
+let mMessage: test.jspb.test.Simple1 = test.jspb.test.Simple1.create(mInterface);
+let mMessageWritter: protobuf.Writer = test.jspb.test.Simple1.encode(mMessage);
+
+// should allow to assign a message to an interface
+mInterface = mMessage;
+
+// should not allow to assign an interface to a message
+// mMessage = mInterface;
+
+// should always decode to a message, not an interface
+let dMessage: test.jspb.test.Simple1 = test.jspb.test.Simple1.decode(mInterfaceWriter.finish());
diff --git a/tests/data/test.json b/tests/data/test.json
new file mode 100644
index 0000000..5186ed4
--- /dev/null
+++ b/tests/data/test.json
@@ -0,0 +1,1564 @@
+{
+  "options": {
+    "java_package": "com.google.apps.jspb.proto",
+    "java_multiple_files": true
+  },
+  "nested": {
+    "jspb": {
+      "nested": {
+        "test": {
+          "nested": {
+            "Empty": {
+              "fields": {}
+            },
+            "OuterEnum": {
+              "values": {
+                "FOO": 1,
+                "BAR": 2
+              }
+            },
+            "EnumContainer": {
+              "fields": {
+                "outerEnum": {
+                  "type": "OuterEnum",
+                  "id": 1
+                }
+              }
+            },
+            "Simple1": {
+              "fields": {
+                "aString": {
+                  "rule": "required",
+                  "type": "string",
+                  "id": 1
+                },
+                "aRepeatedString": {
+                  "rule": "repeated",
+                  "type": "string",
+                  "id": 2
+                },
+                "aBoolean": {
+                  "type": "bool",
+                  "id": 3
+                }
+              }
+            },
+            "Simple2": {
+              "fields": {
+                "aString": {
+                  "rule": "required",
+                  "type": "string",
+                  "id": 1
+                },
+                "aRepeatedString": {
+                  "rule": "repeated",
+                  "type": "string",
+                  "id": 2
+                }
+              }
+            },
+            "SpecialCases": {
+              "fields": {
+                "normal": {
+                  "rule": "required",
+                  "type": "string",
+                  "id": 1
+                },
+                "default": {
+                  "rule": "required",
+                  "type": "string",
+                  "id": 2
+                },
+                "function": {
+                  "rule": "required",
+                  "type": "string",
+                  "id": 3
+                },
+                "var": {
+                  "rule": "required",
+                  "type": "string",
+                  "id": 4
+                }
+              }
+            },
+            "OptionalFields": {
+              "fields": {
+                "aString": {
+                  "type": "string",
+                  "id": 1
+                },
+                "aBool": {
+                  "rule": "required",
+                  "type": "bool",
+                  "id": 2
+                },
+                "aNestedMessage": {
+                  "type": "Nested",
+                  "id": 3
+                },
+                "aRepeatedMessage": {
+                  "rule": "repeated",
+                  "type": "Nested",
+                  "id": 4
+                },
+                "aRepeatedString": {
+                  "rule": "repeated",
+                  "type": "string",
+                  "id": 5
+                }
+              },
+              "nested": {
+                "Nested": {
+                  "fields": {
+                    "anInt": {
+                      "type": "int32",
+                      "id": 1
+                    }
+                  }
+                }
+              }
+            },
+            "HasExtensions": {
+              "fields": {
+                "str1": {
+                  "type": "string",
+                  "id": 1
+                },
+                "str2": {
+                  "type": "string",
+                  "id": 2
+                },
+                "str3": {
+                  "type": "string",
+                  "id": 3
+                }
+              },
+              "extensions": [
+                [
+                  10,
+                  536870911
+                ]
+              ]
+            },
+            "Complex": {
+              "fields": {
+                "aString": {
+                  "rule": "required",
+                  "type": "string",
+                  "id": 1
+                },
+                "anOutOfOrderBool": {
+                  "rule": "required",
+                  "type": "bool",
+                  "id": 9
+                },
+                "aNestedMessage": {
+                  "type": "Nested",
+                  "id": 4
+                },
+                "aRepeatedMessage": {
+                  "rule": "repeated",
+                  "type": "Nested",
+                  "id": 5
+                },
+                "aRepeatedString": {
+                  "rule": "repeated",
+                  "type": "string",
+                  "id": 7
+                }
+              },
+              "nested": {
+                "Nested": {
+                  "fields": {
+                    "anInt": {
+                      "rule": "required",
+                      "type": "int32",
+                      "id": 2
+                    }
+                  }
+                }
+              }
+            },
+            "OuterMessage": {
+              "fields": {},
+              "nested": {
+                "Complex": {
+                  "fields": {
+                    "innerComplexField": {
+                      "type": "int32",
+                      "id": 1
+                    }
+                  }
+                }
+              }
+            },
+            "IsExtension": {
+              "fields": {
+                "ext1": {
+                  "type": "string",
+                  "id": 1
+                }
+              },
+              "nested": {
+                "extField": {
+                  "type": "IsExtension",
+                  "id": 100,
+                  "extend": "HasExtensions"
+                },
+                "simpleOption": {
+                  "type": "string",
+                  "id": 42113038,
+                  "extend": "google.protobuf.EnumOptions"
+                }
+              }
+            },
+            "IndirectExtension": {
+              "fields": {},
+              "nested": {
+                "simple": {
+                  "type": "Simple1",
+                  "id": 101,
+                  "extend": "HasExtensions"
+                },
+                "str": {
+                  "type": "string",
+                  "id": 102,
+                  "extend": "HasExtensions"
+                },
+                "repeatedStr": {
+                  "rule": "repeated",
+                  "type": "string",
+                  "id": 103,
+                  "extend": "HasExtensions"
+                },
+                "repeatedSimple": {
+                  "rule": "repeated",
+                  "type": "Simple1",
+                  "id": 104,
+                  "extend": "HasExtensions"
+                }
+              }
+            },
+            "simple1": {
+              "type": "Simple1",
+              "id": 105,
+              "extend": "HasExtensions"
+            },
+            "DefaultValues": {
+              "fields": {
+                "stringField": {
+                  "type": "string",
+                  "id": 1,
+                  "options": {
+                    "default": "default<>abc"
+                  }
+                },
+                "boolField": {
+                  "type": "bool",
+                  "id": 2,
+                  "options": {
+                    "default": true
+                  }
+                },
+                "intField": {
+                  "type": "int64",
+                  "id": 3,
+                  "options": {
+                    "default": 11
+                  }
+                },
+                "enumField": {
+                  "type": "Enum",
+                  "id": 4,
+                  "options": {
+                    "default": "E1"
+                  }
+                },
+                "emptyField": {
+                  "type": "string",
+                  "id": 6,
+                  "options": {
+                    "default": ""
+                  }
+                },
+                "bytesField": {
+                  "type": "bytes",
+                  "id": 8,
+                  "options": {
+                    "default": "moo"
+                  }
+                }
+              },
+              "nested": {
+                "Enum": {
+                  "values": {
+                    "E1": 13,
+                    "E2": 77
+                  }
+                }
+              }
+            },
+            "FloatingPointFields": {
+              "fields": {
+                "optionalFloatField": {
+                  "type": "float",
+                  "id": 1
+                },
+                "requiredFloatField": {
+                  "rule": "required",
+                  "type": "float",
+                  "id": 2
+                },
+                "repeatedFloatField": {
+                  "rule": "repeated",
+                  "type": "float",
+                  "id": 3,
+                  "options": {
+                    "packed": false
+                  }
+                },
+                "defaultFloatField": {
+                  "type": "float",
+                  "id": 4,
+                  "options": {
+                    "default": 2
+                  }
+                },
+                "optionalDoubleField": {
+                  "type": "double",
+                  "id": 5
+                },
+                "requiredDoubleField": {
+                  "rule": "required",
+                  "type": "double",
+                  "id": 6
+                },
+                "repeatedDoubleField": {
+                  "rule": "repeated",
+                  "type": "double",
+                  "id": 7,
+                  "options": {
+                    "packed": false
+                  }
+                },
+                "defaultDoubleField": {
+                  "type": "double",
+                  "id": 8,
+                  "options": {
+                    "default": 2
+                  }
+                }
+              }
+            },
+            "TestClone": {
+              "fields": {
+                "str": {
+                  "type": "string",
+                  "id": 1
+                },
+                "simple1": {
+                  "type": "Simple1",
+                  "id": 3
+                },
+                "simple2": {
+                  "rule": "repeated",
+                  "type": "Simple1",
+                  "id": 5
+                },
+                "bytesField": {
+                  "type": "bytes",
+                  "id": 6
+                },
+                "unused": {
+                  "type": "string",
+                  "id": 7
+                }
+              },
+              "extensions": [
+                [
+                  10,
+                  536870911
+                ]
+              ]
+            },
+            "CloneExtension": {
+              "fields": {
+                "ext": {
+                  "type": "string",
+                  "id": 2
+                }
+              },
+              "nested": {
+                "extField": {
+                  "type": "CloneExtension",
+                  "id": 100,
+                  "extend": "TestClone"
+                }
+              }
+            },
+            "TestGroup": {
+              "fields": {
+                "repeatedGroup": {
+                  "rule": "repeated",
+                  "type": "RepeatedGroup",
+                  "id": 1
+                },
+                "requiredGroup": {
+                  "rule": "required",
+                  "type": "RequiredGroup",
+                  "id": 2
+                },
+                "optionalGroup": {
+                  "type": "OptionalGroup",
+                  "id": 3
+                },
+                "messageInGroup": {
+                  "type": "MessageInGroup",
+                  "id": 4
+                },
+                "enumInGroup": {
+                  "type": "EnumInGroup",
+                  "id": 5
+                },
+                "id": {
+                  "type": "string",
+                  "id": 6
+                },
+                "requiredSimple": {
+                  "rule": "required",
+                  "type": "Simple2",
+                  "id": 7
+                },
+                "optionalSimple": {
+                  "type": "Simple2",
+                  "id": 8
+                }
+              },
+              "nested": {
+                "RepeatedGroup": {
+                  "fields": {
+                    "id": {
+                      "rule": "required",
+                      "type": "string",
+                      "id": 1
+                    },
+                    "someBool": {
+                      "rule": "repeated",
+                      "type": "bool",
+                      "id": 2,
+                      "options": {
+                        "packed": false
+                      }
+                    }
+                  },
+                  "group": true
+                },
+                "RequiredGroup": {
+                  "fields": {
+                    "id": {
+                      "rule": "required",
+                      "type": "string",
+                      "id": 1
+                    }
+                  },
+                  "group": true
+                },
+                "OptionalGroup": {
+                  "fields": {
+                    "id": {
+                      "rule": "required",
+                      "type": "string",
+                      "id": 1
+                    }
+                  },
+                  "group": true
+                },
+                "MessageInGroup": {
+                  "fields": {
+                    "id": {
+                      "rule": "required",
+                      "type": "NetedMessage",
+                      "id": 1
+                    }
+                  },
+                  "nested": {
+                    "NetedMessage": {
+                      "fields": {
+                        "id": {
+                          "rule": "optional",
+                          "type": "string",
+                          "id": 1
+                        }
+                      }
+                    }
+                  },
+                  "group": true
+                },
+                "EnumInGroup": {
+                  "fields": {
+                    "id": {
+                      "rule": "required",
+                      "type": "NestedEnum",
+                      "id": 1
+                    }
+                  },
+                  "nested": {
+                    "NestedEnum": {
+                      "values": {
+                        "first": 0,
+                        "second": 1
+                      }
+                    }
+                  },
+                  "group": true
+                }
+              }
+            },
+            "TestGroup1": {
+              "fields": {
+                "group": {
+                  "type": "TestGroup.RepeatedGroup",
+                  "id": 1
+                }
+              }
+            },
+            "TestReservedNames": {
+              "fields": {
+                "extension": {
+                  "type": "int32",
+                  "id": 1
+                }
+              },
+              "extensions": [
+                [
+                  10,
+                  536870911
+                ]
+              ]
+            },
+            "TestReservedNamesExtension": {
+              "fields": {},
+              "nested": {
+                "foo": {
+                  "type": "int32",
+                  "id": 10,
+                  "extend": "TestReservedNames"
+                }
+              }
+            },
+            "TestMessageWithOneof": {
+              "oneofs": {
+                "partialOneof": {
+                  "oneof": [
+                    "pone",
+                    "pthree"
+                  ]
+                },
+                "recursiveOneof": {
+                  "oneof": [
+                    "rone",
+                    "rtwo"
+                  ]
+                },
+                "defaultOneofA": {
+                  "oneof": [
+                    "aone",
+                    "atwo"
+                  ]
+                },
+                "defaultOneofB": {
+                  "oneof": [
+                    "bone",
+                    "btwo"
+                  ]
+                }
+              },
+              "fields": {
+                "pone": {
+                  "type": "string",
+                  "id": 3
+                },
+                "pthree": {
+                  "type": "string",
+                  "id": 5
+                },
+                "rone": {
+                  "type": "TestMessageWithOneof",
+                  "id": 6
+                },
+                "rtwo": {
+                  "type": "string",
+                  "id": 7
+                },
+                "normalField": {
+                  "type": "bool",
+                  "id": 8
+                },
+                "repeatedField": {
+                  "rule": "repeated",
+                  "type": "string",
+                  "id": 9
+                },
+                "aone": {
+                  "type": "int32",
+                  "id": 10,
+                  "options": {
+                    "default": 1234
+                  }
+                },
+                "atwo": {
+                  "type": "int32",
+                  "id": 11
+                },
+                "bone": {
+                  "type": "int32",
+                  "id": 12
+                },
+                "btwo": {
+                  "type": "int32",
+                  "id": 13,
+                  "options": {
+                    "default": 1234
+                  }
+                }
+              }
+            },
+            "TestEndsWithBytes": {
+              "fields": {
+                "value": {
+                  "type": "int32",
+                  "id": 1
+                },
+                "data": {
+                  "type": "bytes",
+                  "id": 2
+                }
+              }
+            },
+            "TestMapFieldsNoBinary": {
+              "fields": {
+                "mapStringString": {
+                  "keyType": "string",
+                  "type": "string",
+                  "id": 1
+                },
+                "mapStringInt32": {
+                  "keyType": "string",
+                  "type": "int32",
+                  "id": 2
+                },
+                "mapStringInt64": {
+                  "keyType": "string",
+                  "type": "int64",
+                  "id": 3
+                },
+                "mapStringBool": {
+                  "keyType": "string",
+                  "type": "bool",
+                  "id": 4
+                },
+                "mapStringDouble": {
+                  "keyType": "string",
+                  "type": "double",
+                  "id": 5
+                },
+                "mapStringEnum": {
+                  "keyType": "string",
+                  "type": "MapValueEnumNoBinary",
+                  "id": 6
+                },
+                "mapStringMsg": {
+                  "keyType": "string",
+                  "type": "MapValueMessageNoBinary",
+                  "id": 7
+                },
+                "mapInt32String": {
+                  "keyType": "int32",
+                  "type": "string",
+                  "id": 8
+                },
+                "mapInt64String": {
+                  "keyType": "int64",
+                  "type": "string",
+                  "id": 9
+                },
+                "mapBoolString": {
+                  "keyType": "bool",
+                  "type": "string",
+                  "id": 10
+                },
+                "testMapFields": {
+                  "type": "TestMapFieldsNoBinary",
+                  "id": 11
+                },
+                "mapStringTestmapfields": {
+                  "keyType": "string",
+                  "type": "TestMapFieldsNoBinary",
+                  "id": 12
+                }
+              }
+            },
+            "MapValueEnumNoBinary": {
+              "values": {
+                "MAP_VALUE_FOO_NOBINARY": 0,
+                "MAP_VALUE_BAR_NOBINARY": 1,
+                "MAP_VALUE_BAZ_NOBINARY": 2
+              }
+            },
+            "MapValueMessageNoBinary": {
+              "fields": {
+                "foo": {
+                  "type": "int32",
+                  "id": 1
+                }
+              }
+            },
+            "Deeply": {
+              "fields": {},
+              "nested": {
+                "Nested": {
+                  "fields": {},
+                  "nested": {
+                    "Message": {
+                      "fields": {
+                        "count": {
+                          "type": "int32",
+                          "id": 1
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "google": {
+      "nested": {
+        "protobuf": {
+          "options": {
+            "go_package": "descriptor",
+            "java_package": "com.google.protobuf",
+            "java_outer_classname": "DescriptorProtos",
+            "csharp_namespace": "Google.Protobuf.Reflection",
+            "objc_class_prefix": "GPB",
+            "optimize_for": "SPEED"
+          },
+          "nested": {
+            "FileDescriptorSet": {
+              "fields": {
+                "file": {
+                  "rule": "repeated",
+                  "type": "FileDescriptorProto",
+                  "id": 1
+                }
+              }
+            },
+            "FileDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "package": {
+                  "type": "string",
+                  "id": 2
+                },
+                "dependency": {
+                  "rule": "repeated",
+                  "type": "string",
+                  "id": 3
+                },
+                "publicDependency": {
+                  "rule": "repeated",
+                  "type": "int32",
+                  "id": 10,
+                  "options": {
+                    "packed": false
+                  }
+                },
+                "weakDependency": {
+                  "rule": "repeated",
+                  "type": "int32",
+                  "id": 11,
+                  "options": {
+                    "packed": false
+                  }
+                },
+                "messageType": {
+                  "rule": "repeated",
+                  "type": "DescriptorProto",
+                  "id": 4
+                },
+                "enumType": {
+                  "rule": "repeated",
+                  "type": "EnumDescriptorProto",
+                  "id": 5
+                },
+                "service": {
+                  "rule": "repeated",
+                  "type": "ServiceDescriptorProto",
+                  "id": 6
+                },
+                "extension": {
+                  "rule": "repeated",
+                  "type": "FieldDescriptorProto",
+                  "id": 7
+                },
+                "options": {
+                  "type": "FileOptions",
+                  "id": 8
+                },
+                "sourceCodeInfo": {
+                  "type": "SourceCodeInfo",
+                  "id": 9
+                },
+                "syntax": {
+                  "type": "string",
+                  "id": 12
+                }
+              }
+            },
+            "DescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "field": {
+                  "rule": "repeated",
+                  "type": "FieldDescriptorProto",
+                  "id": 2
+                },
+                "extension": {
+                  "rule": "repeated",
+                  "type": "FieldDescriptorProto",
+                  "id": 6
+                },
+                "nestedType": {
+                  "rule": "repeated",
+                  "type": "DescriptorProto",
+                  "id": 3
+                },
+                "enumType": {
+                  "rule": "repeated",
+                  "type": "EnumDescriptorProto",
+                  "id": 4
+                },
+                "extensionRange": {
+                  "rule": "repeated",
+                  "type": "ExtensionRange",
+                  "id": 5
+                },
+                "oneofDecl": {
+                  "rule": "repeated",
+                  "type": "OneofDescriptorProto",
+                  "id": 8
+                },
+                "options": {
+                  "type": "MessageOptions",
+                  "id": 7
+                },
+                "reservedRange": {
+                  "rule": "repeated",
+                  "type": "ReservedRange",
+                  "id": 9
+                },
+                "reservedName": {
+                  "rule": "repeated",
+                  "type": "string",
+                  "id": 10
+                }
+              },
+              "nested": {
+                "ExtensionRange": {
+                  "fields": {
+                    "start": {
+                      "type": "int32",
+                      "id": 1
+                    },
+                    "end": {
+                      "type": "int32",
+                      "id": 2
+                    }
+                  }
+                },
+                "ReservedRange": {
+                  "fields": {
+                    "start": {
+                      "type": "int32",
+                      "id": 1
+                    },
+                    "end": {
+                      "type": "int32",
+                      "id": 2
+                    }
+                  }
+                }
+              }
+            },
+            "FieldDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "number": {
+                  "type": "int32",
+                  "id": 3
+                },
+                "label": {
+                  "type": "Label",
+                  "id": 4
+                },
+                "type": {
+                  "type": "Type",
+                  "id": 5
+                },
+                "typeName": {
+                  "type": "string",
+                  "id": 6
+                },
+                "extendee": {
+                  "type": "string",
+                  "id": 2
+                },
+                "defaultValue": {
+                  "type": "string",
+                  "id": 7
+                },
+                "oneofIndex": {
+                  "type": "int32",
+                  "id": 9
+                },
+                "jsonName": {
+                  "type": "string",
+                  "id": 10
+                },
+                "options": {
+                  "type": "FieldOptions",
+                  "id": 8
+                }
+              },
+              "nested": {
+                "Type": {
+                  "values": {
+                    "TYPE_DOUBLE": 1,
+                    "TYPE_FLOAT": 2,
+                    "TYPE_INT64": 3,
+                    "TYPE_UINT64": 4,
+                    "TYPE_INT32": 5,
+                    "TYPE_FIXED64": 6,
+                    "TYPE_FIXED32": 7,
+                    "TYPE_BOOL": 8,
+                    "TYPE_STRING": 9,
+                    "TYPE_GROUP": 10,
+                    "TYPE_MESSAGE": 11,
+                    "TYPE_BYTES": 12,
+                    "TYPE_UINT32": 13,
+                    "TYPE_ENUM": 14,
+                    "TYPE_SFIXED32": 15,
+                    "TYPE_SFIXED64": 16,
+                    "TYPE_SINT32": 17,
+                    "TYPE_SINT64": 18
+                  }
+                },
+                "Label": {
+                  "values": {
+                    "LABEL_OPTIONAL": 1,
+                    "LABEL_REQUIRED": 2,
+                    "LABEL_REPEATED": 3
+                  }
+                }
+              }
+            },
+            "OneofDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "options": {
+                  "type": "OneofOptions",
+                  "id": 2
+                }
+              }
+            },
+            "EnumDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "value": {
+                  "rule": "repeated",
+                  "type": "EnumValueDescriptorProto",
+                  "id": 2
+                },
+                "options": {
+                  "type": "EnumOptions",
+                  "id": 3
+                }
+              }
+            },
+            "EnumValueDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "number": {
+                  "type": "int32",
+                  "id": 2
+                },
+                "options": {
+                  "type": "EnumValueOptions",
+                  "id": 3
+                }
+              }
+            },
+            "ServiceDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "method": {
+                  "rule": "repeated",
+                  "type": "MethodDescriptorProto",
+                  "id": 2
+                },
+                "options": {
+                  "type": "ServiceOptions",
+                  "id": 3
+                }
+              }
+            },
+            "MethodDescriptorProto": {
+              "fields": {
+                "name": {
+                  "type": "string",
+                  "id": 1
+                },
+                "inputType": {
+                  "type": "string",
+                  "id": 2
+                },
+                "outputType": {
+                  "type": "string",
+                  "id": 3
+                },
+                "options": {
+                  "type": "MethodOptions",
+                  "id": 4
+                },
+                "clientStreaming": {
+                  "type": "bool",
+                  "id": 5,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "serverStreaming": {
+                  "type": "bool",
+                  "id": 6,
+                  "options": {
+                    "default": false
+                  }
+                }
+              }
+            },
+            "FileOptions": {
+              "fields": {
+                "javaPackage": {
+                  "type": "string",
+                  "id": 1
+                },
+                "javaOuterClassname": {
+                  "type": "string",
+                  "id": 8
+                },
+                "javaMultipleFiles": {
+                  "type": "bool",
+                  "id": 10,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "javaGenerateEqualsAndHash": {
+                  "type": "bool",
+                  "id": 20,
+                  "options": {
+                    "deprecated": true
+                  }
+                },
+                "javaStringCheckUtf8": {
+                  "type": "bool",
+                  "id": 27,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "optimizeFor": {
+                  "type": "OptimizeMode",
+                  "id": 9,
+                  "options": {
+                    "default": "SPEED"
+                  }
+                },
+                "goPackage": {
+                  "type": "string",
+                  "id": 11
+                },
+                "ccGenericServices": {
+                  "type": "bool",
+                  "id": 16,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "javaGenericServices": {
+                  "type": "bool",
+                  "id": 17,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "pyGenericServices": {
+                  "type": "bool",
+                  "id": 18,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "deprecated": {
+                  "type": "bool",
+                  "id": 23,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "ccEnableArenas": {
+                  "type": "bool",
+                  "id": 31,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "objcClassPrefix": {
+                  "type": "string",
+                  "id": 36
+                },
+                "csharpNamespace": {
+                  "type": "string",
+                  "id": 37
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ],
+              "reserved": [
+                [
+                  38,
+                  38
+                ]
+              ],
+              "nested": {
+                "OptimizeMode": {
+                  "values": {
+                    "SPEED": 1,
+                    "CODE_SIZE": 2,
+                    "LITE_RUNTIME": 3
+                  }
+                }
+              }
+            },
+            "MessageOptions": {
+              "fields": {
+                "messageSetWireFormat": {
+                  "type": "bool",
+                  "id": 1,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "noStandardDescriptorAccessor": {
+                  "type": "bool",
+                  "id": 2,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "deprecated": {
+                  "type": "bool",
+                  "id": 3,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "mapEntry": {
+                  "type": "bool",
+                  "id": 7
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ],
+              "reserved": [
+                [
+                  8,
+                  8
+                ]
+              ]
+            },
+            "FieldOptions": {
+              "fields": {
+                "ctype": {
+                  "type": "CType",
+                  "id": 1,
+                  "options": {
+                    "default": "STRING"
+                  }
+                },
+                "packed": {
+                  "type": "bool",
+                  "id": 2
+                },
+                "jstype": {
+                  "type": "JSType",
+                  "id": 6,
+                  "options": {
+                    "default": "JS_NORMAL"
+                  }
+                },
+                "lazy": {
+                  "type": "bool",
+                  "id": 5,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "deprecated": {
+                  "type": "bool",
+                  "id": 3,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "weak": {
+                  "type": "bool",
+                  "id": 10,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ],
+              "reserved": [
+                [
+                  4,
+                  4
+                ]
+              ],
+              "nested": {
+                "CType": {
+                  "values": {
+                    "STRING": 0,
+                    "CORD": 1,
+                    "STRING_PIECE": 2
+                  }
+                },
+                "JSType": {
+                  "values": {
+                    "JS_NORMAL": 0,
+                    "JS_STRING": 1,
+                    "JS_NUMBER": 2
+                  }
+                }
+              }
+            },
+            "OneofOptions": {
+              "fields": {
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ]
+            },
+            "EnumOptions": {
+              "fields": {
+                "allowAlias": {
+                  "type": "bool",
+                  "id": 2
+                },
+                "deprecated": {
+                  "type": "bool",
+                  "id": 3,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ]
+            },
+            "EnumValueOptions": {
+              "fields": {
+                "deprecated": {
+                  "type": "bool",
+                  "id": 1,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ]
+            },
+            "ServiceOptions": {
+              "fields": {
+                "deprecated": {
+                  "type": "bool",
+                  "id": 33,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ]
+            },
+            "MethodOptions": {
+              "fields": {
+                "deprecated": {
+                  "type": "bool",
+                  "id": 33,
+                  "options": {
+                    "default": false
+                  }
+                },
+                "idempotencyLevel": {
+                  "type": "IdempotencyLevel",
+                  "id": 34,
+                  "options": {
+                    "default": "IDEMPOTENCY_UNKNOWN"
+                  }
+                },
+                "uninterpretedOption": {
+                  "rule": "repeated",
+                  "type": "UninterpretedOption",
+                  "id": 999
+                }
+              },
+              "extensions": [
+                [
+                  1000,
+                  536870911
+                ]
+              ],
+              "nested": {
+                "IdempotencyLevel": {
+                  "values": {
+                    "IDEMPOTENCY_UNKNOWN": 0,
+                    "NO_SIDE_EFFECTS": 1,
+                    "IDEMPOTENT": 2
+                  }
+                }
+              }
+            },
+            "UninterpretedOption": {
+              "fields": {
+                "name": {
+                  "rule": "repeated",
+                  "type": "NamePart",
+                  "id": 2
+                },
+                "identifierValue": {
+                  "type": "string",
+                  "id": 3
+                },
+                "positiveIntValue": {
+                  "type": "uint64",
+                  "id": 4
+                },
+                "negativeIntValue": {
+                  "type": "int64",
+                  "id": 5
+                },
+                "doubleValue": {
+                  "type": "double",
+                  "id": 6
+                },
+                "stringValue": {
+                  "type": "bytes",
+                  "id": 7
+                },
+                "aggregateValue": {
+                  "type": "string",
+                  "id": 8
+                }
+              },
+              "nested": {
+                "NamePart": {
+                  "fields": {
+                    "namePart": {
+                      "rule": "required",
+                      "type": "string",
+                      "id": 1
+                    },
+                    "isExtension": {
+                      "rule": "required",
+                      "type": "bool",
+                      "id": 2
+                    }
+                  }
+                }
+              }
+            },
+            "SourceCodeInfo": {
+              "fields": {
+                "location": {
+                  "rule": "repeated",
+                  "type": "Location",
+                  "id": 1
+                }
+              },
+              "nested": {
+                "Location": {
+                  "fields": {
+                    "path": {
+                      "rule": "repeated",
+                      "type": "int32",
+                      "id": 1,
+                      "options": {
+                        "packed": true
+                      }
+                    },
+                    "span": {
+                      "rule": "repeated",
+                      "type": "int32",
+                      "id": 2,
+                      "options": {
+                        "packed": true
+                      }
+                    },
+                    "leadingComments": {
+                      "type": "string",
+                      "id": 3
+                    },
+                    "trailingComments": {
+                      "type": "string",
+                      "id": 4
+                    },
+                    "leadingDetachedComments": {
+                      "rule": "repeated",
+                      "type": "string",
+                      "id": 6
+                    }
+                  }
+                }
+              }
+            },
+            "GeneratedCodeInfo": {
+              "fields": {
+                "annotation": {
+                  "rule": "repeated",
+                  "type": "Annotation",
+                  "id": 1
+                }
+              },
+              "nested": {
+                "Annotation": {
+                  "fields": {
+                    "path": {
+                      "rule": "repeated",
+                      "type": "int32",
+                      "id": 1,
+                      "options": {
+                        "packed": true
+                      }
+                    },
+                    "sourceFile": {
+                      "type": "string",
+                      "id": 2
+                    },
+                    "begin": {
+                      "type": "int32",
+                      "id": 3
+                    },
+                    "end": {
+                      "type": "int32",
+                      "id": 4
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/tests/data/test.proto b/tests/data/test.proto
new file mode 100644
index 0000000..732f975
--- /dev/null
+++ b/tests/data/test.proto
@@ -0,0 +1,284 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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 Google 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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS 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.
+
+// Author: mwr@google.com (Mark Rawling)
+
+syntax = "proto2";
+
+option java_package = "com.google.apps.jspb.proto";
+
+import "google/protobuf/descriptor.proto";
+
+package jspb.test;
+
+message Empty {
+}
+
+enum OuterEnum {
+  FOO = 1;
+  BAR = 2;
+}
+
+message EnumContainer {
+  optional OuterEnum outer_enum = 1;
+}
+
+message Simple1 {
+  required string a_string = 1;
+  repeated string a_repeated_string = 2;
+  optional bool a_boolean = 3;
+}
+
+// A message that differs from Simple1 only by name
+message Simple2 {
+  required string a_string = 1;
+  repeated string a_repeated_string = 2;
+}
+
+message SpecialCases {
+  required string normal = 1;
+  // Examples of Js reserved names that are converted to pb_<name>.
+  required string default = 2;
+  required string function = 3;
+  required string var = 4;
+}
+
+message OptionalFields {
+  message Nested {
+    optional int32 an_int = 1;
+  }
+  optional string a_string = 1;
+  required bool a_bool = 2;
+  optional Nested a_nested_message = 3;
+  repeated Nested a_repeated_message = 4;
+  repeated string a_repeated_string = 5;
+}
+
+message HasExtensions {
+  optional string str1 = 1;
+  optional string str2 = 2;
+  optional string str3 = 3;
+  extensions 10 to max;
+}
+
+message Complex {
+  message Nested {
+    required int32 an_int = 2;
+  }
+  required string a_string = 1;
+  required bool an_out_of_order_bool = 9;
+  optional Nested a_nested_message = 4;
+  repeated Nested a_repeated_message = 5;
+  repeated string a_repeated_string = 7;
+}
+
+message OuterMessage {
+  // Make sure this doesn't conflict with the other Complex message.
+  message Complex {
+    optional int32 inner_complex_field = 1;
+  }
+}
+
+message IsExtension {
+  extend HasExtensions {
+    optional IsExtension ext_field = 100;
+  }
+  optional string ext1 = 1;
+
+  // Extensions of proto2 Descriptor messages will be ignored.
+  extend google.protobuf.EnumOptions {
+    optional string simple_option = 42113038;
+  }
+}
+
+message IndirectExtension {
+  extend HasExtensions {
+    optional Simple1 simple = 101;
+    optional string str = 102;
+    repeated string repeated_str = 103;
+    repeated Simple1 repeated_simple = 104;
+  }
+}
+
+extend HasExtensions {
+  optional Simple1 simple1 = 105;
+}
+
+message DefaultValues {
+  enum Enum {
+    E1 = 13;
+    E2 = 77;
+  }
+  optional string string_field = 1 [default="default<>\'\"abc"];
+  optional bool bool_field = 2 [default=true];
+  optional int64 int_field = 3 [default=11];
+  optional Enum enum_field = 4 [default=E1];
+  optional string empty_field = 6 [default=""];
+  optional bytes bytes_field = 8 [default="moo"]; // Base64 encoding is "bW9v"
+}
+
+message FloatingPointFields {
+  optional float optional_float_field = 1;
+  required float required_float_field = 2;
+  repeated float repeated_float_field = 3;
+  optional float default_float_field = 4 [default = 2.0];
+  optional double optional_double_field = 5;
+  required double required_double_field = 6;
+  repeated double repeated_double_field = 7;
+  optional double default_double_field = 8 [default = 2.0];
+}
+
+message TestClone {
+  optional string str = 1;
+  optional Simple1 simple1 = 3;
+  repeated Simple1 simple2 = 5;
+  optional bytes bytes_field = 6;
+  optional string unused = 7;
+  extensions 10 to max;
+}
+
+message CloneExtension {
+  extend TestClone {
+    optional CloneExtension ext_field = 100;
+  }
+  optional string ext = 2;
+}
+
+message TestGroup {
+  repeated group RepeatedGroup = 1 {
+    required string id = 1;
+    repeated bool some_bool = 2;
+  }
+  required group RequiredGroup = 2 {
+    required string id = 1;
+  }
+  optional group OptionalGroup = 3 {
+    required string id = 1;
+  }
+  optional group MessageInGroup = 4 {
+    message NestedMessage {
+      optional string id = 1;
+    }
+    required NestedMessage id = 1;
+  }
+  optional group EnumInGroup = 5 {
+    enum NestedEnum {
+      first = 0;
+      second = 1;
+    }
+    required NestedEnum id = 1;
+  }
+  optional string id = 6;
+  required Simple2 required_simple = 7;
+  optional Simple2 optional_simple = 8;
+}
+
+message TestGroup1 {
+  optional TestGroup.RepeatedGroup group = 1;
+}
+
+message TestReservedNames {
+  optional int32 extension = 1;
+  extensions 10 to max;
+}
+
+message TestReservedNamesExtension {
+  extend TestReservedNames {
+    optional int32 foo = 10;
+  }
+}
+
+message TestMessageWithOneof {
+
+  oneof partial_oneof {
+    string pone = 3;
+    string pthree = 5;
+  }
+
+  oneof recursive_oneof {
+    TestMessageWithOneof rone = 6;
+    string rtwo = 7;
+  }
+
+  optional bool normal_field = 8;
+  repeated string repeated_field = 9;
+
+  oneof default_oneof_a {
+    int32 aone = 10 [default = 1234];
+    int32 atwo = 11;
+  }
+
+  oneof default_oneof_b {
+    int32 bone = 12;
+    int32 btwo = 13 [default = 1234];
+  }
+}
+
+message TestEndsWithBytes {
+  optional int32 value = 1;
+  optional bytes data = 2;
+}
+
+message TestMapFieldsNoBinary {
+  map<string, string> map_string_string = 1;
+  map<string, int32> map_string_int32 = 2;
+  map<string, int64> map_string_int64 = 3;
+  map<string, bool> map_string_bool = 4;
+  map<string, double> map_string_double = 5;
+  map<string, MapValueEnumNoBinary> map_string_enum = 6;
+  map<string, MapValueMessageNoBinary> map_string_msg = 7;
+
+  map<int32, string> map_int32_string = 8;
+  map<int64, string> map_int64_string = 9;
+  map<bool, string> map_bool_string = 10;
+
+  optional TestMapFieldsNoBinary test_map_fields = 11;
+  map<string, TestMapFieldsNoBinary> map_string_testmapfields = 12;
+}
+
+enum MapValueEnumNoBinary {
+  MAP_VALUE_FOO_NOBINARY = 0;
+  MAP_VALUE_BAR_NOBINARY = 1;
+  MAP_VALUE_BAZ_NOBINARY = 2;
+}
+
+message MapValueMessageNoBinary {
+  optional int32 foo = 1;
+}
+
+message Deeply {
+  message Nested {
+    message Message {
+      optional int32 count = 1;
+    }
+  }
+}
+
+option java_multiple_files = true;
diff --git a/tests/data/type_url.js b/tests/data/type_url.js
new file mode 100644
index 0000000..3cf7daf
--- /dev/null
+++ b/tests/data/type_url.js
@@ -0,0 +1,421 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+"use strict";
+
+var $protobuf = require("../../minimal");
+
+// Common aliases
+var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+// Exported root namespace
+var $root = $protobuf.roots.test_type_url || ($protobuf.roots.test_type_url = {});
+
+$root.TypeUrlTest = (function() {
+
+    /**
+     * Properties of a TypeUrlTest.
+     * @exports ITypeUrlTest
+     * @interface ITypeUrlTest
+     * @property {TypeUrlTest.INested|null} [nested] TypeUrlTest nested
+     */
+
+    /**
+     * Constructs a new TypeUrlTest.
+     * @exports TypeUrlTest
+     * @classdesc Represents a TypeUrlTest.
+     * @implements ITypeUrlTest
+     * @constructor
+     * @param {ITypeUrlTest=} [properties] Properties to set
+     */
+    function TypeUrlTest(properties) {
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * TypeUrlTest nested.
+     * @member {TypeUrlTest.INested|null|undefined} nested
+     * @memberof TypeUrlTest
+     * @instance
+     */
+    TypeUrlTest.prototype.nested = null;
+
+    /**
+     * Creates a new TypeUrlTest instance using the specified properties.
+     * @function create
+     * @memberof TypeUrlTest
+     * @static
+     * @param {ITypeUrlTest=} [properties] Properties to set
+     * @returns {TypeUrlTest} TypeUrlTest instance
+     */
+    TypeUrlTest.create = function create(properties) {
+        return new TypeUrlTest(properties);
+    };
+
+    /**
+     * Encodes the specified TypeUrlTest message. Does not implicitly {@link TypeUrlTest.verify|verify} messages.
+     * @function encode
+     * @memberof TypeUrlTest
+     * @static
+     * @param {ITypeUrlTest} message TypeUrlTest message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    TypeUrlTest.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.nested != null && Object.hasOwnProperty.call(message, "nested"))
+            $root.TypeUrlTest.Nested.encode(message.nested, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim();
+        return writer;
+    };
+
+    /**
+     * Encodes the specified TypeUrlTest message, length delimited. Does not implicitly {@link TypeUrlTest.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof TypeUrlTest
+     * @static
+     * @param {ITypeUrlTest} message TypeUrlTest message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    TypeUrlTest.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a TypeUrlTest message from the specified reader or buffer.
+     * @function decode
+     * @memberof TypeUrlTest
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {TypeUrlTest} TypeUrlTest
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    TypeUrlTest.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.TypeUrlTest();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 1:
+                message.nested = $root.TypeUrlTest.Nested.decode(reader, reader.uint32());
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a TypeUrlTest message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof TypeUrlTest
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {TypeUrlTest} TypeUrlTest
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    TypeUrlTest.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a TypeUrlTest message.
+     * @function verify
+     * @memberof TypeUrlTest
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    TypeUrlTest.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.nested != null && message.hasOwnProperty("nested")) {
+            var error = $root.TypeUrlTest.Nested.verify(message.nested);
+            if (error)
+                return "nested." + error;
+        }
+        return null;
+    };
+
+    /**
+     * Creates a TypeUrlTest message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof TypeUrlTest
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {TypeUrlTest} TypeUrlTest
+     */
+    TypeUrlTest.fromObject = function fromObject(object) {
+        if (object instanceof $root.TypeUrlTest)
+            return object;
+        var message = new $root.TypeUrlTest();
+        if (object.nested != null) {
+            if (typeof object.nested !== "object")
+                throw TypeError(".TypeUrlTest.nested: object expected");
+            message.nested = $root.TypeUrlTest.Nested.fromObject(object.nested);
+        }
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a TypeUrlTest message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof TypeUrlTest
+     * @static
+     * @param {TypeUrlTest} message TypeUrlTest
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    TypeUrlTest.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        var object = {};
+        if (options.defaults)
+            object.nested = null;
+        if (message.nested != null && message.hasOwnProperty("nested"))
+            object.nested = $root.TypeUrlTest.Nested.toObject(message.nested, options);
+        return object;
+    };
+
+    /**
+     * Converts this TypeUrlTest to JSON.
+     * @function toJSON
+     * @memberof TypeUrlTest
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    TypeUrlTest.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    /**
+     * Gets the default type url for TypeUrlTest
+     * @function getTypeUrl
+     * @memberof TypeUrlTest
+     * @static
+     * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+     * @returns {string} The default type url
+     */
+    TypeUrlTest.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+        if (typeUrlPrefix === undefined) {
+            typeUrlPrefix = "type.googleapis.com";
+        }
+        return typeUrlPrefix + "/TypeUrlTest";
+    };
+
+    TypeUrlTest.Nested = (function() {
+
+        /**
+         * Properties of a Nested.
+         * @memberof TypeUrlTest
+         * @interface INested
+         * @property {string|null} [a] Nested a
+         */
+
+        /**
+         * Constructs a new Nested.
+         * @memberof TypeUrlTest
+         * @classdesc Represents a Nested.
+         * @implements INested
+         * @constructor
+         * @param {TypeUrlTest.INested=} [properties] Properties to set
+         */
+        function Nested(properties) {
+            if (properties)
+                for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                    if (properties[keys[i]] != null)
+                        this[keys[i]] = properties[keys[i]];
+        }
+
+        /**
+         * Nested a.
+         * @member {string} a
+         * @memberof TypeUrlTest.Nested
+         * @instance
+         */
+        Nested.prototype.a = "";
+
+        /**
+         * Creates a new Nested instance using the specified properties.
+         * @function create
+         * @memberof TypeUrlTest.Nested
+         * @static
+         * @param {TypeUrlTest.INested=} [properties] Properties to set
+         * @returns {TypeUrlTest.Nested} Nested instance
+         */
+        Nested.create = function create(properties) {
+            return new Nested(properties);
+        };
+
+        /**
+         * Encodes the specified Nested message. Does not implicitly {@link TypeUrlTest.Nested.verify|verify} messages.
+         * @function encode
+         * @memberof TypeUrlTest.Nested
+         * @static
+         * @param {TypeUrlTest.INested} message Nested message or plain object to encode
+         * @param {$protobuf.Writer} [writer] Writer to encode to
+         * @returns {$protobuf.Writer} Writer
+         */
+        Nested.encode = function encode(message, writer) {
+            if (!writer)
+                writer = $Writer.create();
+            if (message.a != null && Object.hasOwnProperty.call(message, "a"))
+                writer.uint32(/* id 1, wireType 2 =*/10).string(message.a);
+            return writer;
+        };
+
+        /**
+         * Encodes the specified Nested message, length delimited. Does not implicitly {@link TypeUrlTest.Nested.verify|verify} messages.
+         * @function encodeDelimited
+         * @memberof TypeUrlTest.Nested
+         * @static
+         * @param {TypeUrlTest.INested} message Nested message or plain object to encode
+         * @param {$protobuf.Writer} [writer] Writer to encode to
+         * @returns {$protobuf.Writer} Writer
+         */
+        Nested.encodeDelimited = function encodeDelimited(message, writer) {
+            return this.encode(message, writer).ldelim();
+        };
+
+        /**
+         * Decodes a Nested message from the specified reader or buffer.
+         * @function decode
+         * @memberof TypeUrlTest.Nested
+         * @static
+         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+         * @param {number} [length] Message length if known beforehand
+         * @returns {TypeUrlTest.Nested} Nested
+         * @throws {Error} If the payload is not a reader or valid buffer
+         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+         */
+        Nested.decode = function decode(reader, length) {
+            if (!(reader instanceof $Reader))
+                reader = $Reader.create(reader);
+            var end = length === undefined ? reader.len : reader.pos + length, message = new $root.TypeUrlTest.Nested();
+            while (reader.pos < end) {
+                var tag = reader.uint32();
+                switch (tag >>> 3) {
+                case 1:
+                    message.a = reader.string();
+                    break;
+                default:
+                    reader.skipType(tag & 7);
+                    break;
+                }
+            }
+            return message;
+        };
+
+        /**
+         * Decodes a Nested message from the specified reader or buffer, length delimited.
+         * @function decodeDelimited
+         * @memberof TypeUrlTest.Nested
+         * @static
+         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+         * @returns {TypeUrlTest.Nested} Nested
+         * @throws {Error} If the payload is not a reader or valid buffer
+         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+         */
+        Nested.decodeDelimited = function decodeDelimited(reader) {
+            if (!(reader instanceof $Reader))
+                reader = new $Reader(reader);
+            return this.decode(reader, reader.uint32());
+        };
+
+        /**
+         * Verifies a Nested message.
+         * @function verify
+         * @memberof TypeUrlTest.Nested
+         * @static
+         * @param {Object.<string,*>} message Plain object to verify
+         * @returns {string|null} `null` if valid, otherwise the reason why it is not
+         */
+        Nested.verify = function verify(message) {
+            if (typeof message !== "object" || message === null)
+                return "object expected";
+            if (message.a != null && message.hasOwnProperty("a"))
+                if (!$util.isString(message.a))
+                    return "a: string expected";
+            return null;
+        };
+
+        /**
+         * Creates a Nested message from a plain object. Also converts values to their respective internal types.
+         * @function fromObject
+         * @memberof TypeUrlTest.Nested
+         * @static
+         * @param {Object.<string,*>} object Plain object
+         * @returns {TypeUrlTest.Nested} Nested
+         */
+        Nested.fromObject = function fromObject(object) {
+            if (object instanceof $root.TypeUrlTest.Nested)
+                return object;
+            var message = new $root.TypeUrlTest.Nested();
+            if (object.a != null)
+                message.a = String(object.a);
+            return message;
+        };
+
+        /**
+         * Creates a plain object from a Nested message. Also converts values to other types if specified.
+         * @function toObject
+         * @memberof TypeUrlTest.Nested
+         * @static
+         * @param {TypeUrlTest.Nested} message Nested
+         * @param {$protobuf.IConversionOptions} [options] Conversion options
+         * @returns {Object.<string,*>} Plain object
+         */
+        Nested.toObject = function toObject(message, options) {
+            if (!options)
+                options = {};
+            var object = {};
+            if (options.defaults)
+                object.a = "";
+            if (message.a != null && message.hasOwnProperty("a"))
+                object.a = message.a;
+            return object;
+        };
+
+        /**
+         * Converts this Nested to JSON.
+         * @function toJSON
+         * @memberof TypeUrlTest.Nested
+         * @instance
+         * @returns {Object.<string,*>} JSON object
+         */
+        Nested.prototype.toJSON = function toJSON() {
+            return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+        };
+
+        /**
+         * Gets the default type url for Nested
+         * @function getTypeUrl
+         * @memberof TypeUrlTest.Nested
+         * @static
+         * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+         * @returns {string} The default type url
+         */
+        Nested.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+            if (typeUrlPrefix === undefined) {
+                typeUrlPrefix = "type.googleapis.com";
+            }
+            return typeUrlPrefix + "/TypeUrlTest.Nested";
+        };
+
+        return Nested;
+    })();
+
+    return TypeUrlTest;
+})();
+
+module.exports = $root;
diff --git a/tests/data/type_url.proto b/tests/data/type_url.proto
new file mode 100644
index 0000000..7255b69
--- /dev/null
+++ b/tests/data/type_url.proto
@@ -0,0 +1,8 @@
+syntax = "proto3";
+
+message TypeUrlTest {
+    message Nested {
+        string a = 1;
+    }
+    Nested nested = 1;
+}
diff --git a/tests/data/uncommon.proto b/tests/data/uncommon.proto
new file mode 100644
index 0000000..fa9fa03
--- /dev/null
+++ b/tests/data/uncommon.proto
@@ -0,0 +1,77 @@
+package uncommon;
+
+import public 'common.proto';
+
+syntax = 'proto3';
+
+option java_package = 'com.google.protobuf';
+
+message Test;
+
+message Test2 {
+    float hex = 0x1 [default=0x1];
+    float oct = 02 [default=02];
+    float zero = 3 [default=0];
+    float inf = 4 [default=inf];
+    float nan = 5 [default=nan];
+
+    /** pre */
+    repeated group lower = 6 {}; /// post
+
+    /** pre */
+    map<string,string> ambiguousComments = 7; /// post
+
+    string str = 8 {
+        option default = "a";
+    }
+
+    map<string,string> strmap = 9 {
+        option (custom) = "";
+    };
+
+    map<uint64,Test> longmap = 10;
+
+    int32 optionTest = 11 [(my_options) = { a: "foo" b {} }];
+
+    /** pre */
+    oneof kind;
+    oneof kind2; /// post
+
+    /** pre */
+    oneof kind3 {
+        option (custom) = ""; /// post
+    };
+
+    option (custom) = -42;
+
+    extend Test;
+    extend Test{};
+    extend Test{required int32 a=1;} // not validated by the parser
+};
+
+enum Test3;
+
+enum Test4{
+    option (custom).foo = "";
+    ONE = 1 [foo="bar"];
+    TWO = 2 [(my_options) = { a: "foo" b { c: "bar" } }];
+    THREE = 3 {
+        option (custom).bar = "";
+    };
+};
+
+enum Test4_1{
+    OPTION = 1;
+}
+
+service Test5;
+
+service Test6 { option (custom).bar = "";
+    message DoSomethingRequest;
+    message DoSomethingResponse;
+
+    rpc DoSomething(stream DoSomethingRequest) returns (stream DoSomethingResponse){ option (custom).foo2 = ""; };
+    /** pre */
+    rpc DoSomethingElse(   stream DoSomethingRequest  ) returns (DoSomethingResponse); /// post
+    rpc DoSomethingEntirelyDifferent(DoSomethingRequest  ) returns (   stream DoSomethingResponse ); /// post
+};
diff --git a/tests/data/weak-other.proto b/tests/data/weak-other.proto
new file mode 100644
index 0000000..1b404bb
--- /dev/null
+++ b/tests/data/weak-other.proto
@@ -0,0 +1 @@
+import weak "NOT_FOUND2";
diff --git a/tests/data/weak.proto b/tests/data/weak.proto
new file mode 100644
index 0000000..3829d9c
--- /dev/null
+++ b/tests/data/weak.proto
@@ -0,0 +1,3 @@
+import "google/protobuf/any.proto";
+import weak "NOT_FOUND";
+import "weak-other.proto";
diff --git a/tests/docs_comments.js b/tests/docs_comments.js
new file mode 100644
index 0000000..4f7702c
--- /dev/null
+++ b/tests/docs_comments.js
@@ -0,0 +1,53 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("proto comments", function(test) {
+    test.plan(11);
+    protobuf.load("tests/data/comments.proto", function(err, root) {
+        if (err)
+            throw test.fail(err.message);
+
+        test.equal(root.lookup("Test1").comment, "Message\nwith\na\ncomment.", "should parse /**-blocks");
+        test.equal(root.lookup("Test2").comment, null, "should not parse //-blocks");
+        test.equal(root.lookup("Test3").comment, null, "should not parse /*-blocks");
+
+        test.equal(root.lookup("Test1.field1").comment, "Field with a comment.", "should parse blocks for message fields");
+        test.equal(root.lookup("Test1.field2").comment, null, "should not parse lines for message fields");
+        test.equal(root.lookup("Test1.field3").comment, "Field with a comment and a <a href=\"http://example.com/foo/\">link</a>", "should parse triple-slash lines for message fields");
+
+        test.equal(root.lookup("Test3").comments.ONE, "Value with a comment.", "should parse blocks for enum values");
+        test.equal(root.lookup("Test3").comments.TWO, null, "should not parse lines for enum values");
+        test.equal(root.lookup("Test3").comments.THREE, "Preferred value with a comment.", "should parse lines for enum values and prefer on top over trailing");
+        test.equal(root.lookup("Test3").comments.FOUR, "Other value with a comment.", "should not confuse previous trailing comments with comments for the next field");
+        test.equal(root.lookup("Test3").comments.FIVE, "Leading comment for value with both types of comments after field with trailing comment.", "should not confuse previous field with trailing comment when leading comment is present");
+
+        test.end();
+    });
+});
+
+tape.test("proto comments with trailing comment preferred", function(test) {
+    test.plan(11);
+    var options = {preferTrailingComment: true};
+    var root = new protobuf.Root();
+    root.load("tests/data/comments.proto", options, function(err, root) {
+        if (err)
+            throw test.fail(err.message);
+
+        test.equal(root.lookup("Test1").comment, "Message\nwith\na\ncomment.", "should parse /**-blocks");
+        test.equal(root.lookup("Test2").comment, null, "should not parse //-blocks");
+        test.equal(root.lookup("Test3").comment, null, "should not parse /*-blocks");
+
+        test.equal(root.lookup("Test1.field1").comment, "Field with a comment.", "should parse blocks for message fields");
+        test.equal(root.lookup("Test1.field2").comment, null, "should not parse lines for message fields");
+        test.equal(root.lookup("Test1.field3").comment, "Field with a comment and a <a href=\"http://example.com/foo/\">link</a>", "should parse triple-slash lines for message fields");
+
+        test.equal(root.lookup("Test3").comments.ONE, "Value with a comment.", "should parse blocks for enum values");
+        test.equal(root.lookup("Test3").comments.TWO, null, "should not parse lines for enum values");
+        test.equal(root.lookup("Test3").comments.THREE, "Value with a comment.", "should prefer trailing comment when preferTrailingComment option enabled");
+        test.equal(root.lookup("Test3").comments.FOUR, "Other value with a comment.", "should not confuse previous trailing comments with comments for the next field");
+        test.equal(root.lookup("Test3").comments.FIVE, "Trailing comment for value with both types of comments after field with trailing comment.", "should not confuse previous field with trailing comment when leading comment is present");
+
+        test.end();
+    });
+});
diff --git a/tests/docs_comments_alternate_parse.js b/tests/docs_comments_alternate_parse.js
new file mode 100644
index 0000000..01c2a24
--- /dev/null
+++ b/tests/docs_comments_alternate_parse.js
@@ -0,0 +1,83 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("proto comments in alternate-parse mode", function(test) {
+    test.plan(24);
+    var options = {alternateCommentMode: true};
+    var root = new protobuf.Root();
+    root.load("tests/data/comments-alternate-parse.proto", options, function(err, root) {
+        if (err)
+            throw test.fail(err.message);
+
+        test.equal(root.lookup("Test1").comment, "Message with\na\nmulti-line comment.", "should parse double-slash multiline comment");
+        test.equal(root.lookup("Test2").comment, "Message\nwith\na multiline plain slash-star\ncomment.", "should parse slash-star multiline comment");
+        test.equal(root.lookup("Test3").comment, "Message\nwith\na\ncomment and stars.", "should parse doc-block multiline comment");
+
+        test.equal(root.lookup("Test1.field1").comment, "Field with a doc-block comment.", "should parse doc-block field comment");
+        test.equal(root.lookup("Test1.field2").comment, "Field with a single-line comment starting with two slashes.", "should parse double-slash field comment");
+        test.equal(root.lookup("Test1.field3").comment, "Field with a single-line comment starting with three slashes.", "should parse triple-slash field comment");
+        test.equal(root.lookup("Test1.field4").comment, "Field with a single-line slash-star comment.", "should parse single-line slash-star field comment");
+        test.equal(root.lookup("Test1.field5").comment, "Field with a trailing single-line two-slash comment.", "should parse trailing double-slash comment");
+        test.equal(root.lookup("Test1.field6").comment, "Field with a trailing single-line three-slash comment.", "should parse trailing triple-slash comment");
+        test.equal(root.lookup("Test1.field7").comment, "Field with a trailing single-line slash-star comment.", "should parse trailing slash-star comment");
+        test.equal(root.lookup("Test1.field8").comment, null, "should parse no comment");
+        test.equal(root.lookup("Test1.field9").comment, "Field with a\nmulti-line comment.", "should parse multiline double-slash field comment");
+        test.equal(root.lookup("Test1.field10").comment, "Field with a\nmulti-line doc-block comment.", "should parse multiline doc-block field comment");
+        test.equal(root.lookup("Test1.field11").comment, "Field with both block comment", "should parse both trailing comment and trailing comment");
+        test.equal(root.lookup("Test1.field12").comment, "Trailing comment in last line should not be recognized as leading comment for this field.", "trailing comment in last line should not be recognized as leading comment for this field");
+
+        test.equal(root.lookup("Test3").comments.ONE, "Value with a comment.", "should parse blocks for enum values");
+        test.equal(root.lookup("Test3").comments.TWO, "Value with a single-line comment.", "should parse double-slash comments for enum values");
+        test.equal(root.lookup("Test3").comments.THREE, "Value with a triple-slash comment.", "should parse lines for enum values and prefer on top over trailing");
+        test.equal(root.lookup("Test3").comments.FOUR, "Other value with a comment.", "should not confuse previous trailing comments with comments for the next field");
+        test.equal(root.lookup("Test3").comments.FIVE, "Leading comment for value with both types of comments after field with trailing comment.", "should not confuse previous field with trailing comment when leading comment is present");
+
+        test.equal(root.lookup("ServiceTest.SingleLineMethod").comment, 'My method does things');
+        test.equal(root.lookup("ServiceTest.TwoLineMethodWithComment").comment, 'TwoLineMethodWithComment documentation');
+        test.equal(root.lookup("ServiceTest.ThreeLine012345678901234567890123456712345671234567123456783927483923473892837489238749832432874983274983274983274").comment, 'Very very long method');
+        test.equal(root.lookup("ServiceTest.TwoLineMethodNoComment").comment, null);
+
+        test.end();
+    });
+});
+
+tape.test("proto comments in alternate-parse mode with trailing comment preferred", function(test) {
+    test.plan(24);
+    var options = {alternateCommentMode: true, preferTrailingComment: true};
+    var root = new protobuf.Root();
+    root.load("tests/data/comments-alternate-parse.proto", options, function(err, root) {
+        if (err)
+            throw test.fail(err.message);
+
+        test.equal(root.lookup("Test1").comment, "Message with\na\nmulti-line comment.", "should parse double-slash multiline comment");
+        test.equal(root.lookup("Test2").comment, "Message\nwith\na multiline plain slash-star\ncomment.", "should parse slash-star multiline comment");
+        test.equal(root.lookup("Test3").comment, "Message\nwith\na\ncomment and stars.", "should parse doc-block multiline comment");
+
+        test.equal(root.lookup("Test1.field1").comment, "Field with a doc-block comment.", "should parse doc-block field comment");
+        test.equal(root.lookup("Test1.field2").comment, "Field with a single-line comment starting with two slashes.", "should parse double-slash field comment");
+        test.equal(root.lookup("Test1.field3").comment, "Field with a single-line comment starting with three slashes.", "should parse triple-slash field comment");
+        test.equal(root.lookup("Test1.field4").comment, "Field with a single-line slash-star comment.", "should parse single-line slash-star field comment");
+        test.equal(root.lookup("Test1.field5").comment, "Field with a trailing single-line two-slash comment.", "should parse trailing double-slash comment");
+        test.equal(root.lookup("Test1.field6").comment, "Field with a trailing single-line three-slash comment.", "should parse trailing triple-slash comment");
+        test.equal(root.lookup("Test1.field7").comment, "Field with a trailing single-line slash-star comment.", "should parse trailing slash-star comment");
+        test.equal(root.lookup("Test1.field8").comment, null, "should parse no comment");
+        test.equal(root.lookup("Test1.field9").comment, "Field with a\nmulti-line comment.", "should parse multiline double-slash field comment");
+        test.equal(root.lookup("Test1.field10").comment, "Field with a\nmulti-line doc-block comment.", "should parse multiline doc-block field comment");
+        test.equal(root.lookup("Test1.field11").comment, "and trailing comment.", "should parse both trailing comment and trailing comment");
+        test.equal(root.lookup("Test1.field12").comment, "Trailing comment in last line should not be recognized as leading comment for this field.", "trailing comment in last line should not be recognized as leading comment for this field");
+
+        test.equal(root.lookup("Test3").comments.ONE, "Value with a comment.", "should parse blocks for enum values");
+        test.equal(root.lookup("Test3").comments.TWO, "Value with a single-line comment.", "should parse double-slash comments for enum values");
+        test.equal(root.lookup("Test3").comments.THREE, "ignored", "should prefer trailing comment when preferTrailingComment option enabled");
+        test.equal(root.lookup("Test3").comments.FOUR, "Other value with a comment.", "should not confuse previous trailing comments with comments for the next field");
+        test.equal(root.lookup("Test3").comments.FIVE, "Trailing comment for value with both types of comments after field with trailing comment.", "should not confuse previous field with trailing comment when leading comment is present");
+
+        test.equal(root.lookup("ServiceTest.SingleLineMethod").comment, 'My method does things');
+        test.equal(root.lookup("ServiceTest.TwoLineMethodWithComment").comment, 'TwoLineMethodWithComment documentation');
+        test.equal(root.lookup("ServiceTest.ThreeLine012345678901234567890123456712345671234567123456783927483923473892837489238749832432874983274983274983274").comment, 'Very very long method');
+        test.equal(root.lookup("ServiceTest.TwoLineMethodNoComment").comment, null);
+
+        test.end();
+    });
+});
diff --git a/tests/gen_type_url.js b/tests/gen_type_url.js
new file mode 100644
index 0000000..863bacf
--- /dev/null
+++ b/tests/gen_type_url.js
@@ -0,0 +1,11 @@
+var tape = require("tape");
+
+var TypeUrlTest = require("./data/type_url").TypeUrlTest;
+
+tape.test("getTypeUrl method", function(test) {
+    test.equal(TypeUrlTest.getTypeUrl(), "type.googleapis.com/TypeUrlTest", "should have a valid type url");
+    test.equal(TypeUrlTest.Nested.getTypeUrl(), "type.googleapis.com/TypeUrlTest.Nested", "nested messages should have a valid type url");
+    test.equal(TypeUrlTest.getTypeUrl("example.com"), "example.com/TypeUrlTest", "should have a valid type url override");
+    test.equal(TypeUrlTest.Nested.getTypeUrl("example.com"), "example.com/TypeUrlTest.Nested", "nested messages should have a valid type url override");
+    test.end();
+});
diff --git a/tests/lib_aspromise.js b/tests/lib_aspromise.js
new file mode 100644
index 0000000..249e7b4
--- /dev/null
+++ b/tests/lib_aspromise.js
@@ -0,0 +1,2 @@
+if (typeof Promise !== "undefined")
+    require("../lib/aspromise/tests");
diff --git a/tests/lib_base64.js b/tests/lib_base64.js
new file mode 100644
index 0000000..7760c52
--- /dev/null
+++ b/tests/lib_base64.js
@@ -0,0 +1 @@
+require("../lib/base64/tests");
diff --git a/tests/lib_codegen.js b/tests/lib_codegen.js
new file mode 100644
index 0000000..dae088d
--- /dev/null
+++ b/tests/lib_codegen.js
@@ -0,0 +1,8 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+tape.test("codegen", function(test) {
+    test.equal(protobuf.util.codegen.verbose, false, "should not be verbose by default");
+    test.end();
+});
diff --git a/tests/lib_eventemitter.js b/tests/lib_eventemitter.js
new file mode 100644
index 0000000..bbd0cca
--- /dev/null
+++ b/tests/lib_eventemitter.js
@@ -0,0 +1 @@
+require("../lib/eventemitter/tests");
diff --git a/tests/lib_inquire.js b/tests/lib_inquire.js
new file mode 100644
index 0000000..75e2ccf
--- /dev/null
+++ b/tests/lib_inquire.js
@@ -0,0 +1,4 @@
+var protobuf = require("..");
+
+if (protobuf.util.isNode)
+    require("../lib/inquire/tests");
diff --git a/tests/lib_path.js b/tests/lib_path.js
new file mode 100644
index 0000000..ff7c112
--- /dev/null
+++ b/tests/lib_path.js
@@ -0,0 +1 @@
+require("../lib/path/tests");
diff --git a/tests/lib_pool.js b/tests/lib_pool.js
new file mode 100644
index 0000000..dc8ac69
--- /dev/null
+++ b/tests/lib_pool.js
@@ -0,0 +1,2 @@
+if (typeof Uint8Array !== "undefined")
+    require("../lib/pool/tests");
diff --git a/tests/node/api_load-sync.js b/tests/node/api_load-sync.js
new file mode 100644
index 0000000..0bc9405
--- /dev/null
+++ b/tests/node/api_load-sync.js
@@ -0,0 +1,48 @@
+var tape = require("tape");
+
+var protobuf = require("../..");
+
+tape.test("load sync", function(test) {
+    var root = protobuf.loadSync("tests/data/common.proto");
+
+    test.ok(root.lookup("Something"), "should parse message Something");
+
+    test.throws(function() {
+        protobuf.loadSync("tests/data/__NOTFOUND__", root);
+    }, Error, "should throw if not found");
+
+    var isNode = protobuf.util.isNode;
+    try {
+        protobuf.util.isNode = false;
+        test.throws(function() {
+            protobuf.loadSync("tests/data/common.proto");
+        }, "should throw when not running under node");
+    } finally {
+        protobuf.util.isNode = isNode;
+    }
+
+    test.throws(function() {
+        protobuf.loadSync("tests/data/invalid.proto");
+    }, Error, "should throw when trying to load an invalid proto");
+
+    test.throws(function() {
+        protobuf.loadSync("tests/data/invalid.json");
+    }, Error, "should throw when trying to load invalid json");
+
+    root = protobuf.loadSync("tests/data/weak.proto");
+    test.ok(root.files.indexOf("tests/data/NOT_FOUND") > -1, "should ignore missing weak protos and remember them");
+    test.ok(root.files.indexOf("google/protobuf/any.proto") > -1, "should still load other protos when ignoring weak protos");
+
+    test.end();
+});
+
+tape.test("should load bundled definitions even if resolvePath method was overrided", function(test) {
+    var protoFilePath = "tests/data/common.proto";
+    var root = new protobuf.Root();
+    root.resolvePath = (origin, target) => origin === "" && target === protoFilePath ? target : null;
+
+    root.loadSync(protoFilePath);
+
+    test.ok(root.lookup("Something"), "should parse message Something");
+    test.end();
+});
diff --git a/tests/node/comp_loaders.js b/tests/node/comp_loaders.js
new file mode 100644
index 0000000..16e9884
--- /dev/null
+++ b/tests/node/comp_loaders.js
@@ -0,0 +1,88 @@
+var fs   = require("fs"),
+    path = require("path"),
+    vm   = require("vm"),
+    long = require("long"),
+    tape = require("tape");
+
+var distPath = path.join(__dirname, "..", "..", "dist");
+
+[
+    {
+        name: "full",
+        data: fs.readFileSync(path.join(distPath, "protobuf.min.js")).toString("utf8")
+    },
+    {
+        name: "light",
+        data: fs.readFileSync(path.join(distPath, "light/protobuf.min.js")).toString("utf8")
+    },
+    {
+        name: "minimal",
+        data: fs.readFileSync(path.join(distPath, "minimal/protobuf.min.js")).toString("utf8")
+    }
+]
+.forEach(function(dist) {
+
+    tape.test(dist.name + " build", function(test) {
+
+        test.test(test.name + " - script tags", function(test) {
+            var sandbox;
+
+            var dcodeIO = { Long: long };
+
+            vm.runInNewContext(dist.data, sandbox = {
+                window: {
+                    dcodeIO: dcodeIO
+                },
+                dcodeIO: dcodeIO
+            });
+
+            test.ok(sandbox.window.protobuf, "should load the library as a global");
+            test.ok(sandbox.window.protobuf.util.Long, "should load long.js to util");
+            test.end();
+        });
+
+        test.test(test.name + " - webworkers", function(test) {
+            var sandbox;
+
+            var dcodeIO = { Long: long };
+
+            vm.runInNewContext(dist.data, sandbox = {
+                self: {
+                    dcodeIO: dcodeIO
+                },
+                dcodeIO: dcodeIO
+            });
+
+            test.ok(sandbox.self.protobuf, "should load the library as a global");
+            test.ok(sandbox.self.protobuf.util.Long, "should load long.js to util");
+            test.end();
+        });
+
+        test.test(test.name + " - amd loaders", function(test) {
+            var sandbox;
+
+            function fakeDefine(deps, factory) {
+                test.same(deps, [ "long" ], "should request long.js as a dependency");
+                test.notOk(sandbox.window.protobuf.util.Long, "should not have loaded long.js before calling the factory function");
+                factory(long);
+                test.ok(sandbox.window.protobuf.util.Long, "should have loaded long.js after calling the factory function");
+            }
+            fakeDefine.amd = true;
+
+            vm.runInNewContext(dist.data, sandbox = {
+                define: fakeDefine,
+                window: {},
+                require: undefined,
+                console: console
+            });
+
+            test.ok(sandbox.window.protobuf, "should load the library as a global");
+            test.end();
+
+        });
+
+    });
+
+});
+
+// commonjs uses ./src
diff --git a/tests/node/lib_fetch.js b/tests/node/lib_fetch.js
new file mode 100644
index 0000000..03231be
--- /dev/null
+++ b/tests/node/lib_fetch.js
@@ -0,0 +1 @@
+require("../../lib/fetch/tests"); // requires fs
diff --git a/tests/node/lib_float.js b/tests/node/lib_float.js
new file mode 100644
index 0000000..038f0c6
--- /dev/null
+++ b/tests/node/lib_float.js
@@ -0,0 +1 @@
+require("../../lib/float/tests"); // requires node for modified global envs
diff --git a/tests/node/lib_utf8.js b/tests/node/lib_utf8.js
new file mode 100644
index 0000000..0a721d1
--- /dev/null
+++ b/tests/node/lib_utf8.js
@@ -0,0 +1 @@
+require("../../lib/utf8/tests"); // requires fs to load the test file
diff --git a/tests/other_basics-debug.js b/tests/other_basics-debug.js
new file mode 100644
index 0000000..6863263
--- /dev/null
+++ b/tests/other_basics-debug.js
@@ -0,0 +1,108 @@
+/* var tape = require("tape");
+
+var protobuf = require("../debug");
+
+tape.test("google.protobuf.Any type", function(test) {
+    protobuf.debug.enable();
+    protobuf.load("tests/data/common.proto", function(err, root) {
+        if (err)
+            return test.fail(err.message);
+
+        var google_protobuf = root.resolveAll().lookup("google.protobuf");
+        test.ok(google_protobuf.Any, "should expose Any as a property on the reflected google.protobuf namespace");
+
+        var Any = root.lookup("google.protobuf.Any");
+
+        test.ok(Any instanceof protobuf.Type, "should extend Type");
+
+        var valueBuffer = protobuf.util.newBuffer(1);
+        valueBuffer[0] = 0;
+        var any = Any.create({
+            type_url: "some.type",
+            value: valueBuffer
+        });
+
+        test.test(test.name + " - instances", function(test) {
+
+            test.ok(any instanceof protobuf.Message, "should extend Message");
+            test.deepEqual(any, {
+                type_url: "some.type",
+                value: valueBuffer
+            }, "should be populated with the contents we provided");
+
+            var writer = Any.encode(any),
+                buf;
+
+            function verifyEncode(test, buf) {
+                test.equal(buf[0]    , 1 << 3 | 2, "a tag with id 1, wire type 2");
+                test.equal(buf[1]    , 9         , "a field length of 9");
+                test.equal(buf[11]   , 2 << 3 | 2, "a tag with id 2, wire type 2");
+                test.equal(buf[12]   , 1         , "a field length of 1");
+                test.equal(buf.length, 14        , "14 bytes in total");
+            }
+
+            test.test(test.name + " - should encode", function(test) {
+                
+                writer = Any.encode(any);
+                buf = writer.finish();
+
+                verifyEncode(test, buf);
+
+                test.end();
+            });
+
+            test.test(test.name + " - should decode", function(test) {
+
+                var msg = Any.decode(buf);
+
+                test.deepEqual(msg, any, "an equal message");
+
+                test.end();
+            });
+
+            test.test(test.name + " - should encodeDelimited", function(test) {
+
+                writer = Any.encodeDelimited(any);
+                buf = writer.finish();
+                
+                test.equal(buf[0]    , 14        , "a length of 14");
+                test.equal(buf[1]    , 1 << 3 | 2, "a tag with id 1, wire type 2");
+                test.equal(buf[2]    , 9         , "a field length of 9");
+                test.equal(buf[12]   , 2 << 3 | 2, "a tag with id 2, wire type 2");
+                test.equal(buf[13]   , 1         , "a field length of 1");
+                test.equal(buf.length, 15        , "15 bytes in total");
+
+                test.end();
+            });
+
+            test.test(test.name + " - should decodeDelimited", function(test) {
+
+                var msg = Any.decodeDelimited(buf);
+                test.deepEqual(msg, any, "an equal message");
+
+                test.end();
+            });
+
+            test.test(test.name + " - debug", function(test) {
+                var unused = protobuf.debug.unusedTypes(root).map(function(type) { return type.fullName; });
+                test.same(unused, [
+                    ".Something",
+                    ".google.protobuf.Duration",
+                    ".google.protobuf.Empty",
+                    ".google.protobuf.Struct",
+                    ".google.protobuf.Value",
+                    ".google.protobuf.ListValue",
+                    ".google.protobuf.Timestamp"
+                ], "should recognize unused types (all but .google.protobuf.Any)");
+                
+                protobuf.debug.disable();
+                test.end();
+            });
+
+            test.end();
+        });
+
+        test.end();
+
+    });
+}); */
\ No newline at end of file
diff --git a/tests/other_bench.js b/tests/other_bench.js
new file mode 100644
index 0000000..37314ea
--- /dev/null
+++ b/tests/other_bench.js
@@ -0,0 +1,26 @@
+var tape = require("tape");
+
+var protobuf = require(".."),
+    util = protobuf.util;
+
+tape.test("bench.proto and bench.json", function(test) {
+    test.plan(4);
+    protobuf.load("bench/data/bench.proto", undefined, function(err, root) { // no require.resolve to support browsers
+        if (err)
+            return test.fail(err.message);
+
+        var Test = root.lookup("Test");
+
+        var data = require("../bench/data/bench.json");
+
+        test.equal(Test.verify(data), null, "should verify our test data");
+        test.equal(Test.ctor.verify(data), null, "should verify our test data (static)");
+
+        var decoded = Test.decode(Test.encode(data).finish());
+        test.deepEqual(decoded, data, "should reproduce the original data when encoded and decoded again");
+
+        test.deepEqual(Test.toObject(decoded), data, "should convert back to the original object");
+
+        test.end();
+    });
+});
\ No newline at end of file
diff --git a/tests/other_classes.js b/tests/other_classes.js
new file mode 100644
index 0000000..efc2758
--- /dev/null
+++ b/tests/other_classes.js
@@ -0,0 +1,85 @@
+var tape = require("tape");
+
+var protobuf = require(".."),
+    Message  = protobuf.Message;
+
+tape.test("google.protobuf.Any class", function(test) {
+
+    test.plan(1);
+
+    protobuf.load("tests/data/common.proto", function(err, root) {
+        if (err)
+            return test.fail(err.message);
+
+        function Any(properties) {
+            Message.call(this, properties);
+        }
+        root.lookup("google.protobuf.Any").ctor = Any;
+
+        var valueBuffer = protobuf.util.newBuffer(1);
+        valueBuffer[0] = 0;
+        var any = new Any({
+            type_url: "some.type",
+            value: valueBuffer
+        });
+
+        test.test(test.name + " - instances", function(test) {
+
+            test.ok(any instanceof protobuf.Message, "should extend Message");
+            test.ok(any instanceof Any, "should extend the custom class");
+            test.deepEqual(any, {
+                type_url: "some.type",
+                value: valueBuffer
+            }, "should be populated with the contents we provided");
+
+            var buf;
+
+            test.test(test.name + " - should encode", function(test) {
+
+                buf = Any.encode(any).finish();
+
+                test.equal(buf[0]    , 1 << 3 | 2, "a tag with id 1, wire type 2");
+                test.equal(buf[1]    , 9         , "a field length of 9");
+                test.equal(buf[11]   , 2 << 3 | 2, "a tag with id 2, wire type 2");
+                test.equal(buf[12]   , 1         , "a field length of 1");
+                test.equal(buf.length, 14        , "14 bytes in total");
+
+                test.end();
+            });
+
+            test.test(test.name + " - should decode", function(test) {
+
+                msg = Any.decode(buf);
+                test.ok(msg instanceof Any, "to an object that extends the custom class");
+                test.deepEqual(msg, any, "an equal message");
+
+                test.end();
+            });
+
+            test.test(test.name + " - should encodeDelimited", function(test) {
+
+                buf = Any.encodeDelimited(any).finish();
+
+                test.equal(buf[0]    , 14        , "a length of 14");
+                test.equal(buf[1]    , 1 << 3 | 2, "a tag with id 1, wire type 2");
+                test.equal(buf[2]    , 9         , "a field length of 9");
+                test.equal(buf[12]   , 2 << 3 | 2, "a tag with id 2, wire type 2");
+                test.equal(buf[13]   , 1         , "a field length of 1");
+                test.equal(buf.length, 15        , "15 bytes in total");
+
+                test.end();
+            });
+
+            test.test(test.name + " - should decodeDelimited", function(test) {
+
+                msg = Any.decodeDelimited(buf);
+                test.ok(msg instanceof Any, "to an object that extends the custom class");
+                test.deepEqual(msg, any, "an equal message");
+
+                test.end();
+            });
+
+            test.end();
+        });
+    });
+});
diff --git a/tests/other_node-or-browser.js b/tests/other_node-or-browser.js
new file mode 100644
index 0000000..2039807
--- /dev/null
+++ b/tests/other_node-or-browser.js
@@ -0,0 +1,18 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var util = protobuf.util;
+
+if (util.isNode)
+    tape.test("under node.js", function(test) {
+        test.ok(util.fs && util.fs.readFile, "the fs module should be available");
+        test.ok(util.Long && util.Long.isLong, "the long module should be available");
+        test.end();
+    });
+else
+    tape.test("in the browser", function(test) {
+        test.ok(util.fs === null, "the fs module should not be available");
+        test.ok(util.Long && util.Long.isLong, "the long module should be available to test cases");
+        test.end();
+    });
diff --git a/tests/other_protocolerror.js b/tests/other_protocolerror.js
new file mode 100644
index 0000000..7723798
--- /dev/null
+++ b/tests/other_protocolerror.js
@@ -0,0 +1,41 @@
+var tape = require("tape");
+
+var protobuf = require("..");
+
+var ProtocolError = protobuf.util.ProtocolError;
+
+tape.test("a protocol error", function(test) {
+
+    test.ok(ProtocolError("test1") instanceof ProtocolError, "should construct by calling the constructor as a function");
+    test.ok(new ProtocolError("test2") instanceof ProtocolError, "should construct by using the 'new' keyword");
+
+    var root = new protobuf.Root().add(
+        new protobuf.Type("Test").add(
+            new protobuf.Field("foo", 1, "uint32", "optional")
+        ).add(
+            new protobuf.Field("bar", 2, "string", "required")
+        )
+    );
+    
+    var Test = root.lookup("Test");
+    var buf  = protobuf.util.newBuffer(2);
+    buf[0] = 1 << 3 | 0;
+    buf[1] = 0x02;
+
+    try {
+        Test.decode(buf);
+        test.fail("should be thrown if a message is missing required fields");
+    } catch (e) {
+        test.ok(e instanceof ProtocolError, "should be thrown if a message is missing required fields");
+        test.ok(e.message, "should have an error message");
+        test.ok(typeof e.stack === "string", "should have a stack trace (empty string if not supported)");
+        test.equal(e.name, "ProtocolError", "should have the correct name");
+        test.ok(/^ProtocolError: /.test(e.toString()), "should correctly convert toString");
+        test.same(e.instance, {
+            foo: 2
+        }, "should still return the so far decoded message");
+    }
+
+    test.end();
+
+});
diff --git a/tests/split/root.js b/tests/split/root.js
new file mode 100644
index 0000000..75b480c
--- /dev/null
+++ b/tests/split/root.js
@@ -0,0 +1,43 @@
+/*eslint-disable block-scoped-var, no-redeclare, no-control-regex, no-prototype-builtins*/
+"use strict";
+
+var $protobuf = require("protobufjs");
+
+var $root = ($protobuf.roots.split || ($protobuf.roots.split = new $protobuf.Root()))
+.setOptions({
+  "(foo)": "bar"
+})
+.addJSON({
+  com: {
+    nested: {
+      Outer: {
+        fields: {
+          inner: {
+            type: "Inner",
+            id: 1
+          },
+          other: {
+            type: "Other",
+            id: 2
+          }
+        },
+        nested: {
+          Inner: {
+            fields: {}
+          }
+        }
+      },
+      Other: {
+        fields: {
+          "var": {
+            rule: "required",
+            type: "uint32",
+            id: 1
+          }
+        }
+      }
+    }
+  }
+});
+
+module.exports = $root;
diff --git a/tests/split/test.proto b/tests/split/test.proto
new file mode 100644
index 0000000..2b08a4f
--- /dev/null
+++ b/tests/split/test.proto
@@ -0,0 +1,15 @@
+option (foo) = "bar";
+
+package com;
+
+message Outer {
+    optional Inner inner = 1;
+    optional Other other = 2;
+
+    message Inner {
+    }
+}
+
+message Other {
+    required uint32 var = 1;
+}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..a0b3639
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,8 @@
+{
+    "compilerOptions": {
+        "target": "ES5",
+        "experimentalDecorators": true,
+        "emitDecoratorMetadata": true,
+        "esModuleInterop": true,
+    }
+}
\ No newline at end of file