Forráskód Böngészése

Merge pull request #1133 from DioxusLabs/jk/add-cli-to-mainline

Add CLI back into Dioxus Mainline
Jon Kelley 2 éve
szülő
commit
065cea8a6d
83 módosított fájl, 16304 hozzáadás és 0 törlés
  1. 31 0
      packages/cli/.github/workflows/build.yml
  2. 34 0
      packages/cli/.github/workflows/docs.yml
  3. 68 0
      packages/cli/.github/workflows/main.yml
  4. 4 0
      packages/cli/.gitignore
  5. 6 0
      packages/cli/.vscode/settings.json
  6. 4778 0
      packages/cli/Cargo.lock
  7. 92 0
      packages/cli/Cargo.toml
  8. 45 0
      packages/cli/Dioxus.toml
  9. 43 0
      packages/cli/README.md
  10. 50 0
      packages/cli/build.rs
  11. 1 0
      packages/cli/docs/.gitignore
  12. 6 0
      packages/cli/docs/book.toml
  13. 18 0
      packages/cli/docs/src/SUMMARY.md
  14. 26 0
      packages/cli/docs/src/cmd/README.md
  15. 47 0
      packages/cli/docs/src/cmd/build.md
  16. 18 0
      packages/cli/docs/src/cmd/clean.md
  17. 61 0
      packages/cli/docs/src/cmd/serve.md
  18. 68 0
      packages/cli/docs/src/cmd/translate.md
  19. 208 0
      packages/cli/docs/src/configure.md
  20. 39 0
      packages/cli/docs/src/creating.md
  21. 22 0
      packages/cli/docs/src/installation.md
  22. 21 0
      packages/cli/docs/src/introduction.md
  23. 79 0
      packages/cli/docs/src/plugin/README.md
  24. 21 0
      packages/cli/docs/src/plugin/interface/command.md
  25. 35 0
      packages/cli/docs/src/plugin/interface/dirs.md
  26. 48 0
      packages/cli/docs/src/plugin/interface/log.md
  27. 34 0
      packages/cli/docs/src/plugin/interface/network.md
  28. 11 0
      packages/cli/docs/src/plugin/interface/os.md
  29. 35 0
      packages/cli/docs/src/plugin/interface/path.md
  30. 0 0
      packages/cli/examples/README.md
  31. 18 0
      packages/cli/examples/plugin/init.lua
  32. 25 0
      packages/cli/examples/plugin/interface.lua
  33. 20 0
      packages/cli/extension/.eslintrc.js
  34. 13 0
      packages/cli/extension/.gitignore
  35. 10 0
      packages/cli/extension/DEV.md
  36. 21 0
      packages/cli/extension/LICENSE.txt
  37. 14 0
      packages/cli/extension/README.md
  38. 2 0
      packages/cli/extension/dist/.gitignore
  39. 5079 0
      packages/cli/extension/package-lock.json
  40. 102 0
      packages/cli/extension/package.json
  41. 3 0
      packages/cli/extension/server/.gitignore
  42. 282 0
      packages/cli/extension/src/main.ts
  43. BIN
      packages/cli/extension/static/icon.png
  44. 12 0
      packages/cli/extension/tsconfig.json
  45. 8 0
      packages/cli/rustfmt.toml
  46. 25 0
      packages/cli/src/assets/autoreload.js
  47. 47 0
      packages/cli/src/assets/dioxus.toml
  48. 22 0
      packages/cli/src/assets/index.html
  49. 725 0
      packages/cli/src/builder.rs
  50. 94 0
      packages/cli/src/cargo.rs
  51. 184 0
      packages/cli/src/cli/autoformat/mod.rs
  52. 76 0
      packages/cli/src/cli/build/mod.rs
  53. 96 0
      packages/cli/src/cli/cfg.rs
  54. 33 0
      packages/cli/src/cli/clean/mod.rs
  55. 63 0
      packages/cli/src/cli/config/mod.rs
  56. 76 0
      packages/cli/src/cli/create/mod.rs
  57. 89 0
      packages/cli/src/cli/mod.rs
  58. 37 0
      packages/cli/src/cli/plugin/mod.rs
  59. 100 0
      packages/cli/src/cli/serve/mod.rs
  60. 64 0
      packages/cli/src/cli/tool/mod.rs
  61. 138 0
      packages/cli/src/cli/translate/mod.rs
  62. 76 0
      packages/cli/src/cli/version.rs
  63. 264 0
      packages/cli/src/config.rs
  64. 80 0
      packages/cli/src/error.rs
  65. 24 0
      packages/cli/src/lib.rs
  66. 35 0
      packages/cli/src/logging.rs
  67. 65 0
      packages/cli/src/main.rs
  68. 64 0
      packages/cli/src/plugin/interface/command.rs
  69. 13 0
      packages/cli/src/plugin/interface/dirs.rs
  70. 85 0
      packages/cli/src/plugin/interface/fs.rs
  71. 28 0
      packages/cli/src/plugin/interface/log.rs
  72. 233 0
      packages/cli/src/plugin/interface/mod.rs
  73. 27 0
      packages/cli/src/plugin/interface/network.rs
  74. 18 0
      packages/cli/src/plugin/interface/os.rs
  75. 40 0
      packages/cli/src/plugin/interface/path.rs
  76. 333 0
      packages/cli/src/plugin/mod.rs
  77. 138 0
      packages/cli/src/plugin/types.rs
  78. 752 0
      packages/cli/src/server/mod.rs
  79. 171 0
      packages/cli/src/server/proxy.rs
  80. 349 0
      packages/cli/src/tools.rs
  81. 4 0
      packages/cli/tests/main.rs
  82. 30 0
      packages/cli/tests/svg.html
  83. 48 0
      packages/cli/tests/test.html

+ 31 - 0
packages/cli/.github/workflows/build.yml

@@ -0,0 +1,31 @@
+# .github/workflows/build.yml
+
+on:
+  release:
+    types: [created]
+
+jobs:
+  release:
+    name: release ${{ matrix.target }}
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - target: x86_64-unknown-linux-gnu
+            archive: tar.gz tar.xz
+          - target: x86_64-unknown-linux-musl
+            archive: tar.gz tar.xz
+          - target: x86_64-apple-darwin
+            archive: tar.gz tar.xz
+          - target: x86_64-pc-windows-gnu
+            archive: zip
+
+    steps:
+      - uses: actions/checkout@master
+      - name: Compile and release
+        uses: rust-build/rust-build.action@latest
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          RUSTTARGET: ${{ matrix.target }}
+          ARCHIVE_TYPES: ${{ matrix.archive }}

+ 34 - 0
packages/cli/.github/workflows/docs.yml

@@ -0,0 +1,34 @@
+name: github pages
+
+on:
+  push:
+    paths:
+      - docs/**
+    branches:
+      - master
+
+jobs:
+  deploy:
+    runs-on: ubuntu-20.04
+    concurrency:
+      group: ${{ github.workflow }}-${{ github.ref }}
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Setup mdBook
+        uses: peaceiris/actions-mdbook@v1
+        with:
+          mdbook-version: '0.4.10'
+          # mdbook-version: 'latest'
+
+      - run: cd docs && mdbook build
+
+      - name: Deploy 🚀
+        uses: JamesIves/github-pages-deploy-action@v4.2.3
+        with:
+          branch: gh-pages # The branch the action should deploy to.
+          folder: docs/book # The folder the action should deploy.
+          target-folder: docs/nightly/cli
+          repository-name: dioxuslabs/docsite
+          clean: false
+          token: ${{ secrets.DEPLOY_KEY }} # let's pretend I don't need it for now

+ 68 - 0
packages/cli/.github/workflows/main.yml

@@ -0,0 +1,68 @@
+on: [push, pull_request]
+
+name: Rust CI
+
+jobs:
+  check:
+    name: Check
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: stable
+          override: true
+      - uses: Swatinem/rust-cache@v1
+      - uses: actions-rs/cargo@v1
+        with:
+          command: check
+
+  test:
+    name: Test Suite
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: stable
+          override: true
+      - uses: Swatinem/rust-cache@v1
+      - uses: actions-rs/cargo@v1
+        with:
+          command: test
+
+  fmt:
+    name: Rustfmt
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: stable
+          override: true
+      - uses: Swatinem/rust-cache@v1
+      - run: rustup component add rustfmt
+      - uses: actions-rs/cargo@v1
+        with:
+          command: fmt
+          args: --all -- --check
+
+  # clippy:
+  #  name: Clippy
+  #  runs-on: ubuntu-latest
+  #  steps:
+  #    - uses: actions/checkout@v2
+  #    - uses: actions-rs/toolchain@v1
+  #      with:
+  #        profile: minimal
+  #        toolchain: stable
+  #        override: true
+  #    - uses: Swatinem/rust-cache@v1
+  #    - run: rustup component add clippy
+  #    - uses: actions-rs/cargo@v1
+  #      with:
+  #        command: clippy
+  #        args: -- -D warnings

+ 4 - 0
packages/cli/.gitignore

@@ -0,0 +1,4 @@
+/target
+Cargo.lock
+.DS_Store
+.idea/

+ 6 - 0
packages/cli/.vscode/settings.json

@@ -0,0 +1,6 @@
+{
+    "Lua.diagnostics.globals": [
+        "plugin_logger",
+        "PLUGIN_DOWNLOADER"
+    ]
+}

+ 4778 - 0
packages/cli/Cargo.lock

@@ -0,0 +1,4778 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "addr2line"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "aes"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+]
+
+[[package]]
+name = "ahash"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
+dependencies = [
+ "getrandom 0.2.10",
+ "once_cell",
+ "version_check",
+]
+
+[[package]]
+name = "ahash"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
+dependencies = [
+ "cfg-if",
+ "const-random",
+ "getrandom 0.2.10",
+ "once_cell",
+ "version_check",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "aligned"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80a21b9440a626c7fc8573a9e3d3a06b75c7c97754c2949bc7857b90353ca655"
+dependencies = [
+ "as-slice",
+]
+
+[[package]]
+name = "alloc-no-stdlib"
+version = "2.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
+
+[[package]]
+name = "alloc-stdlib"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
+dependencies = [
+ "alloc-no-stdlib",
+]
+
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anstream"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is-terminal",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
+dependencies = [
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
+
+[[package]]
+name = "anymap2"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c"
+
+[[package]]
+name = "arrayref"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
+
+[[package]]
+name = "arrayvec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
+
+[[package]]
+name = "as-slice"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516"
+dependencies = [
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "async-compression"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a"
+dependencies = [
+ "brotli",
+ "flate2",
+ "futures-core",
+ "memchr",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "async-trait"
+version = "0.1.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi 0.1.19",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "axum"
+version = "0.5.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acee9fd5073ab6b045a275b3e709c163dd36c90685219cb21804a147b58dba43"
+dependencies = [
+ "async-trait",
+ "axum-core",
+ "base64 0.13.1",
+ "bitflags",
+ "bytes",
+ "futures-util",
+ "headers",
+ "http",
+ "http-body",
+ "hyper",
+ "itoa",
+ "matchit",
+ "memchr",
+ "mime",
+ "percent-encoding",
+ "pin-project-lite",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sha-1",
+ "sync_wrapper",
+ "tokio",
+ "tokio-tungstenite",
+ "tower",
+ "tower-http 0.3.5",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "axum-core"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37e5939e02c56fecd5c017c37df4238c0a839fa76b7f97acdd7efb804fd181cc"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "mime",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "backtrace"
+version = "0.3.67"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide 0.6.2",
+ "object",
+ "rustc-demangle",
+]
+
+[[package]]
+name = "base64"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
+dependencies = [
+ "byteorder",
+ "safemem",
+]
+
+[[package]]
+name = "base64"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
+
+[[package]]
+name = "base64"
+version = "0.21.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
+
+[[package]]
+name = "base64ct"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
+
+[[package]]
+name = "binary-install"
+version = "0.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5bc5f8c50dd6a80d0b303ddab79f42ddcb52fd43d68107ecf622c551fd4cd4"
+dependencies = [
+ "curl",
+ "dirs 1.0.5",
+ "failure",
+ "flate2",
+ "hex 0.3.2",
+ "is_executable",
+ "siphasher",
+ "tar",
+ "zip 0.5.13",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "blake2b_simd"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "constant_time_eq",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "brotli"
+version = "3.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68"
+dependencies = [
+ "alloc-no-stdlib",
+ "alloc-stdlib",
+ "brotli-decompressor",
+]
+
+[[package]]
+name = "brotli-decompressor"
+version = "2.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744"
+dependencies = [
+ "alloc-no-stdlib",
+ "alloc-stdlib",
+]
+
+[[package]]
+name = "bstr"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "bstr"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5"
+dependencies = [
+ "memchr",
+ "once_cell",
+ "regex-automata",
+ "serde",
+]
+
+[[package]]
+name = "btoi"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dd6407f73a9b8b6162d8a2ef999fe6afd7cc15902ebf42c5cd296addf17e0ad"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
+
+[[package]]
+name = "bumpslab"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e5816c875b50b9866d759fa24d46159dccab0d7942c0ccbfd700b4f45dd961e"
+dependencies = [
+ "bumpalo",
+]
+
+[[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
+[[package]]
+name = "bytes"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
+
+[[package]]
+name = "bzip2"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
+dependencies = [
+ "bzip2-sys",
+ "libc",
+]
+
+[[package]]
+name = "bzip2-sys"
+version = "0.1.11+1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "camino"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "cargo-generate"
+version = "0.18.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7b2f627381dc7523340c606559dddf6083cb2e6134368381da5778638f906d8"
+dependencies = [
+ "anyhow",
+ "clap",
+ "console",
+ "dialoguer",
+ "env_logger",
+ "git2",
+ "gix-config",
+ "heck 0.4.1",
+ "home",
+ "ignore",
+ "indicatif",
+ "liquid",
+ "liquid-core",
+ "liquid-derive",
+ "liquid-lib",
+ "log",
+ "names",
+ "paste",
+ "path-absolutize",
+ "regex",
+ "remove_dir_all",
+ "rhai",
+ "sanitize-filename",
+ "semver",
+ "serde",
+ "tempfile",
+ "thiserror",
+ "toml 0.7.5",
+ "walkdir",
+]
+
+[[package]]
+name = "cargo-platform"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "cargo_metadata"
+version = "0.15.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a"
+dependencies = [
+ "camino",
+ "cargo-platform",
+ "semver",
+ "serde",
+ "serde_json",
+ "thiserror",
+]
+
+[[package]]
+name = "cargo_toml"
+version = "0.11.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e72c3ff59e3b7d24630206bb63a73af65da4ed5df1f76ee84dfafb9fee2ba60e"
+dependencies = [
+ "serde",
+ "serde_derive",
+ "toml 0.5.11",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
+dependencies = [
+ "jobserver",
+]
+
+[[package]]
+name = "cfg-expr"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bbc13bf6290a6b202cc3efb36f7ec2b739a80634215630c8053a313edf6abef"
+dependencies = [
+ "smallvec",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "js-sys",
+ "num-traits",
+ "time 0.1.45",
+ "wasm-bindgen",
+ "winapi",
+]
+
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+]
+
+[[package]]
+name = "clap"
+version = "4.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34d21f9bf1b425d2968943631ec91202fe5e837264063503708b83013f8fc938"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+ "once_cell",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "bitflags",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
+
+[[package]]
+name = "colored"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59"
+dependencies = [
+ "atty",
+ "lazy_static",
+ "winapi",
+]
+
+[[package]]
+name = "colored"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
+dependencies = [
+ "atty",
+ "lazy_static",
+ "winapi",
+]
+
+[[package]]
+name = "console"
+version = "0.15.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
+dependencies = [
+ "encode_unicode",
+ "lazy_static",
+ "libc",
+ "unicode-width",
+ "windows-sys 0.45.0",
+]
+
+[[package]]
+name = "const-random"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e"
+dependencies = [
+ "const-random-macro",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "const-random-macro"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb"
+dependencies = [
+ "getrandom 0.2.10",
+ "once_cell",
+ "proc-macro-hack",
+ "tiny-keccak",
+]
+
+[[package]]
+name = "constant_time_eq"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
+
+[[package]]
+name = "convert_case"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8"
+
+[[package]]
+name = "core-foundation"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "ctrlc"
+version = "3.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e"
+dependencies = [
+ "nix",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "curl"
+version = "0.4.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22"
+dependencies = [
+ "curl-sys",
+ "libc",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "socket2 0.4.9",
+ "winapi",
+]
+
+[[package]]
+name = "curl-sys"
+version = "0.4.63+curl-8.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aeb0fef7046022a1e2ad67a004978f0e3cacb9e3123dc62ce768f92197b771dc"
+dependencies = [
+ "cc",
+ "libc",
+ "libz-sys",
+ "openssl-sys",
+ "pkg-config",
+ "vcpkg",
+ "winapi",
+]
+
+[[package]]
+name = "cvt"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2ae9bf77fbf2d39ef573205d554d87e86c12f1994e9ea335b0651b9b278bcf1"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "darling"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "data-encoding"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
+
+[[package]]
+name = "dialoguer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87"
+dependencies = [
+ "console",
+ "shell-words",
+ "tempfile",
+ "zeroize",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "dioxus-autofmt"
+version = "0.3.0"
+source = "git+https://github.com/DioxusLabs/dioxus#11c9abcf7ce731ccb4a44c52de383c090ab319af"
+dependencies = [
+ "dioxus-rsx",
+ "prettier-please",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "dioxus-cli"
+version = "0.3.1"
+dependencies = [
+ "anyhow",
+ "atty",
+ "axum",
+ "binary-install",
+ "cargo-generate",
+ "cargo_metadata",
+ "cargo_toml",
+ "chrono",
+ "clap",
+ "colored 2.0.0",
+ "convert_case",
+ "ctrlc",
+ "dioxus-autofmt",
+ "dioxus-core",
+ "dioxus-html",
+ "dioxus-rsx",
+ "dirs 4.0.0",
+ "fern",
+ "flate2",
+ "fs_extra",
+ "futures",
+ "gitignore",
+ "headers",
+ "html_parser",
+ "hyper",
+ "hyper-rustls 0.23.2",
+ "indicatif",
+ "lazy_static",
+ "log",
+ "mlua",
+ "notify",
+ "open",
+ "proc-macro2",
+ "regex",
+ "reqwest",
+ "rsx-rosetta",
+ "serde",
+ "serde_json",
+ "subprocess",
+ "syn 1.0.109",
+ "tar",
+ "thiserror",
+ "tokio",
+ "toml 0.5.11",
+ "toml_edit",
+ "tower",
+ "tower-http 0.2.5",
+ "walkdir",
+ "wasm-bindgen-cli-support",
+ "zip 0.6.6",
+]
+
+[[package]]
+name = "dioxus-core"
+version = "0.3.3"
+source = "git+https://github.com/DioxusLabs/dioxus#11c9abcf7ce731ccb4a44c52de383c090ab319af"
+dependencies = [
+ "bumpalo",
+ "bumpslab",
+ "futures-channel",
+ "futures-util",
+ "indexmap 1.9.3",
+ "log",
+ "longest-increasing-subsequence",
+ "rustc-hash",
+ "serde",
+ "slab",
+ "smallbox",
+]
+
+[[package]]
+name = "dioxus-html"
+version = "0.3.1"
+source = "git+https://github.com/DioxusLabs/dioxus#11c9abcf7ce731ccb4a44c52de383c090ab319af"
+dependencies = [
+ "async-trait",
+ "dioxus-core",
+ "dioxus-rsx",
+ "enumset",
+ "euclid",
+ "keyboard-types",
+ "serde",
+ "serde-value",
+ "serde_repr",
+]
+
+[[package]]
+name = "dioxus-rsx"
+version = "0.0.3"
+source = "git+https://github.com/DioxusLabs/dioxus#11c9abcf7ce731ccb4a44c52de383c090ab319af"
+dependencies = [
+ "dioxus-core",
+ "internment",
+ "krates",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "dirs"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
+dependencies = [
+ "libc",
+ "redox_users 0.3.5",
+ "winapi",
+]
+
+[[package]]
+name = "dirs"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
+dependencies = [
+ "libc",
+ "redox_users 0.4.3",
+ "winapi",
+]
+
+[[package]]
+name = "doc-comment"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
+
+[[package]]
+name = "either"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
+
+[[package]]
+name = "encode_unicode"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "enum-as-inner"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "enumset"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e875f1719c16de097dee81ed675e2d9bb63096823ed3f0ca827b7dea3028bbbb"
+dependencies = [
+ "enumset_derive",
+]
+
+[[package]]
+name = "enumset_derive"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
+dependencies = [
+ "humantime",
+ "is-terminal",
+ "log",
+ "regex",
+ "termcolor",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1"
+
+[[package]]
+name = "errno"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
+dependencies = [
+ "errno-dragonfly",
+ "libc",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "errno-dragonfly"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
+name = "euclid"
+version = "0.22.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f253bc5c813ca05792837a0ff4b3a580336b224512d48f7eda1d7dd9210787"
+dependencies = [
+ "num-traits",
+ "serde",
+]
+
+[[package]]
+name = "failure"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
+dependencies = [
+ "backtrace",
+ "failure_derive",
+]
+
+[[package]]
+name = "failure_derive"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+ "synstructure",
+]
+
+[[package]]
+name = "fastrand"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
+dependencies = [
+ "instant",
+]
+
+[[package]]
+name = "fern"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee"
+dependencies = [
+ "colored 1.9.3",
+ "log",
+]
+
+[[package]]
+name = "filetime"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall 0.2.16",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "fixedbitset"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
+
+[[package]]
+name = "flate2"
+version = "1.0.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide 0.7.1",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "fs_at"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15550ecca96ea332ec143fb450701074143b70d358e50b32b1f847ccff2e1cf7"
+dependencies = [
+ "aligned",
+ "cfg-if",
+ "cvt",
+ "libc",
+ "nix",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
+[[package]]
+name = "fsevent-sys"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "futures"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
+
+[[package]]
+name = "futures-task"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
+
+[[package]]
+name = "futures-util"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.9.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "gimli"
+version = "0.27.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
+
+[[package]]
+name = "git2"
+version = "0.17.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b989d6a7ca95a362cf2cfc5ad688b3a467be1f87e480b8dad07fee8c79b0044"
+dependencies = [
+ "bitflags",
+ "libc",
+ "libgit2-sys",
+ "log",
+ "openssl-probe",
+ "openssl-sys",
+ "url",
+]
+
+[[package]]
+name = "gitignore"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d051488d9a601181a9b90c9ad8ae7e8251d642ddd2463008f2f5019d255bd89"
+dependencies = [
+ "glob",
+]
+
+[[package]]
+name = "gix-actor"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc22b0cdc52237667c301dd7cdc6ead8f8f73c9f824e9942c8ebd6b764f6c0bf"
+dependencies = [
+ "bstr 1.5.0",
+ "btoi",
+ "gix-date",
+ "itoa",
+ "nom",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-config"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fbad5ce54a8fc997acc50febd89ec80fa6e97cb7f8d0654cb229936407489d8"
+dependencies = [
+ "bstr 1.5.0",
+ "gix-config-value",
+ "gix-features 0.28.1",
+ "gix-glob",
+ "gix-path",
+ "gix-ref",
+ "gix-sec",
+ "log",
+ "memchr",
+ "nom",
+ "once_cell",
+ "smallvec",
+ "thiserror",
+ "unicode-bom",
+]
+
+[[package]]
+name = "gix-config-value"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d09154c0c8677e4da0ec35e896f56ee3e338e741b9599fae06075edd83a4081c"
+dependencies = [
+ "bitflags",
+ "bstr 1.5.0",
+ "gix-path",
+ "libc",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-date"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b96271912ce39822501616f177dea7218784e6c63be90d5f36322ff3a722aae2"
+dependencies = [
+ "bstr 1.5.0",
+ "itoa",
+ "thiserror",
+ "time 0.3.22",
+]
+
+[[package]]
+name = "gix-features"
+version = "0.28.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b76f9a80f6dd7be66442ae86e1f534effad9546676a392acc95e269d0c21c22"
+dependencies = [
+ "gix-hash 0.10.4",
+ "libc",
+ "sha1_smol",
+ "walkdir",
+]
+
+[[package]]
+name = "gix-features"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf69b0f5c701cc3ae22d3204b671907668f6437ca88862d355eaf9bc47a4f897"
+dependencies = [
+ "gix-hash 0.11.3",
+ "libc",
+]
+
+[[package]]
+name = "gix-fs"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b37a1832f691fdc09910bd267f9a2e413737c1f9ec68c6e31f9e802616278a9"
+dependencies = [
+ "gix-features 0.29.0",
+]
+
+[[package]]
+name = "gix-glob"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93e43efd776bc543f46f0fd0ca3d920c37af71a764a16f2aebd89765e9ff2993"
+dependencies = [
+ "bitflags",
+ "bstr 1.5.0",
+]
+
+[[package]]
+name = "gix-hash"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a258595457bc192d1f1c59d0d168a1e34e2be9b97a614e14995416185de41a7"
+dependencies = [
+ "hex 0.4.3",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-hash"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0dd58cdbe7ffa4032fc111864c80d5f8cecd9a2c9736c97ae7e5be834188272"
+dependencies = [
+ "hex 0.4.3",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-lock"
+version = "5.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c693d7f05730fa74a7c467150adc7cea393518410c65f0672f80226b8111555"
+dependencies = [
+ "gix-tempfile",
+ "gix-utils",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-object"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df068db9180ee935fbb70504848369e270bdcb576b05c0faa8b9fd3b86fc017"
+dependencies = [
+ "bstr 1.5.0",
+ "btoi",
+ "gix-actor",
+ "gix-features 0.28.1",
+ "gix-hash 0.10.4",
+ "gix-validate",
+ "hex 0.4.3",
+ "itoa",
+ "nom",
+ "smallvec",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-path"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32370dce200bb951df013e03dff35b4233fc7a89458642b047629b91734a7e19"
+dependencies = [
+ "bstr 1.5.0",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-ref"
+version = "0.27.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4e909396ed3b176823991ccc391c276ae2a015e54edaafa3566d35123cfac9d"
+dependencies = [
+ "gix-actor",
+ "gix-features 0.28.1",
+ "gix-hash 0.10.4",
+ "gix-lock",
+ "gix-object",
+ "gix-path",
+ "gix-tempfile",
+ "gix-validate",
+ "memmap2",
+ "nom",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-sec"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8ffa5bf0772f9b01de501c035b6b084cf9b8bb07dec41e3afc6a17336a65f47"
+dependencies = [
+ "bitflags",
+ "dirs 4.0.0",
+ "gix-path",
+ "libc",
+ "windows 0.43.0",
+]
+
+[[package]]
+name = "gix-tempfile"
+version = "5.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71a0d32f34e71e86586124225caefd78dabc605d0486de580d717653addf182"
+dependencies = [
+ "gix-fs",
+ "libc",
+ "once_cell",
+ "parking_lot",
+ "tempfile",
+]
+
+[[package]]
+name = "gix-utils"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ca284c260845bc0724050aec59c7a596407678342614cdf5a1d69e044f29a36"
+dependencies = [
+ "fastrand",
+]
+
+[[package]]
+name = "gix-validate"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d092b594c8af00a3a31fe526d363ee8a51a6f29d8496cdb991ed2f01ec0ec13"
+dependencies = [
+ "bstr 1.5.0",
+ "thiserror",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "globset"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc"
+dependencies = [
+ "aho-corasick 0.7.20",
+ "bstr 1.5.0",
+ "fnv",
+ "log",
+ "regex",
+]
+
+[[package]]
+name = "h2"
+version = "0.3.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http",
+ "indexmap 1.9.3",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+dependencies = [
+ "ahash 0.7.6",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
+
+[[package]]
+name = "headers"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584"
+dependencies = [
+ "base64 0.13.1",
+ "bitflags",
+ "bytes",
+ "headers-core",
+ "http",
+ "httpdate",
+ "mime",
+ "sha1",
+]
+
+[[package]]
+name = "headers-core"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
+dependencies = [
+ "http",
+]
+
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
+
+[[package]]
+name = "hex"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "home"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
+dependencies = [
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "hostname"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
+dependencies = [
+ "libc",
+ "match_cfg",
+ "winapi",
+]
+
+[[package]]
+name = "html_parser"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec016cabcf7c9c48f9d5fdc6b03f273585bfce640a0f47a69552039e92b1959a"
+dependencies = [
+ "pest",
+ "pest_derive",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "thiserror",
+]
+
+[[package]]
+name = "http"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
+dependencies = [
+ "bytes",
+ "http",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "http-range-header"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29"
+
+[[package]]
+name = "httparse"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
+
+[[package]]
+name = "httpdate"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
+
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
+name = "hyper"
+version = "0.14.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "socket2 0.4.9",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.23.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c"
+dependencies = [
+ "http",
+ "hyper",
+ "log",
+ "rustls 0.20.8",
+ "rustls-native-certs",
+ "tokio",
+ "tokio-rustls 0.23.4",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7"
+dependencies = [
+ "http",
+ "hyper",
+ "rustls 0.21.2",
+ "tokio",
+ "tokio-rustls 0.24.1",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
+dependencies = [
+ "bytes",
+ "hyper",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+]
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows 0.48.0",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "id-arena"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "idna"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
+dependencies = [
+ "matches",
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "idna"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "ignore"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492"
+dependencies = [
+ "globset",
+ "lazy_static",
+ "log",
+ "memchr",
+ "regex",
+ "same-file",
+ "thread_local",
+ "walkdir",
+ "winapi-util",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown 0.12.3",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.14.0",
+]
+
+[[package]]
+name = "indicatif"
+version = "0.17.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ff8cc23a7393a397ed1d7f56e6365cba772aba9f9912ab968b03043c395d057"
+dependencies = [
+ "console",
+ "instant",
+ "number_prefix",
+ "portable-atomic",
+ "unicode-width",
+]
+
+[[package]]
+name = "inotify"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
+dependencies = [
+ "bitflags",
+ "inotify-sys",
+ "libc",
+]
+
+[[package]]
+name = "inotify-sys"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "internment"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "161079c3ad892faa215fcfcf3fd7a6a3c9288df2b06a2c2bad7fbfad4f01d69d"
+dependencies = [
+ "hashbrown 0.12.3",
+ "parking_lot",
+]
+
+[[package]]
+name = "io-lifetimes"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
+dependencies = [
+ "hermit-abi 0.3.1",
+ "libc",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "ipconfig"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
+dependencies = [
+ "socket2 0.5.3",
+ "widestring",
+ "windows-sys 0.48.0",
+ "winreg 0.50.0",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
+
+[[package]]
+name = "iri-string"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f0f7638c1e223529f1bfdc48c8b133b9e0b434094d1d28473161ee48b235f78"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "is-docker"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "is-terminal"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
+dependencies = [
+ "hermit-abi 0.3.1",
+ "io-lifetimes",
+ "rustix",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "is-wsl"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
+dependencies = [
+ "is-docker",
+ "once_cell",
+]
+
+[[package]]
+name = "is_executable"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "302d553b8abc8187beb7d663e34c065ac4570b273bc9511a50e940e99409c577"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
+
+[[package]]
+name = "jobserver"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "keyboard-types"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7668b7cff6a51fe61cdde64cd27c8a220786f399501b57ebe36f7d8112fd68"
+dependencies = [
+ "bitflags",
+ "serde",
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "kqueue"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c8fc60ba15bf51257aa9807a48a61013db043fcf3a78cb0d916e8e396dcad98"
+dependencies = [
+ "kqueue-sys",
+ "libc",
+]
+
+[[package]]
+name = "kqueue-sys"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587"
+dependencies = [
+ "bitflags",
+ "libc",
+]
+
+[[package]]
+name = "krates"
+version = "0.12.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "942c43a6cba1c201dfe81a943c89fa5c9140b34993e0c027f542c80b92e319a7"
+dependencies = [
+ "cargo_metadata",
+ "cfg-expr",
+ "petgraph",
+ "semver",
+]
+
+[[package]]
+name = "kstring"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747"
+dependencies = [
+ "serde",
+ "static_assertions",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "leb128"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
+
+[[package]]
+name = "libc"
+version = "0.2.147"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+
+[[package]]
+name = "libgit2-sys"
+version = "0.15.2+1.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a80df2e11fb4a61f4ba2ab42dbe7f74468da143f1a75c74e11dee7c813f694fa"
+dependencies = [
+ "cc",
+ "libc",
+ "libssh2-sys",
+ "libz-sys",
+ "openssl-sys",
+ "pkg-config",
+]
+
+[[package]]
+name = "libssh2-sys"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee"
+dependencies = [
+ "cc",
+ "libc",
+ "libz-sys",
+ "openssl-sys",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "libz-sys"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "linked-hash-map"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
+
+[[package]]
+name = "liquid"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69f68ae1011499ae2ef879f631891f21c78e309755f4a5e483c4a8f12e10b609"
+dependencies = [
+ "doc-comment",
+ "liquid-core",
+ "liquid-derive",
+ "liquid-lib",
+ "serde",
+]
+
+[[package]]
+name = "liquid-core"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79e0724dfcaad5cfb7965ea0f178ca0870b8d7315178f4a7179f5696f7f04d5f"
+dependencies = [
+ "anymap2",
+ "itertools",
+ "kstring",
+ "liquid-derive",
+ "num-traits",
+ "pest",
+ "pest_derive",
+ "regex",
+ "serde",
+ "time 0.3.22",
+]
+
+[[package]]
+name = "liquid-derive"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc2fb41a9bb4257a3803154bdf7e2df7d45197d1941c9b1a90ad815231630721"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "liquid-lib"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2a17e273a6fb1fb6268f7a5867ddfd0bd4683c7e19b51084f3d567fad4348c0"
+dependencies = [
+ "itertools",
+ "liquid-core",
+ "once_cell",
+ "percent-encoding",
+ "regex",
+ "time 0.3.22",
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
+
+[[package]]
+name = "longest-increasing-subsequence"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86"
+
+[[package]]
+name = "lru-cache"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
+dependencies = [
+ "linked-hash-map",
+]
+
+[[package]]
+name = "lua-src"
+version = "546.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cb00c1380f1b4b4928dd211c07301ffa34872a239e590bd3219d9e5b213face"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "luajit-src"
+version = "210.4.5+resty2cf5186"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27b7992a40e602786272d84c6f2beca44a588ededcfd57b48ec6f82008a7cb97"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "match_cfg"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
+
+[[package]]
+name = "matches"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
+
+[[package]]
+name = "matchit"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb"
+
+[[package]]
+name = "memchr"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+
+[[package]]
+name = "memmap2"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
+[[package]]
+name = "mime_guess"
+version = "2.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "mio"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
+dependencies = [
+ "libc",
+ "log",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "mlua"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07366ed2cd22a3b000aed076e2b68896fb46f06f1f5786c5962da73c0af01577"
+dependencies = [
+ "bstr 0.2.17",
+ "cc",
+ "futures-core",
+ "futures-task",
+ "futures-util",
+ "lua-src",
+ "luajit-src",
+ "mlua_derive",
+ "num-traits",
+ "once_cell",
+ "pkg-config",
+ "rustc-hash",
+]
+
+[[package]]
+name = "mlua_derive"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9214e60d3cf1643013b107330fcd374ccec1e4ba1eef76e7e5da5e8202e71c0"
+dependencies = [
+ "itertools",
+ "once_cell",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "names"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7bddcd3bf5144b6392de80e04c347cd7fab2508f6df16a85fc496ecd5cec39bc"
+dependencies = [
+ "rand",
+]
+
+[[package]]
+name = "native-tls"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
+name = "nix"
+version = "0.26.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "libc",
+ "static_assertions",
+]
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "normpath"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec60c60a693226186f5d6edf073232bfb6464ed97eb22cf3b01c1e8198fd97f5"
+dependencies = [
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "notify"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "729f63e1ca555a43fe3efa4f3efdf4801c479da85b432242a7b726f353c88486"
+dependencies = [
+ "bitflags",
+ "crossbeam-channel",
+ "filetime",
+ "fsevent-sys",
+ "inotify",
+ "kqueue",
+ "libc",
+ "mio",
+ "serde",
+ "walkdir",
+ "windows-sys 0.45.0",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
+dependencies = [
+ "hermit-abi 0.2.6",
+ "libc",
+]
+
+[[package]]
+name = "num_threads"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "number_prefix"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
+
+[[package]]
+name = "object"
+version = "0.30.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+
+[[package]]
+name = "open"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a083c0c7e5e4a8ec4176346cf61f67ac674e8bfb059d9226e1c54a96b377c12"
+dependencies = [
+ "is-wsl",
+ "libc",
+ "pathdiff",
+]
+
+[[package]]
+name = "openssl"
+version = "0.10.55"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "ordered-float"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall 0.3.5",
+ "smallvec",
+ "windows-targets 0.48.0",
+]
+
+[[package]]
+name = "password-hash"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
+dependencies = [
+ "base64ct",
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
+
+[[package]]
+name = "path-absolutize"
+version = "3.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f1d4993b16f7325d90c18c3c6a3327db7808752db8d208cea0acee0abd52c52"
+dependencies = [
+ "path-dedot",
+]
+
+[[package]]
+name = "path-dedot"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d55e486337acb9973cdea3ec5638c1b3bcb22e573b2b7b41969e0c744d5a15e"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "pathdiff"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
+
+[[package]]
+name = "pbkdf2"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
+dependencies = [
+ "digest",
+ "hmac",
+ "password-hash",
+ "sha2",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
+
+[[package]]
+name = "pest"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f73935e4d55e2abf7f130186537b19e7a4abc886a0252380b59248af473a3fc9"
+dependencies = [
+ "thiserror",
+ "ucd-trie",
+]
+
+[[package]]
+name = "pest_derive"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aef623c9bbfa0eedf5a0efba11a5ee83209c326653ca31ff019bec3a95bfff2b"
+dependencies = [
+ "pest",
+ "pest_generator",
+]
+
+[[package]]
+name = "pest_generator"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190"
+dependencies = [
+ "pest",
+ "pest_meta",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "pest_meta"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a01f71cb40bd8bb94232df14b946909e14660e33fc05db3e50ae2a82d7ea0ca0"
+dependencies = [
+ "once_cell",
+ "pest",
+ "sha2",
+]
+
+[[package]]
+name = "petgraph"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4"
+dependencies = [
+ "fixedbitset",
+ "indexmap 1.9.3",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
+
+[[package]]
+name = "portable-atomic"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "prettier-please"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be31b7957122175fcf33c6d8f54489a5262176020bf096026a86b308b7fa5b23"
+dependencies = [
+ "proc-macro2",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.20+deprecated"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quick-error"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
+
+[[package]]
+name = "quote"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.10",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.1.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
+dependencies = [
+ "getrandom 0.1.16",
+ "redox_syscall 0.1.57",
+ "rust-argon2",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
+dependencies = [
+ "getrandom 0.2.10",
+ "redox_syscall 0.2.16",
+ "thiserror",
+]
+
+[[package]]
+name = "regex"
+version = "1.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
+dependencies = [
+ "aho-corasick 1.0.2",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
+
+[[package]]
+name = "regex-syntax"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
+
+[[package]]
+name = "remove_dir_all"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23895cfadc1917fed9c6ed76a8c2903615fa3704f7493ff82b364c6540acc02b"
+dependencies = [
+ "aligned",
+ "cfg-if",
+ "cvt",
+ "fs_at",
+ "lazy_static",
+ "libc",
+ "normpath",
+ "windows-sys 0.45.0",
+]
+
+[[package]]
+name = "reqwest"
+version = "0.11.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
+dependencies = [
+ "base64 0.21.2",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "hyper",
+ "hyper-rustls 0.24.0",
+ "hyper-tls",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "native-tls",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustls 0.21.2",
+ "rustls-pemfile",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "tokio",
+ "tokio-native-tls",
+ "tokio-rustls 0.24.1",
+ "tokio-util",
+ "tower-service",
+ "trust-dns-resolver",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-streams",
+ "web-sys",
+ "webpki-roots",
+ "winreg 0.10.1",
+]
+
+[[package]]
+name = "resolv-conf"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00"
+dependencies = [
+ "hostname",
+ "quick-error",
+]
+
+[[package]]
+name = "rhai"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd29fa1f740be6dc91982013957e08c3c4232d7efcfe19e12da87d50bad47758"
+dependencies = [
+ "ahash 0.8.3",
+ "bitflags",
+ "instant",
+ "num-traits",
+ "rhai_codegen",
+ "smallvec",
+ "smartstring",
+]
+
+[[package]]
+name = "rhai_codegen"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db74e3fdd29d969a0ec1f8e79171a6f0f71d0429293656901db382d248c4c021"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ring"
+version = "0.16.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
+dependencies = [
+ "cc",
+ "libc",
+ "once_cell",
+ "spin",
+ "untrusted",
+ "web-sys",
+ "winapi",
+]
+
+[[package]]
+name = "rsx-rosetta"
+version = "0.3.0"
+source = "git+https://github.com/DioxusLabs/dioxus#11c9abcf7ce731ccb4a44c52de383c090ab319af"
+dependencies = [
+ "convert_case",
+ "dioxus-autofmt",
+ "dioxus-rsx",
+ "html_parser",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "rust-argon2"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
+dependencies = [
+ "base64 0.13.1",
+ "blake2b_simd",
+ "constant_time_eq",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustix"
+version = "0.37.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0"
+dependencies = [
+ "bitflags",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "rustls"
+version = "0.20.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f"
+dependencies = [
+ "log",
+ "ring",
+ "sct",
+ "webpki",
+]
+
+[[package]]
+name = "rustls"
+version = "0.21.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f"
+dependencies = [
+ "log",
+ "ring",
+ "rustls-webpki",
+ "sct",
+]
+
+[[package]]
+name = "rustls-native-certs"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
+dependencies = [
+ "openssl-probe",
+ "rustls-pemfile",
+ "schannel",
+ "security-framework",
+]
+
+[[package]]
+name = "rustls-pemfile"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
+dependencies = [
+ "base64 0.21.2",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.100.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b"
+dependencies = [
+ "ring",
+ "untrusted",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
+
+[[package]]
+name = "safemem"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "sanitize-filename"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08c502bdb638f1396509467cb0580ef3b29aa2a45c5d43e5d84928241280296c"
+dependencies = [
+ "lazy_static",
+ "regex",
+]
+
+[[package]]
+name = "schannel"
+version = "0.1.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
+dependencies = [
+ "windows-sys 0.42.0",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "sct"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
+dependencies = [
+ "ring",
+ "untrusted",
+]
+
+[[package]]
+name = "security-framework"
+version = "2.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.164"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde-value"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
+dependencies = [
+ "ordered-float",
+ "serde",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.164"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.99"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_repr"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "sha-1"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "sha1"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "sha1_smol"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
+
+[[package]]
+name = "sha2"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "shell-words"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "siphasher"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
+
+[[package]]
+name = "slab"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "smallbox"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4679d6eef28b85020158619fc09769de89e90886c5de7157587d87cb72648faa"
+
+[[package]]
+name = "smallvec"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+
+[[package]]
+name = "smartstring"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29"
+dependencies = [
+ "autocfg",
+ "static_assertions",
+ "version_check",
+]
+
+[[package]]
+name = "socket2"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "socket2"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
+dependencies = [
+ "libc",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "spin"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "subprocess"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c2e86926081dda636c546d8c5e641661049d7562a68f5488be4a1f7f66f6086"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "subtle"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "sync_wrapper"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
+
+[[package]]
+name = "synstructure"
+version = "0.12.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+ "unicode-xid",
+]
+
+[[package]]
+name = "tar"
+version = "0.4.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6"
+dependencies = [
+ "filetime",
+ "libc",
+ "xattr",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "redox_syscall 0.3.5",
+ "rustix",
+ "windows-sys 0.45.0",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+]
+
+[[package]]
+name = "time"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
+dependencies = [
+ "libc",
+ "wasi 0.10.0+wasi-snapshot-preview1",
+ "winapi",
+]
+
+[[package]]
+name = "time"
+version = "0.3.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd"
+dependencies = [
+ "itoa",
+ "libc",
+ "num_threads",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
+
+[[package]]
+name = "time-macros"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
+dependencies = [
+ "time-core",
+]
+
+[[package]]
+name = "tiny-keccak"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
+dependencies = [
+ "crunchy",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.28.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2"
+dependencies = [
+ "autocfg",
+ "bytes",
+ "libc",
+ "mio",
+ "num_cpus",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2 0.4.9",
+ "tokio-macros",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.23.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
+dependencies = [
+ "rustls 0.20.8",
+ "tokio",
+ "webpki",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
+dependencies = [
+ "rustls 0.21.2",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-tungstenite"
+version = "0.17.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181"
+dependencies = [
+ "futures-util",
+ "log",
+ "tokio",
+ "tungstenite",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.19.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7"
+dependencies = [
+ "indexmap 2.0.0",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "tower"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project",
+ "pin-project-lite",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "tower-http"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8"
+dependencies = [
+ "async-compression",
+ "base64 0.13.1",
+ "bitflags",
+ "bytes",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-range-header",
+ "httpdate",
+ "iri-string",
+ "mime",
+ "mime_guess",
+ "percent-encoding",
+ "pin-project-lite",
+ "tokio",
+ "tokio-util",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "tower-http"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858"
+dependencies = [
+ "bitflags",
+ "bytes",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-range-header",
+ "pin-project-lite",
+ "tower",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
+
+[[package]]
+name = "tower-service"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
+
+[[package]]
+name = "tracing"
+version = "0.1.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
+dependencies = [
+ "cfg-if",
+ "log",
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "trust-dns-proto"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26"
+dependencies = [
+ "async-trait",
+ "cfg-if",
+ "data-encoding",
+ "enum-as-inner",
+ "futures-channel",
+ "futures-io",
+ "futures-util",
+ "idna 0.2.3",
+ "ipnet",
+ "lazy_static",
+ "rand",
+ "smallvec",
+ "thiserror",
+ "tinyvec",
+ "tokio",
+ "tracing",
+ "url",
+]
+
+[[package]]
+name = "trust-dns-resolver"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe"
+dependencies = [
+ "cfg-if",
+ "futures-util",
+ "ipconfig",
+ "lazy_static",
+ "lru-cache",
+ "parking_lot",
+ "resolv-conf",
+ "smallvec",
+ "thiserror",
+ "tokio",
+ "tracing",
+ "trust-dns-proto",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
+
+[[package]]
+name = "tungstenite"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0"
+dependencies = [
+ "base64 0.13.1",
+ "byteorder",
+ "bytes",
+ "http",
+ "httparse",
+ "log",
+ "rand",
+ "sha-1",
+ "thiserror",
+ "url",
+ "utf-8",
+]
+
+[[package]]
+name = "typenum"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
+
+[[package]]
+name = "ucd-trie"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
+
+[[package]]
+name = "unicase"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
+dependencies = [
+ "version_check",
+]
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
+
+[[package]]
+name = "unicode-bom"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63ec69f541d875b783ca40184d655f2927c95f0bffd486faa83cd3ac3529ec32"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
+
+[[package]]
+name = "untrusted"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
+
+[[package]]
+name = "url"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
+dependencies = [
+ "form_urlencoded",
+ "idna 0.4.0",
+ "percent-encoding",
+]
+
+[[package]]
+name = "utf-8"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "walkdir"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "walrus"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4eb08e48cde54c05f363d984bb54ce374f49e242def9468d2e1b6c2372d291f8"
+dependencies = [
+ "anyhow",
+ "id-arena",
+ "leb128",
+ "log",
+ "walrus-macro",
+ "wasmparser",
+]
+
+[[package]]
+name = "walrus-macro"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a6e5bd22c71e77d60140b0bd5be56155a37e5bd14e24f5f87298040d0cc40d7"
+dependencies = [
+ "heck 0.3.3",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
+name = "wasi"
+version = "0.10.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-cli-support"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d21c60239a09bf9bab8dfa752be4e6c637db22296b9ded493800090448692da9"
+dependencies = [
+ "anyhow",
+ "base64 0.9.3",
+ "log",
+ "rustc-demangle",
+ "serde_json",
+ "tempfile",
+ "unicode-ident",
+ "walrus",
+ "wasm-bindgen-externref-xform",
+ "wasm-bindgen-multi-value-xform",
+ "wasm-bindgen-shared",
+ "wasm-bindgen-threads-xform",
+ "wasm-bindgen-wasm-conventions",
+ "wasm-bindgen-wasm-interpreter",
+]
+
+[[package]]
+name = "wasm-bindgen-externref-xform"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bafbe1984f67cc12645f12ab65e6145e8ddce1ab265d0be58435f25bb0ce2608"
+dependencies = [
+ "anyhow",
+ "walrus",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-multi-value-xform"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581419e3995571a1d2d066e360ca1c0c09da097f5a53c98e6f00d96eddaf0ffe"
+dependencies = [
+ "anyhow",
+ "walrus",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
+
+[[package]]
+name = "wasm-bindgen-threads-xform"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e05d272073981137e8426cf2a6830d43d1f84f988a050b2f8b210f0e266b8983"
+dependencies = [
+ "anyhow",
+ "walrus",
+ "wasm-bindgen-wasm-conventions",
+]
+
+[[package]]
+name = "wasm-bindgen-wasm-conventions"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e9c65b1ff5041ea824ca24c519948aec16fb6611c617d601623c0657dfcd47b"
+dependencies = [
+ "anyhow",
+ "walrus",
+]
+
+[[package]]
+name = "wasm-bindgen-wasm-interpreter"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c5c796220738ab5d44666f37205728a74141c0039d1166bcf8110b26bafaa1e"
+dependencies = [
+ "anyhow",
+ "log",
+ "walrus",
+ "wasm-bindgen-wasm-conventions",
+]
+
+[[package]]
+name = "wasm-streams"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078"
+dependencies = [
+ "futures-util",
+ "js-sys",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "wasmparser"
+version = "0.77.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fe3d5405e9ea6c1317a656d6e0820912d8b7b3607823a7596117c8f666daf6f"
+
+[[package]]
+name = "web-sys"
+version = "0.3.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "webpki"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
+dependencies = [
+ "ring",
+ "untrusted",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "0.22.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
+dependencies = [
+ "webpki",
+]
+
+[[package]]
+name = "widestring"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows"
+version = "0.43.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244"
+dependencies = [
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
+]
+
+[[package]]
+name = "windows"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+dependencies = [
+ "windows-targets 0.48.0",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+dependencies = [
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets 0.42.2",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.0",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.0",
+ "windows_aarch64_msvc 0.48.0",
+ "windows_i686_gnu 0.48.0",
+ "windows_i686_msvc 0.48.0",
+ "windows_x86_64_gnu 0.48.0",
+ "windows_x86_64_gnullvm 0.48.0",
+ "windows_x86_64_msvc 0.48.0",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+
+[[package]]
+name = "winnow"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "winreg"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winreg"
+version = "0.50.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
+dependencies = [
+ "cfg-if",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "xattr"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
+
+[[package]]
+name = "zip"
+version = "0.5.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815"
+dependencies = [
+ "byteorder",
+ "bzip2",
+ "crc32fast",
+ "flate2",
+ "thiserror",
+ "time 0.1.45",
+]
+
+[[package]]
+name = "zip"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
+dependencies = [
+ "aes",
+ "byteorder",
+ "bzip2",
+ "constant_time_eq",
+ "crc32fast",
+ "crossbeam-utils",
+ "flate2",
+ "hmac",
+ "pbkdf2",
+ "sha1",
+ "time 0.3.22",
+ "zstd",
+]
+
+[[package]]
+name = "zstd"
+version = "0.11.2+zstd.1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
+dependencies = [
+ "zstd-safe",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "5.0.2+zstd.1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
+dependencies = [
+ "libc",
+ "zstd-sys",
+]
+
+[[package]]
+name = "zstd-sys"
+version = "2.0.8+zstd.1.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]

+ 92 - 0
packages/cli/Cargo.toml

@@ -0,0 +1,92 @@
+[package]
+name = "dioxus-cli"
+version = "0.3.1"
+authors = ["Jonathan Kelley"]
+edition = "2021"
+description = "CLI tool for developing, testing, and publishing Dioxus apps"
+license = "MIT/Apache-2.0"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+
+# cli core
+clap = { version = "4.2", features = ["derive"] }
+thiserror = "1.0.30"
+wasm-bindgen-cli-support = "0.2"
+colored = "2.0.0"
+
+# features
+log = "0.4.14"
+fern = { version = "0.6.0", features = ["colored"] }
+serde = { version = "1.0.136", features = ["derive"] }
+serde_json = "1.0.79"
+toml = "0.5.8"
+fs_extra = "1.2.0"
+cargo_toml = "0.11.4"
+futures = "0.3.21"
+notify = { version = "5.0.0-pre.16", features = ["serde"] }
+html_parser = "0.6.2"
+binary-install = "0.0.2"
+convert_case = "0.5.0"
+cargo_metadata = "0.15.0"
+tokio = { version = "1.16.1", features = ["full"] }
+atty = "0.2.14"
+regex = "1.5.4"
+chrono = "0.4.19"
+anyhow = "1.0.53"
+hyper = "0.14.17"
+hyper-rustls = "0.23.2"
+indicatif = "0.17.0-rc.11"
+subprocess = "0.2.9"
+
+axum = { version = "0.5.1", features = ["ws", "headers"] }
+tower-http = { version = "0.2.2", features = ["full"] }
+headers = "0.3.7"
+
+walkdir = "2"
+
+# tools download
+dirs = "4.0.0"
+reqwest = { version = "0.11", features = [
+    "rustls-tls",
+    "stream",
+    "trust-dns",
+    "blocking",
+] }
+flate2 = "1.0.22"
+tar = "0.4.38"
+zip = "0.6.2"
+tower = "0.4.12"
+
+syn = { version = "1.0", features = ["full", "extra-traits"] }
+
+
+proc-macro2 = { version = "1.0", features = ["span-locations"] }
+lazy_static = "1.4.0"
+
+# plugin packages
+mlua = { version = "0.8.1", features = [
+    "lua54",
+    "vendored",
+    "async",
+    "send",
+    "macros",
+] }
+ctrlc = "3.2.3"
+# dioxus-rsx = "0.0.1"
+gitignore = "1.0.7"
+
+dioxus-rsx = { git = "https://github.com/DioxusLabs/dioxus" }
+dioxus-html = { git = "https://github.com/DioxusLabs/dioxus", features = ["hot-reload-context"] }
+dioxus-core = { git = "https://github.com/DioxusLabs/dioxus", features = ["serialize"] }
+dioxus-autofmt = { git = "https://github.com/DioxusLabs/dioxus" }
+rsx-rosetta = { git = "https://github.com/DioxusLabs/dioxus" }
+open = "4.1.0"
+cargo-generate = "0.18.3"
+toml_edit = "0.19.11"
+
+[[bin]]
+path = "src/main.rs"
+
+name = "dioxus"

+ 45 - 0
packages/cli/Dioxus.toml

@@ -0,0 +1,45 @@
+[application]
+
+# dioxus project name
+name = "dioxus-cli"
+
+# default platfrom
+# you can also use `dioxus serve/build --platform XXX` to use other platform
+# value: web | desktop
+default_platform = "desktop"
+
+# Web `build` & `serve` dist path
+out_dir = "dist"
+
+# resource (static) file folder
+asset_dir = "public"
+
+[web.app]
+
+# HTML title tag content
+title = "dioxus | ⛺"
+
+[web.watcher]
+
+watch_path = ["src"]
+
+# include `assets` in web platform
+[web.resource]
+
+# CSS style file
+style = []
+
+# Javascript code file
+script = []
+
+[web.resource.dev]
+
+# Javascript code file
+# serve: [dev-server] only
+script = []
+
+[application.tools]
+
+# use binaryen.wasm-opt for output Wasm file
+# binaryen just will trigger in `web` platform
+binaryen = { wasm_opt = true }

+ 43 - 0
packages/cli/README.md

@@ -0,0 +1,43 @@
+<div align="center">
+  <h1>📦✨ Dioxus CLI </h1>
+  <p><strong>Tooling to supercharge Dioxus projects</strong></p>
+</div>
+**dioxus-cli** (inspired by wasm-pack and webpack) is a tool for getting Dioxus projects up and running. 
+It handles all build, bundling, development and publishing to simplify web development.
+
+
+## Installation
+
+### Install stable version
+```
+cargo install dioxus-cli
+```
+### Install from git repository
+```
+cargo install --git https://github.com/DioxusLabs/cli
+```
+### Install from local folder
+```
+cargo install --path . --debug
+```
+
+
+## Get Started 
+
+Use `dioxus create project-name` to initialize a new Dioxus project. <br>
+
+It will be cloned from the [dioxus-template](https://github.com/DioxusLabs/dioxus-template) repository.
+
+<br>
+
+Alternatively, you can specify the template path:
+
+```
+dioxus create hello --template gh:dioxuslabs/dioxus-template
+```
+
+## Dioxus Config File
+
+Dioxus CLI will use `Dioxus.toml` file to Identify some project info and switch some cli feature.
+
+You can get more configure information from [Dioxus CLI Document](https://dioxuslabs.com/cli/configure.html).

+ 50 - 0
packages/cli/build.rs

@@ -0,0 +1,50 @@
+//! Construct version in the `commit-hash date channel` format
+
+use std::{env, path::PathBuf, process::Command};
+
+fn main() {
+    set_rerun();
+    set_commit_info();
+    if option_env!("CFG_RELEASE").is_none() {
+        println!("cargo:rustc-env=POKE_RA_DEVS=1");
+    }
+}
+
+fn set_rerun() {
+    println!("cargo:rerun-if-env-changed=CFG_RELEASE");
+
+    let mut manifest_dir = PathBuf::from(
+        env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is always set by cargo."),
+    );
+
+    while manifest_dir.parent().is_some() {
+        let head_ref = manifest_dir.join(".git/HEAD");
+        if head_ref.exists() {
+            println!("cargo:rerun-if-changed={}", head_ref.display());
+            return;
+        }
+
+        manifest_dir.pop();
+    }
+
+    println!("cargo:warning=Could not find `.git/HEAD` from manifest dir!");
+}
+
+fn set_commit_info() {
+    let output = match Command::new("git")
+        .arg("log")
+        .arg("-1")
+        .arg("--date=short")
+        .arg("--format=%H %h %cd")
+        .output()
+    {
+        Ok(output) if output.status.success() => output,
+        _ => return,
+    };
+    let stdout = String::from_utf8(output.stdout).unwrap();
+    let mut parts = stdout.split_whitespace();
+    let mut next = || parts.next().unwrap();
+    println!("cargo:rustc-env=RA_COMMIT_HASH={}", next());
+    println!("cargo:rustc-env=RA_COMMIT_SHORT_HASH={}", next());
+    println!("cargo:rustc-env=RA_COMMIT_DATE={}", next())
+}

+ 1 - 0
packages/cli/docs/.gitignore

@@ -0,0 +1 @@
+book

+ 6 - 0
packages/cli/docs/book.toml

@@ -0,0 +1,6 @@
+[book]
+authors = ["YuKun Liu"]
+language = "en"
+multilingual = false
+src = "src"
+title = "Dioxus Cli"

+ 18 - 0
packages/cli/docs/src/SUMMARY.md

@@ -0,0 +1,18 @@
+# Summary
+
+- [Introduction](./introduction.md)
+- [Installation](./installation.md)
+- [Create a Project](./creating.md)
+- [Configure Project](./configure.md)
+- [Commands](./cmd/README.md)
+  - [Build](./cmd/build.md)
+  - [Serve](./cmd/serve.md)
+  - [Clean](./cmd/clean.md)
+  - [Translate](./cmd/translate.md)
+- [Plugin Development](./plugin/README.md)
+  - [API.Log](./plugin/interface/log.md)
+  - [API.Command](./plugin/interface/command.md)
+  - [API.OS](./plugin/interface/os.md)
+  - [API.Directories](./plugin/interface/dirs.md)
+  - [API.Network](./plugin/interface/network.md)
+  - [API.Path](./plugin/interface/path.md)

+ 26 - 0
packages/cli/docs/src/cmd/README.md

@@ -0,0 +1,26 @@
+# Commands
+
+In this chapter we will introduce all `dioxus-cli` commands.
+
+> You can also use `dioxus --help` to get cli help info.
+
+```
+dioxus 
+Build, bundle, & ship your Dioxus app
+
+USAGE:
+    dioxus [OPTIONS] <SUBCOMMAND>
+
+OPTIONS:
+    -h, --help    Print help information
+    -v            Enable verbose logging
+
+SUBCOMMANDS:
+    build        Build the Dioxus application and all of its assets
+    clean        Clean output artifacts
+    config       Dioxus config file controls
+    create       Init a new project for Dioxus
+    help         Print this message or the help of the given subcommand(s)
+    serve        Build, watch & serve the Rust WASM app and all of its assets
+    translate    Translate some html file into a Dioxus component
+```

+ 47 - 0
packages/cli/docs/src/cmd/build.md

@@ -0,0 +1,47 @@
+# Build
+
+The `dioxus build` command can help you `pack & build` a dioxus project.
+
+```
+dioxus-build 
+Build the Rust WASM app and all of its assets
+
+USAGE:
+    dioxus build [OPTIONS]
+
+OPTIONS:
+        --example <EXAMPLE>      [default: ""]
+        --platform <PLATFORM>    [default: "default_platform"]
+        --release                [default: false]
+```
+
+You can use this command to build a project:
+
+```
+dioxus build --release
+```
+
+## Target platform
+
+Use the `platform` option to choose your target platform:
+
+```
+# for desktop project
+dioxus build --platform desktop
+```
+
+`platform` currently only supports `desktop` & `web`.
+
+```
+# for web project
+dioxus build --platform web
+```
+
+## Build Example
+
+You can use the `example` option to select a example to build:
+
+```
+# build the `test` example
+dioxus build --exmaple test
+```

+ 18 - 0
packages/cli/docs/src/cmd/clean.md

@@ -0,0 +1,18 @@
+# Clean
+
+`dioxus clean` will clear the build artifacts (the out_dir and the cargo cache)
+
+```
+dioxus-clean 
+Clean build artifacts
+
+USAGE:
+    dioxus clean
+```
+
+# Example
+
+```
+dioxus clean
+```
+

+ 61 - 0
packages/cli/docs/src/cmd/serve.md

@@ -0,0 +1,61 @@
+# Serve
+
+The `dioxus serve` can start a dev server with hot-reloading
+
+```
+dioxus-serve 
+Build, watch & serve the Rust WASM app and all of its assets
+
+USAGE:
+    dioxus serve [OPTIONS]
+
+OPTIONS:
+        --example <EXAMPLE>      [default: ""]
+        --platform <PLATFORM>    [default: "default_platform"]
+        --release                [default: false]
+        --hot-reload             [default: false]ß
+```
+
+You can use this command to build project and start a dev server:
+
+```
+dioxus serve
+```
+
+## Serve Example
+
+You can use the `example` option to serve a example:
+
+```
+# serve the `test` example
+dioxus serve --exmaple test
+```
+
+## Open Browser
+
+You can add the `--open` option to open system default browser when server startup:
+
+```
+dioxus serve --open
+```
+
+## RSX Hot Reloading
+
+You can add the `--hot-reload` flag to enable [rsx hot reloading](https://dioxuslabs.com/docs/0.3/guide/en/getting_started/hot_reload.html). This will allow you to reload some rsx changes without a full recompile:
+
+```
+dioxus serve --open
+```
+
+## Cross Origin Policy
+
+You can add the `cross-origin-policy` option to change cross-origin header to:
+
+```
+  Cross-Origin-Opener-Policy: same-origin
+  Cross-Origin-Embedder-Policy: require-corp
+```
+
+```
+dioxus serve --corss-origin-policy
+```

+ 68 - 0
packages/cli/docs/src/cmd/translate.md

@@ -0,0 +1,68 @@
+# Translate
+
+`dioxus translate` can translate some `html` file into a Dioxus compoent
+
+```
+dioxus-translate 
+Translate some source file into a Dioxus component
+
+USAGE:
+    dioxus translate [OPTIONS] [OUTPUT]
+
+ARGS:
+    <OUTPUT>    Output file, defaults to stdout if not present
+
+OPTIONS:
+    -c, --component      Activate debug mode
+    -f, --file <FILE>    Input file
+```
+
+## Translate HTML to stdout
+
+You can use the `file` option to set path to the `html` file to translate:
+
+```
+dioxus transtale --file ./index.html
+```
+
+## Output rsx to a file
+
+You can pass a file to the traslate command to set the path to write the output of the command to:
+
+```
+dioxus translate --file ./index.html component.rsx
+```
+
+## Output rsx to a file
+
+Setting the `component` option will create a compoent from the HTML:
+
+```
+dioxus translate --file ./index.html --component
+```
+
+## Example
+
+This HTML:
+```html
+<div>
+    <h1> Hello World </h1>
+    <a href="https://dioxuslabs.com/">Link</a>
+</div>
+```
+
+Translates into this Dioxus component:
+
+```rust
+fn component(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div {
+            h1 { "Hello World" },
+            a {
+                href: "https://dioxuslabs.com/",
+                "Link"
+            }
+        }
+    })
+}
+```

+ 208 - 0
packages/cli/docs/src/configure.md

@@ -0,0 +1,208 @@
+# Configure Project
+
+
+This chapter will introduce you to how to configure the CLI with your `Dioxus.toml` file
+
+Be aware that if the config file is present in the folder, some fields must be filled out, or the CLI tool will abort. The mandatory [table headers](https://toml.io/en/v1.0.0#table) and keys will have a '✍' sign beside it.
+
+## Structure
+
+The CLI uses a `Dioxus.toml` file in the root of your crate to define some configuration for your `dioxus` project.
+
+### Application ✍
+
+General application confiration:
+
+```
+[application]
+# configuration
+```
+1. ***name*** ✍ - project name & title
+2. ***default_platform*** ✍ - which platform target for this project.
+
+   ```
+   name = "my-project"
+   ```
+2. ***default_platform*** - The platform this project targets
+   ```ß
+   # current supported platforms: web, desktop
+   # default: web
+   default_platform = "web"
+   ```
+   if you change this to `desktop`, the `dioxus build` will default building a desktop app
+3. ***out_dir*** - The directory to place the build artifacts from `dioxus build` or `dioxus service` into. This is also where the `assets` directory will be copied to
+    ```
+    out_dir = "dist"
+    ```
+4. ***asset_dir*** - The directory with your static assets. The CLI will automatically copy these assets into the ***out_dir*** after a build/serve.
+   ```
+   asset_dir = "public"
+   ```
+5. ***sub_package*** - The sub package in the workspace to build by default
+   ```
+   sub_package = "my-crate"
+   ```
+
+### Web.App ✍
+
+Configeration specific to web applications:
+
+```
+[web.app]
+# configuration
+```
+
+1. ***title*** - The title of the web page
+   ```
+   # HTML title tag content
+   title = "dioxus app | ⛺"
+   ```
+2. ***base_path*** - The base path to build the appliation for serving at. This can be useful when serving your application in a subdirectory under a domain. For example when building a site to be served on github pages.
+   ```
+   # The application will be served at domain.com/my_application/, so we need to modify the base_path to the path where the application will be served
+   base_path = "my_application"
+   ```
+
+### Web.Watcher ✍
+
+Configeration related to the development server:
+
+```
+[web.watcher]
+# configuration
+```
+
+1. ***reload_html*** - If this is true, the cli will rebuild the index.html file every time the application is rebuilt
+   ```
+   reload_html = true
+   ```
+2. ***watch_path*** - The files & directories to moniter for changes
+   ```
+   watch_path = ["src", "public"]
+   ```
+3. ***index_on_404*** - If enabled, Dioxus CLI will serve the root page when a route is not found. *This is needed when serving an application that uses the router*
+   ```
+   index_on_404 = true
+   ```
+
+### Web.Resource ✍
+
+Configeration related to static resources your application uses:
+```
+[web.resource]
+# configuration
+```
+
+1. ***style*** - The styles (`.css` files) to include in your application
+   ```
+   style = [
+      # include from public_dir.
+      "./assets/style.css",
+      # or some asset from online cdn.
+      "https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css"
+   ]
+   ```
+2. ***script*** - The additional scripts (`.js` files) to include in your application
+    ```
+    style = [
+        # include from public_dir.
+        "./assets/index.js",
+        # or some asset from online cdn.
+        "https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.js"
+    ]
+   ```
+
+### Web.Resource.Dev ✍
+
+Configeration related to static resources your application uses in development:
+```
+[web.resource.dev]
+# configuration
+```
+
+1. ***style*** - The styles (`.css` files) to include in your application
+   ```
+   style = [
+      # include from public_dir.
+      "./assets/style.css",
+      # or some asset from online cdn.
+      "https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css"
+   ]
+   ```
+2. ***script*** - The additional scripts (`.js` files) to include in your application
+    ```
+    style = [
+        # include from public_dir.
+        "./assets/index.js",
+        # or some asset from online cdn.
+        "https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.js"
+    ]
+   ```
+
+### Web.Proxy
+
+Configeration related to any proxies your application requires durring development. Proxies will forward requests to a new service
+
+```
+[web.proxy]
+# configuration
+```
+
+1. ***backend*** - The URL to the server to proxy. The CLI will forward any requests under the backend relative route to the backend instead of returning 404
+   ```
+   backend = "http://localhost:8000/api/"
+   ```
+   This will cause any requests made to the dev server with prefix /api/ to be redirected to the backend server at http://localhost:8000. The path and query parameters will be passed on as-is (path rewriting is not currently supported).
+
+## Config example
+
+```toml
+[application]
+
+# App (Project) Name
+name = "{{project-name}}"
+
+# The Dioxus platform to default to
+default_platform = "web"
+
+# `build` & `serve` output path
+out_dir = "dist"
+
+# the static resource path
+asset_dir = "public"
+
+[web.app]
+
+# HTML title tag content
+title = "dioxus | ⛺"
+
+[web.watcher]
+
+# when watcher is triggered, regenerate the `index.html`
+reload_html = true
+
+# which files or dirs will be monitored
+watch_path = ["src", "public"]
+
+# include `assets` in web platform
+[web.resource]
+
+# CSS style file
+style = []
+
+# Javascript code file
+script = []
+
+[web.resource.dev]
+
+# serve: [dev-server] only
+
+# CSS style file
+style = []
+
+# Javascript code file
+script = []
+
+[[web.proxy]]
+backend = "http://localhost:8000/api/"
+```

+ 39 - 0
packages/cli/docs/src/creating.md

@@ -0,0 +1,39 @@
+# Create a Project
+
+Once you have the Dioxus CLI tool installed, you can use it to create dioxus project.
+
+## Initializing a default project
+
+First, run the `dioxus create` command to create a new project ready to be used with Dioxus and the Dioxus CLI:
+
+```
+dioxus create hello-dioxus
+```
+
+> It will clone a default template from github template: [DioxusLabs/dioxus-template](https://github.com/DioxusLabs/dioxus-template)
+> This default template is use for `web` platform application.
+>
+> You can choose to create your project from a different template by passing the `template` argument:
+> ```
+> dioxus init hello-dioxus --template=gh:dioxuslabs/dioxus-template
+> ```
+
+Next, move the current directory into your new project:
+
+```
+cd hello-dioxus
+```
+
+> Make sure `wasm32 target` is installed before running the Web project.
+> You can install the wasm target for rust using rustup:
+> ```
+> rustup target add wasm32-unknown-unknown
+> ```
+
+Finally, create serve your project with the Dioxus CLI:
+
+```
+dioxus serve
+```
+
+By default, the CLI serve your site at: [`http://127.0.0.1:8080/`](http://127.0.0.1:8080/)

+ 22 - 0
packages/cli/docs/src/installation.md

@@ -0,0 +1,22 @@
+# Installation
+
+Choose any one of the methods below to install the Dioxus CLI:
+
+## Install from latest git version
+
+To get the most up to date bug fixes and features of the Dioxus CLI, you can install the development version from git.
+
+```
+cargo install --git https://github.com/Dioxuslabs/cli
+```
+
+This will automatically download `Dioxus-CLI` source from github master branch,
+and install it in Cargo's global binary directory (`~/.cargo/bin/` by default).
+
+## Install from `crates.io` version
+
+The published version of the Dioxus CLI is updated less often, but should be more stable than the git version of the Dioxus CLI.
+
+```
+cargo install dioxus-cli
+```

+ 21 - 0
packages/cli/docs/src/introduction.md

@@ -0,0 +1,21 @@
+# Introduction
+
+📦✨ **Dioxus-Cli** is a tool to help get dioxus projects off the ground.
+
+![dioxus-logo](https://dioxuslabs.com/guide/images/dioxuslogo_full.png)
+
+It includes `dev server`, `hot reload` and some `quick command` to help you use dioxus.
+
+## Features
+
+- [x] `html` to `rsx` conversion tool
+- [x] hot reload for `web` platform
+- [x] create dioxus project from `git` repo
+- [x] build & pack dioxus project
+- [ ] autoformat dioxus `rsx` code
+
+## Contributors
+
+Contributors to this guide:
+
+- [mrxiaozhuox](https://github.com/mrxiaozhuox)

+ 79 - 0
packages/cli/docs/src/plugin/README.md

@@ -0,0 +1,79 @@
+# CLI Plugin Development
+
+> For Cli 0.2.0 we will add `plugin-develop` support.
+
+Before the 0.2.0 we use `dioxus tool` to use & install some plugin, but we think that is not good for extend cli program, some people want tailwind support, some people want sass support, we can't add all this thing in to the cli source code and we don't have time to maintain a lot of tools that user request, so maybe user make plugin by themself is a good choice.
+
+### Why Lua ?
+
+We choose `Lua: 5.4` to be the plugin develop language, because cli plugin is not complex, just like a workflow, and user & developer can write some easy code for their plugin. We have **vendored** lua in cli program, and user don't need install lua runtime in their computer, and the lua parser & runtime doesn't take up much disk memory.
+
+### Event Management
+
+The plugin library have pre-define some important event you can control:
+
+- `build.on_start`
+- `build.on_finished`
+- `serve.on_start`
+- `serve.on_rebuild`
+- `serve.on_shutdown`
+
+### Plugin Template
+
+```lua
+package.path = library_dir .. "/?.lua"
+
+local plugin = require("plugin")
+local manager = require("manager")
+
+-- deconstruct api functions
+local log = plugin.log
+
+-- plugin information
+manager.name = "Hello Dixous Plugin"
+manager.repository = "https://github.com/mrxiaozhuox/hello-dioxus-plugin"
+manager.author = "YuKun Liu <mrxzx.info@gmail.com>"
+manager.version = "0.0.1"
+
+-- init manager info to plugin api
+plugin.init(manager)
+
+manager.on_init = function ()
+    -- when the first time plugin been load, this function will be execute.
+    -- system will create a `dcp.json` file to verify init state.
+    log.info("[plugin] Start to init plugin: " .. manager.name)
+end
+
+---@param info BuildInfo
+manager.build.on_start = function (info)
+    -- before the build work start, system will execute this function.
+    log.info("[plugin] Build starting: " .. info.name)
+end
+
+---@param info BuildInfo
+manager.build.on_finish = function (info)
+    -- when the build work is done, system will execute this function.
+    log.info("[plugin] Build finished: " .. info.name)
+end
+
+---@param info ServeStartInfo
+manager.serve.on_start = function (info)
+    -- this function will after clean & print to run, so you can print some thing.
+    log.info("[plugin] Serve start: " .. info.name)
+end
+
+---@param info ServeRebuildInfo
+manager.serve.on_rebuild = function (info)
+    -- this function will after clean & print to run, so you can print some thing.
+    local files = plugin.tool.dump(info.changed_files)
+    log.info("[plugin] Serve rebuild: '" .. files .. "'")
+end
+
+manager.serve.on_shutdown = function ()
+    log.info("[plugin] Serve shutdown")
+end
+
+manager.serve.interval = 1000
+
+return manager
+```

+ 21 - 0
packages/cli/docs/src/plugin/interface/command.md

@@ -0,0 +1,21 @@
+# Command Functions
+
+> you can use command functions to execute some code & script
+
+Type Define:
+```
+Stdio: "Inherit" | "Piped" | "Null"
+```
+
+### `exec(commands: [string], stdout: Stdio, stderr: Stdio)`
+
+you can use this function to run some command on the current system.
+
+```lua
+local cmd = plugin.command
+
+manager.test = function ()
+    cmd.exec({"git", "clone", "https://github.com/DioxusLabs/cli-plugin-library"})
+end
+```
+> Warning: This function don't have exception catch.

+ 35 - 0
packages/cli/docs/src/plugin/interface/dirs.md

@@ -0,0 +1,35 @@
+# Dirs Functions
+
+> you can use Dirs functions to get some directory path
+
+
+### plugin_dir() -> string
+
+You can get current plugin **root** directory path
+
+```lua
+local path = plugin.dirs.plugin_dir()
+-- example: ~/Development/DioxusCli/plugin/test-plugin/
+```
+
+### bin_dir() -> string
+
+You can get plugin **bin** direcotry path
+
+Sometime you need install some binary file like `tailwind-cli` & `sass-cli` to help your plugin work, then you should put binary file in this directory.
+
+```lua
+local path = plugin.dirs.bin_dir()
+-- example: ~/Development/DioxusCli/plugin/test-plugin/bin/
+```
+
+### temp_dir() -> string
+
+You can get plugin **temp** direcotry path
+
+Just put some temporary file in this directory.
+
+```lua
+local path = plugin.dirs.bin_dir()
+-- example: ~/Development/DioxusCli/plugin/test-plugin/temp/
+```

+ 48 - 0
packages/cli/docs/src/plugin/interface/log.md

@@ -0,0 +1,48 @@
+# Log Functions
+
+> You can use log function to print some useful log info
+
+### Trace(info: string)
+
+Print trace log info
+
+```lua
+local log = plugin.log
+log.trace("trace information")
+```
+
+### Debug(info: string)
+
+Print debug log info
+
+```lua
+local log = plugin.log
+log.debug("debug information")
+```
+
+### Info(info: string)
+
+Print info log info
+
+```lua
+local log = plugin.log
+log.info("info information")
+```
+
+### Warn(info: string)
+
+Print warning log info
+
+```lua
+local log = plugin.log
+log.warn("warn information")
+```
+
+### Error(info: string)
+
+Print error log info
+
+```lua
+local log = plugin.log
+log.error("error information")
+```

+ 34 - 0
packages/cli/docs/src/plugin/interface/network.md

@@ -0,0 +1,34 @@
+# Network Functions
+
+> you can use Network functions to download & read some data from internet
+
+### download_file(url: string, path: string) -> boolean
+
+This function can help you download some file from url, and it will return a *boolean* value to check the download status. (true: success | false: fail)
+
+You need pass a target url and a local path (where you want to save this file)
+
+```lua
+-- this file will download to plugin temp directory
+local status = plugin.network.download_file(
+    "http://xxx.com/xxx.zip",
+    plugin.dirs.temp_dir()
+)
+if status != true then
+    log.error("Download Failed")
+end
+```
+
+### clone_repo(url: string, path: string) -> boolean
+
+This function can help you use `git clone` command (this system must have been installed git)
+
+```lua
+local status = plugin.network.clone_repo(
+    "http://github.com/mrxiaozhuox/dioxus-starter",
+    plugin.dirs.bin_dir()
+)
+if status != true then
+    log.error("Clone Failed")
+end
+```

+ 11 - 0
packages/cli/docs/src/plugin/interface/os.md

@@ -0,0 +1,11 @@
+# OS Functions
+
+> you can use OS functions to get some system information
+
+### current_platform() -> string ("windows" | "macos" | "linux")
+
+This function can help you get system & platform type:
+
+```lua
+local platform = plugin.os.current_platform()
+```

+ 35 - 0
packages/cli/docs/src/plugin/interface/path.md

@@ -0,0 +1,35 @@
+# Path Functions
+
+> you can use path functions to operate valid path string
+
+### join(path: string, extra: string) -> string
+
+This function can help you extend a path, you can extend any path, dirname or filename.
+
+```lua
+local current_path = "~/hello/dioxus"
+local new_path = plugin.path.join(current_path, "world")
+-- new_path = "~/hello/dioxus/world"
+```
+
+### parent(path: string) -> string
+
+This function will return `path` parent-path string, back to the parent.
+
+```lua
+local current_path = "~/hello/dioxus"
+local new_path = plugin.path.parent(current_path)
+-- new_path = "~/hello/"
+```
+
+### exists(path: string) -> boolean
+
+This function can check some path (dir & file) is exists.
+
+### is_file(path: string) -> boolean
+
+This function can check some path is a exist file.
+
+### is_dir(path: string) -> boolean
+
+This function can check some path is a exist dir.

+ 0 - 0
packages/cli/examples/README.md


+ 18 - 0
packages/cli/examples/plugin/init.lua

@@ -0,0 +1,18 @@
+local Api = require("./interface")
+local log = Api.log;
+
+local manager = {
+    name = "Dioxus-CLI Plugin Demo",
+    repository = "http://github.com/DioxusLabs/cli",
+    author = "YuKun Liu <mrxzx.info@gmail.com>",
+}
+
+manager.onLoad = function ()
+    log.info("plugin loaded.")
+end
+
+manager.onStartBuild = function ()
+    log.warn("system start to build")
+end
+
+return manager

+ 25 - 0
packages/cli/examples/plugin/interface.lua

@@ -0,0 +1,25 @@
+local interface = {}
+
+if plugin_logger ~= nil then
+    interface.log = plugin_logger
+else
+    interface.log = {
+        trace = function (info)
+            print("trace: " .. info)
+        end,
+        debug = function (info)
+            print("debug: " .. info)
+        end,
+        info = function (info)
+            print("info: " .. info)
+        end,
+        warn = function (info)
+            print("warn: " .. info)
+        end,
+        error = function (info)
+            print("error: " .. info)
+        end,
+    }
+end
+
+return interface

+ 20 - 0
packages/cli/extension/.eslintrc.js

@@ -0,0 +1,20 @@
+/**@type {import('eslint').Linter.Config} */
+// eslint-disable-next-line no-undef
+module.exports = {
+	root: true,
+	parser: '@typescript-eslint/parser',
+	plugins: [
+		'@typescript-eslint',
+	],
+	extends: [
+		'eslint:recommended',
+		'plugin:@typescript-eslint/recommended',
+	],
+	rules: {
+		'semi': [2, "always"],
+		'@typescript-eslint/no-unused-vars': 0,
+		'@typescript-eslint/no-explicit-any': 0,
+		'@typescript-eslint/explicit-module-boundary-types': 0,
+		'@typescript-eslint/no-non-null-assertion': 0,
+	}
+};

+ 13 - 0
packages/cli/extension/.gitignore

@@ -0,0 +1,13 @@
+.DS_Store
+npm-debug.log
+Thumbs.db
+*/node_modules/
+node_modules/
+*/out/
+out/
+*/.vs/
+.vs/
+tsconfig.lsif.json
+*.lsif
+*.db
+*.vsix

+ 10 - 0
packages/cli/extension/DEV.md

@@ -0,0 +1,10 @@
+
+## packaging
+
+```
+$ cd myExtension
+$ vsce package
+# myExtension.vsix generated
+$ vsce publish
+# <publisherID>.myExtension published to VS Code Marketplace
+```

+ 21 - 0
packages/cli/extension/LICENSE.txt

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 DioxusLabs
+
+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.

+ 14 - 0
packages/cli/extension/README.md

@@ -0,0 +1,14 @@
+# Dioxus VSCode Extension
+
+![Dioxus Logo](https://dioxuslabs.com/guide/images/dioxuslogo_full.png)
+
+This extension wraps functionality in Dioxus CLI to be used in your editor! Make sure the dioxus-cli is installed before using this extension.
+
+## Current commands:
+
+### Convert HTML to RSX
+Converts a selection of html to valid rsx.
+
+### Convert HTML to Dioxus Component
+
+Converts a selection of html to a valid Dioxus component with all SVGs factored out into their own module.

+ 2 - 0
packages/cli/extension/dist/.gitignore

@@ -0,0 +1,2 @@
+**
+!.gitignore

+ 5079 - 0
packages/cli/extension/package-lock.json

@@ -0,0 +1,5079 @@
+{
+    "name": "dioxus",
+    "version": "0.0.1",
+    "lockfileVersion": 2,
+    "requires": true,
+    "packages": {
+        "": {
+            "name": "dioxus",
+            "version": "0.0.1",
+            "license": "MIT",
+            "dependencies": {
+                "vsce": "^2.9.2"
+            },
+            "devDependencies": {
+                "@types/node": "^18.0.2",
+                "@types/vscode": "^1.68.1",
+                "@typescript-eslint/eslint-plugin": "^5.30.5",
+                "@typescript-eslint/parser": "^5.30.5",
+                "cross-env": "^7.0.3",
+                "esbuild": "^0.14.27",
+                "eslint": "^8.19.0",
+                "eslint-config-prettier": "^8.5.0",
+                "ovsx": "^0.5.1",
+                "prettier": "^2.6.2",
+                "tslib": "^2.3.0",
+                "typescript": "^4.7.4",
+                "vsce": "^2.7.0"
+            },
+            "engines": {
+                "vscode": "^1.68.1"
+            }
+        },
+        "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/@humanwhocodes/config-array": {
+            "version": "0.9.5",
+            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz",
+            "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==",
+            "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/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/@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/@types/json-schema": {
+            "version": "7.0.11",
+            "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
+            "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
+            "dev": true
+        },
+        "node_modules/@types/node": {
+            "version": "18.0.2",
+            "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.2.tgz",
+            "integrity": "sha512-b947SdS4GH+g2W33wf5FzUu1KLj5FcSIiNWbU1ZyMvt/X7w48ZsVcsQoirIgE/Oq03WT5Qbn/dkY0hePi4ZXcQ==",
+            "dev": true
+        },
+        "node_modules/@types/vscode": {
+            "version": "1.68.1",
+            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.68.1.tgz",
+            "integrity": "sha512-fXlaq13NT5yHh6yZ3c+UxXloTSk34mIvsNFYyQCeO5Po2BLFAwz7EZT4kQ43B64/aPcnAenyWy3QasrTofBOnQ==",
+            "dev": true
+        },
+        "node_modules/@typescript-eslint/eslint-plugin": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz",
+            "integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==",
+            "dev": true,
+            "dependencies": {
+                "@typescript-eslint/scope-manager": "5.30.5",
+                "@typescript-eslint/type-utils": "5.30.5",
+                "@typescript-eslint/utils": "5.30.5",
+                "debug": "^4.3.4",
+                "functional-red-black-tree": "^1.0.1",
+                "ignore": "^5.2.0",
+                "regexpp": "^3.2.0",
+                "semver": "^7.3.7",
+                "tsutils": "^3.21.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependencies": {
+                "@typescript-eslint/parser": "^5.0.0",
+                "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+            },
+            "peerDependenciesMeta": {
+                "typescript": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/@typescript-eslint/parser": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.5.tgz",
+            "integrity": "sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q==",
+            "dev": true,
+            "dependencies": {
+                "@typescript-eslint/scope-manager": "5.30.5",
+                "@typescript-eslint/types": "5.30.5",
+                "@typescript-eslint/typescript-estree": "5.30.5",
+                "debug": "^4.3.4"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependencies": {
+                "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+            },
+            "peerDependenciesMeta": {
+                "typescript": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/@typescript-eslint/scope-manager": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz",
+            "integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==",
+            "dev": true,
+            "dependencies": {
+                "@typescript-eslint/types": "5.30.5",
+                "@typescript-eslint/visitor-keys": "5.30.5"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            }
+        },
+        "node_modules/@typescript-eslint/type-utils": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz",
+            "integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==",
+            "dev": true,
+            "dependencies": {
+                "@typescript-eslint/utils": "5.30.5",
+                "debug": "^4.3.4",
+                "tsutils": "^3.21.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependencies": {
+                "eslint": "*"
+            },
+            "peerDependenciesMeta": {
+                "typescript": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/@typescript-eslint/types": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz",
+            "integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==",
+            "dev": true,
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            }
+        },
+        "node_modules/@typescript-eslint/typescript-estree": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz",
+            "integrity": "sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ==",
+            "dev": true,
+            "dependencies": {
+                "@typescript-eslint/types": "5.30.5",
+                "@typescript-eslint/visitor-keys": "5.30.5",
+                "debug": "^4.3.4",
+                "globby": "^11.1.0",
+                "is-glob": "^4.0.3",
+                "semver": "^7.3.7",
+                "tsutils": "^3.21.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependenciesMeta": {
+                "typescript": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/@typescript-eslint/utils": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.5.tgz",
+            "integrity": "sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA==",
+            "dev": true,
+            "dependencies": {
+                "@types/json-schema": "^7.0.9",
+                "@typescript-eslint/scope-manager": "5.30.5",
+                "@typescript-eslint/types": "5.30.5",
+                "@typescript-eslint/typescript-estree": "5.30.5",
+                "eslint-scope": "^5.1.1",
+                "eslint-utils": "^3.0.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependencies": {
+                "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+            }
+        },
+        "node_modules/@typescript-eslint/visitor-keys": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz",
+            "integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==",
+            "dev": true,
+            "dependencies": {
+                "@typescript-eslint/types": "5.30.5",
+                "eslint-visitor-keys": "^3.3.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            }
+        },
+        "node_modules/acorn": {
+            "version": "8.7.1",
+            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
+            "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
+            "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/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-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/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/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/azure-devops-node-api": {
+            "version": "11.1.1",
+            "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.1.tgz",
+            "integrity": "sha512-XDG91XzLZ15reP12s3jFkKS8oiagSICjnLwxEYieme4+4h3ZveFOFRA4iYIG40RyHXsiI0mefFYYMFIJbMpWcg==",
+            "dev": true,
+            "dependencies": {
+                "tunnel": "0.0.6",
+                "typed-rest-client": "^1.8.4"
+            }
+        },
+        "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/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/bl": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+            "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+            "dev": true,
+            "dependencies": {
+                "buffer": "^5.5.0",
+                "inherits": "^2.0.4",
+                "readable-stream": "^3.4.0"
+            }
+        },
+        "node_modules/boolbase": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+            "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+            "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": "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/buffer": {
+            "version": "5.7.1",
+            "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+            "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+            "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": {
+                "base64-js": "^1.3.1",
+                "ieee754": "^1.1.13"
+            }
+        },
+        "node_modules/buffer-crc32": {
+            "version": "0.2.13",
+            "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+            "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+            "dev": true,
+            "engines": {
+                "node": "*"
+            }
+        },
+        "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/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/cheerio": {
+            "version": "1.0.0-rc.12",
+            "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
+            "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
+            "dev": true,
+            "dependencies": {
+                "cheerio-select": "^2.1.0",
+                "dom-serializer": "^2.0.0",
+                "domhandler": "^5.0.3",
+                "domutils": "^3.0.1",
+                "htmlparser2": "^8.0.1",
+                "parse5": "^7.0.0",
+                "parse5-htmlparser2-tree-adapter": "^7.0.0"
+            },
+            "engines": {
+                "node": ">= 6"
+            },
+            "funding": {
+                "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+            }
+        },
+        "node_modules/cheerio-select": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+            "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+            "dev": true,
+            "dependencies": {
+                "boolbase": "^1.0.0",
+                "css-select": "^5.1.0",
+                "css-what": "^6.1.0",
+                "domelementtype": "^2.3.0",
+                "domhandler": "^5.0.3",
+                "domutils": "^3.0.1"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/fb55"
+            }
+        },
+        "node_modules/chownr": {
+            "version": "1.1.4",
+            "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+            "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+            "dev": true
+        },
+        "node_modules/ci-info": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+            "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+            "dev": true
+        },
+        "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/commander": {
+            "version": "6.2.1",
+            "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+            "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+            "dev": true,
+            "engines": {
+                "node": ">= 6"
+            }
+        },
+        "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/cross-env": {
+            "version": "7.0.3",
+            "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
+            "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
+            "dev": true,
+            "dependencies": {
+                "cross-spawn": "^7.0.1"
+            },
+            "bin": {
+                "cross-env": "src/bin/cross-env.js",
+                "cross-env-shell": "src/bin/cross-env-shell.js"
+            },
+            "engines": {
+                "node": ">=10.14",
+                "npm": ">=6",
+                "yarn": ">=1"
+            }
+        },
+        "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/css-select": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
+            "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
+            "dev": true,
+            "dependencies": {
+                "boolbase": "^1.0.0",
+                "css-what": "^6.1.0",
+                "domhandler": "^5.0.2",
+                "domutils": "^3.0.1",
+                "nth-check": "^2.0.1"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/fb55"
+            }
+        },
+        "node_modules/css-what": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+            "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+            "dev": true,
+            "engines": {
+                "node": ">= 6"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/fb55"
+            }
+        },
+        "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/decompress-response": {
+            "version": "6.0.0",
+            "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+            "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+            "dev": true,
+            "dependencies": {
+                "mimic-response": "^3.1.0"
+            },
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "node_modules/deep-extend": {
+            "version": "0.6.0",
+            "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+            "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+            "dev": true,
+            "engines": {
+                "node": ">=4.0.0"
+            }
+        },
+        "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/detect-libc": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
+            "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==",
+            "dev": true,
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "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/dom-serializer": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+            "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+            "dev": true,
+            "dependencies": {
+                "domelementtype": "^2.3.0",
+                "domhandler": "^5.0.2",
+                "entities": "^4.2.0"
+            },
+            "funding": {
+                "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+            }
+        },
+        "node_modules/domelementtype": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+            "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+            "dev": true,
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/fb55"
+                }
+            ]
+        },
+        "node_modules/domhandler": {
+            "version": "5.0.3",
+            "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+            "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+            "dev": true,
+            "dependencies": {
+                "domelementtype": "^2.3.0"
+            },
+            "engines": {
+                "node": ">= 4"
+            },
+            "funding": {
+                "url": "https://github.com/fb55/domhandler?sponsor=1"
+            }
+        },
+        "node_modules/domutils": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
+            "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
+            "dev": true,
+            "dependencies": {
+                "dom-serializer": "^2.0.0",
+                "domelementtype": "^2.3.0",
+                "domhandler": "^5.0.1"
+            },
+            "funding": {
+                "url": "https://github.com/fb55/domutils?sponsor=1"
+            }
+        },
+        "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": "4.3.1",
+            "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz",
+            "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==",
+            "dev": true,
+            "engines": {
+                "node": ">=0.12"
+            },
+            "funding": {
+                "url": "https://github.com/fb55/entities?sponsor=1"
+            }
+        },
+        "node_modules/esbuild": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz",
+            "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==",
+            "dev": true,
+            "hasInstallScript": true,
+            "bin": {
+                "esbuild": "bin/esbuild"
+            },
+            "engines": {
+                "node": ">=12"
+            },
+            "optionalDependencies": {
+                "esbuild-android-64": "0.14.48",
+                "esbuild-android-arm64": "0.14.48",
+                "esbuild-darwin-64": "0.14.48",
+                "esbuild-darwin-arm64": "0.14.48",
+                "esbuild-freebsd-64": "0.14.48",
+                "esbuild-freebsd-arm64": "0.14.48",
+                "esbuild-linux-32": "0.14.48",
+                "esbuild-linux-64": "0.14.48",
+                "esbuild-linux-arm": "0.14.48",
+                "esbuild-linux-arm64": "0.14.48",
+                "esbuild-linux-mips64le": "0.14.48",
+                "esbuild-linux-ppc64le": "0.14.48",
+                "esbuild-linux-riscv64": "0.14.48",
+                "esbuild-linux-s390x": "0.14.48",
+                "esbuild-netbsd-64": "0.14.48",
+                "esbuild-openbsd-64": "0.14.48",
+                "esbuild-sunos-64": "0.14.48",
+                "esbuild-windows-32": "0.14.48",
+                "esbuild-windows-64": "0.14.48",
+                "esbuild-windows-arm64": "0.14.48"
+            }
+        },
+        "node_modules/esbuild-android-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz",
+            "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "android"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-android-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz",
+            "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "android"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-darwin-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz",
+            "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-darwin-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz",
+            "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-freebsd-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz",
+            "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "freebsd"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-freebsd-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz",
+            "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "freebsd"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-linux-32": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz",
+            "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==",
+            "cpu": [
+                "ia32"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-linux-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz",
+            "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-linux-arm": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz",
+            "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-linux-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz",
+            "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-linux-mips64le": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz",
+            "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==",
+            "cpu": [
+                "mips64el"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-linux-ppc64le": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz",
+            "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==",
+            "cpu": [
+                "ppc64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-linux-riscv64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz",
+            "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==",
+            "cpu": [
+                "riscv64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-linux-s390x": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz",
+            "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==",
+            "cpu": [
+                "s390x"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-netbsd-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz",
+            "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "netbsd"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-openbsd-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz",
+            "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "openbsd"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-sunos-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz",
+            "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "sunos"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-windows-32": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz",
+            "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==",
+            "cpu": [
+                "ia32"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-windows-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz",
+            "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/esbuild-windows-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz",
+            "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "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/eslint": {
+            "version": "8.19.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz",
+            "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==",
+            "dev": true,
+            "dependencies": {
+                "@eslint/eslintrc": "^1.3.0",
+                "@humanwhocodes/config-array": "^0.9.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.2",
+                "esquery": "^1.4.0",
+                "esutils": "^2.0.2",
+                "fast-deep-equal": "^3.1.3",
+                "file-entry-cache": "^6.0.1",
+                "functional-red-black-tree": "^1.0.1",
+                "glob-parent": "^6.0.1",
+                "globals": "^13.15.0",
+                "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-config-prettier": {
+            "version": "8.5.0",
+            "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
+            "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
+            "dev": true,
+            "bin": {
+                "eslint-config-prettier": "bin/cli.js"
+            },
+            "peerDependencies": {
+                "eslint": ">=7.0.0"
+            }
+        },
+        "node_modules/eslint-scope": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+            "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+            "dev": true,
+            "dependencies": {
+                "esrecurse": "^4.3.0",
+                "estraverse": "^4.1.1"
+            },
+            "engines": {
+                "node": ">=8.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/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/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/espree": {
+            "version": "9.3.2",
+            "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz",
+            "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==",
+            "dev": true,
+            "dependencies": {
+                "acorn": "^8.7.1",
+                "acorn-jsx": "^5.3.2",
+                "eslint-visitor-keys": "^3.3.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            }
+        },
+        "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/esquery/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/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/esrecurse/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/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/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/expand-template": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+            "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+            "dev": true,
+            "engines": {
+                "node": ">=6"
+            }
+        },
+        "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/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/fd-slicer": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+            "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+            "dev": true,
+            "dependencies": {
+                "pend": "~1.2.0"
+            }
+        },
+        "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/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/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.6",
+            "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz",
+            "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==",
+            "dev": true
+        },
+        "node_modules/follow-redirects": {
+            "version": "1.15.1",
+            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
+            "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
+            "dev": true,
+            "funding": [
+                {
+                    "type": "individual",
+                    "url": "https://github.com/sponsors/RubenVerborgh"
+                }
+            ],
+            "engines": {
+                "node": ">=4.0"
+            },
+            "peerDependenciesMeta": {
+                "debug": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/fs-constants": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+            "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+            "dev": true
+        },
+        "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/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/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/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/github-from-package": {
+            "version": "0.0.0",
+            "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+            "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
+            "dev": true
+        },
+        "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/globals": {
+            "version": "13.16.0",
+            "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz",
+            "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==",
+            "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/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-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-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/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/htmlparser2": {
+            "version": "8.0.1",
+            "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
+            "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
+            "dev": true,
+            "funding": [
+                "https://github.com/fb55/htmlparser2?sponsor=1",
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/fb55"
+                }
+            ],
+            "dependencies": {
+                "domelementtype": "^2.3.0",
+                "domhandler": "^5.0.2",
+                "domutils": "^3.0.1",
+                "entities": "^4.3.0"
+            }
+        },
+        "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/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/is-ci": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+            "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+            "dev": true,
+            "dependencies": {
+                "ci-info": "^2.0.0"
+            },
+            "bin": {
+                "is-ci": "bin.js"
+            }
+        },
+        "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-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-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/isexe": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+            "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+            "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/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/keytar": {
+            "version": "7.9.0",
+            "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
+            "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==",
+            "dev": true,
+            "hasInstallScript": true,
+            "dependencies": {
+                "node-addon-api": "^4.3.0",
+                "prebuild-install": "^7.0.1"
+            }
+        },
+        "node_modules/leven": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+            "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+            "dev": true,
+            "engines": {
+                "node": ">=6"
+            }
+        },
+        "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/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/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/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/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/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/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/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/mime": {
+            "version": "1.6.0",
+            "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+            "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+            "dev": true,
+            "bin": {
+                "mime": "cli.js"
+            },
+            "engines": {
+                "node": ">=4"
+            }
+        },
+        "node_modules/mimic-response": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+            "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+            "dev": true,
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "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/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/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-stream": {
+            "version": "0.0.8",
+            "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+            "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+            "dev": true
+        },
+        "node_modules/napi-build-utils": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
+            "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
+            "dev": true
+        },
+        "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/node-abi": {
+            "version": "3.22.0",
+            "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz",
+            "integrity": "sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==",
+            "dev": true,
+            "dependencies": {
+                "semver": "^7.3.5"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/node-addon-api": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
+            "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
+            "dev": true
+        },
+        "node_modules/nth-check": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+            "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+            "dev": true,
+            "dependencies": {
+                "boolbase": "^1.0.0"
+            },
+            "funding": {
+                "url": "https://github.com/fb55/nth-check?sponsor=1"
+            }
+        },
+        "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/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.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/ovsx": {
+            "version": "0.5.1",
+            "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.1.tgz",
+            "integrity": "sha512-3OWq0l7DuVHi2bd2aQe5+QVQlFIqvrcw3/2vGXL404L6Tr+R4QHtzfnYYghv8CCa85xJHjU0RhcaC7pyXkAUbg==",
+            "dev": true,
+            "dependencies": {
+                "commander": "^6.1.0",
+                "follow-redirects": "^1.14.6",
+                "is-ci": "^2.0.0",
+                "leven": "^3.1.0",
+                "tmp": "^0.2.1",
+                "vsce": "^2.6.3"
+            },
+            "bin": {
+                "ovsx": "lib/ovsx"
+            },
+            "engines": {
+                "node": ">= 14"
+            }
+        },
+        "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/parse-semver": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
+            "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==",
+            "dev": true,
+            "dependencies": {
+                "semver": "^5.1.0"
+            }
+        },
+        "node_modules/parse-semver/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/parse5": {
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz",
+            "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==",
+            "dev": true,
+            "dependencies": {
+                "entities": "^4.3.0"
+            },
+            "funding": {
+                "url": "https://github.com/inikulin/parse5?sponsor=1"
+            }
+        },
+        "node_modules/parse5-htmlparser2-tree-adapter": {
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
+            "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
+            "dev": true,
+            "dependencies": {
+                "domhandler": "^5.0.2",
+                "parse5": "^7.0.0"
+            },
+            "funding": {
+                "url": "https://github.com/inikulin/parse5?sponsor=1"
+            }
+        },
+        "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-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/pend": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+            "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+            "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/prebuild-install": {
+            "version": "7.1.1",
+            "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz",
+            "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==",
+            "dev": true,
+            "dependencies": {
+                "detect-libc": "^2.0.0",
+                "expand-template": "^2.0.3",
+                "github-from-package": "0.0.0",
+                "minimist": "^1.2.3",
+                "mkdirp-classic": "^0.5.3",
+                "napi-build-utils": "^1.0.1",
+                "node-abi": "^3.3.0",
+                "pump": "^3.0.0",
+                "rc": "^1.2.7",
+                "simple-get": "^4.0.0",
+                "tar-fs": "^2.0.0",
+                "tunnel-agent": "^0.6.0"
+            },
+            "bin": {
+                "prebuild-install": "bin.js"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "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/prettier": {
+            "version": "2.7.1",
+            "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
+            "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
+            "dev": true,
+            "bin": {
+                "prettier": "bin-prettier.js"
+            },
+            "engines": {
+                "node": ">=10.13.0"
+            },
+            "funding": {
+                "url": "https://github.com/prettier/prettier?sponsor=1"
+            }
+        },
+        "node_modules/pump": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+            "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+            "dev": true,
+            "dependencies": {
+                "end-of-stream": "^1.1.0",
+                "once": "^1.3.1"
+            }
+        },
+        "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/qs": {
+            "version": "6.11.0",
+            "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+            "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+            "dev": true,
+            "dependencies": {
+                "side-channel": "^1.0.4"
+            },
+            "engines": {
+                "node": ">=0.6"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "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/rc": {
+            "version": "1.2.8",
+            "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+            "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+            "dev": true,
+            "dependencies": {
+                "deep-extend": "^0.6.0",
+                "ini": "~1.3.0",
+                "minimist": "^1.2.0",
+                "strip-json-comments": "~2.0.1"
+            },
+            "bin": {
+                "rc": "cli.js"
+            }
+        },
+        "node_modules/rc/node_modules/strip-json-comments": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+            "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+            "dev": true,
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/read": {
+            "version": "1.0.7",
+            "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
+            "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==",
+            "dev": true,
+            "dependencies": {
+                "mute-stream": "~0.0.4"
+            },
+            "engines": {
+                "node": ">=0.8"
+            }
+        },
+        "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/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/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/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/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/sax": {
+            "version": "1.2.4",
+            "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+            "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+            "dev": true
+        },
+        "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/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/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/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/simple-get": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+            "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+            "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": {
+                "decompress-response": "^6.0.0",
+                "once": "^1.3.1",
+                "simple-concat": "^1.0.0"
+            }
+        },
+        "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/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/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-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/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/tar-fs": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
+            "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+            "dev": true,
+            "dependencies": {
+                "chownr": "^1.1.1",
+                "mkdirp-classic": "^0.5.2",
+                "pump": "^3.0.0",
+                "tar-stream": "^2.1.4"
+            }
+        },
+        "node_modules/tar-stream": {
+            "version": "2.2.0",
+            "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+            "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+            "dev": true,
+            "dependencies": {
+                "bl": "^4.0.3",
+                "end-of-stream": "^1.4.1",
+                "fs-constants": "^1.0.0",
+                "inherits": "^2.0.3",
+                "readable-stream": "^3.1.1"
+            },
+            "engines": {
+                "node": ">=6"
+            }
+        },
+        "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/tmp": {
+            "version": "0.2.1",
+            "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+            "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+            "dev": true,
+            "dependencies": {
+                "rimraf": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=8.17.0"
+            }
+        },
+        "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/tslib": {
+            "version": "2.4.0",
+            "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+            "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
+            "dev": true
+        },
+        "node_modules/tsutils": {
+            "version": "3.21.0",
+            "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+            "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+            "dev": true,
+            "dependencies": {
+                "tslib": "^1.8.1"
+            },
+            "engines": {
+                "node": ">= 6"
+            },
+            "peerDependencies": {
+                "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+            }
+        },
+        "node_modules/tsutils/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/tunnel": {
+            "version": "0.0.6",
+            "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+            "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+            "dev": true,
+            "engines": {
+                "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
+            }
+        },
+        "node_modules/tunnel-agent": {
+            "version": "0.6.0",
+            "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+            "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+            "dev": true,
+            "dependencies": {
+                "safe-buffer": "^5.0.1"
+            },
+            "engines": {
+                "node": "*"
+            }
+        },
+        "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/typed-rest-client": {
+            "version": "1.8.9",
+            "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz",
+            "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==",
+            "dev": true,
+            "dependencies": {
+                "qs": "^6.9.1",
+                "tunnel": "0.0.6",
+                "underscore": "^1.12.1"
+            }
+        },
+        "node_modules/typescript": {
+            "version": "4.7.4",
+            "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
+            "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
+            "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/underscore": {
+            "version": "1.13.4",
+            "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz",
+            "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==",
+            "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/url-join": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
+            "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
+            "dev": true
+        },
+        "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/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/vsce": {
+            "version": "2.9.2",
+            "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.9.2.tgz",
+            "integrity": "sha512-xyLqL4U82BilUX1t6Ym2opQEa2tLGWYjbgB7+ETeNVXlIJz5sWBJjQJSYJVFOKJSpiOtQclolu88cj7oY6vvPQ==",
+            "dev": true,
+            "dependencies": {
+                "azure-devops-node-api": "^11.0.1",
+                "chalk": "^2.4.2",
+                "cheerio": "^1.0.0-rc.9",
+                "commander": "^6.1.0",
+                "glob": "^7.0.6",
+                "hosted-git-info": "^4.0.2",
+                "keytar": "^7.7.0",
+                "leven": "^3.1.0",
+                "markdown-it": "^12.3.2",
+                "mime": "^1.3.4",
+                "minimatch": "^3.0.3",
+                "parse-semver": "^1.1.1",
+                "read": "^1.0.7",
+                "semver": "^5.1.0",
+                "tmp": "^0.2.1",
+                "typed-rest-client": "^1.8.4",
+                "url-join": "^4.0.1",
+                "xml2js": "^0.4.23",
+                "yauzl": "^2.3.1",
+                "yazl": "^2.2.2"
+            },
+            "bin": {
+                "vsce": "vsce"
+            },
+            "engines": {
+                "node": ">= 14"
+            }
+        },
+        "node_modules/vsce/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/vsce/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/vsce/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/vsce/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/vsce/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/vsce/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/vsce/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/vsce/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/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/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/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/xml2js": {
+            "version": "0.4.23",
+            "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+            "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+            "dev": true,
+            "dependencies": {
+                "sax": ">=0.6.0",
+                "xmlbuilder": "~11.0.0"
+            },
+            "engines": {
+                "node": ">=4.0.0"
+            }
+        },
+        "node_modules/xmlbuilder": {
+            "version": "11.0.1",
+            "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+            "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+            "dev": true,
+            "engines": {
+                "node": ">=4.0"
+            }
+        },
+        "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/yauzl": {
+            "version": "2.10.0",
+            "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+            "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+            "dev": true,
+            "dependencies": {
+                "buffer-crc32": "~0.2.3",
+                "fd-slicer": "~1.1.0"
+            }
+        },
+        "node_modules/yazl": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
+            "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==",
+            "dev": true,
+            "dependencies": {
+                "buffer-crc32": "~0.2.3"
+            }
+        }
+    },
+    "dependencies": {
+        "@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"
+            }
+        },
+        "@humanwhocodes/config-array": {
+            "version": "0.9.5",
+            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz",
+            "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==",
+            "dev": true,
+            "requires": {
+                "@humanwhocodes/object-schema": "^1.2.1",
+                "debug": "^4.1.1",
+                "minimatch": "^3.0.4"
+            }
+        },
+        "@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
+        },
+        "@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"
+            }
+        },
+        "@types/json-schema": {
+            "version": "7.0.11",
+            "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
+            "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
+            "dev": true
+        },
+        "@types/node": {
+            "version": "18.0.2",
+            "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.2.tgz",
+            "integrity": "sha512-b947SdS4GH+g2W33wf5FzUu1KLj5FcSIiNWbU1ZyMvt/X7w48ZsVcsQoirIgE/Oq03WT5Qbn/dkY0hePi4ZXcQ==",
+            "dev": true
+        },
+        "@types/vscode": {
+            "version": "1.68.1",
+            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.68.1.tgz",
+            "integrity": "sha512-fXlaq13NT5yHh6yZ3c+UxXloTSk34mIvsNFYyQCeO5Po2BLFAwz7EZT4kQ43B64/aPcnAenyWy3QasrTofBOnQ==",
+            "dev": true
+        },
+        "@typescript-eslint/eslint-plugin": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz",
+            "integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/scope-manager": "5.30.5",
+                "@typescript-eslint/type-utils": "5.30.5",
+                "@typescript-eslint/utils": "5.30.5",
+                "debug": "^4.3.4",
+                "functional-red-black-tree": "^1.0.1",
+                "ignore": "^5.2.0",
+                "regexpp": "^3.2.0",
+                "semver": "^7.3.7",
+                "tsutils": "^3.21.0"
+            }
+        },
+        "@typescript-eslint/parser": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.5.tgz",
+            "integrity": "sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/scope-manager": "5.30.5",
+                "@typescript-eslint/types": "5.30.5",
+                "@typescript-eslint/typescript-estree": "5.30.5",
+                "debug": "^4.3.4"
+            }
+        },
+        "@typescript-eslint/scope-manager": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz",
+            "integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/types": "5.30.5",
+                "@typescript-eslint/visitor-keys": "5.30.5"
+            }
+        },
+        "@typescript-eslint/type-utils": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz",
+            "integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/utils": "5.30.5",
+                "debug": "^4.3.4",
+                "tsutils": "^3.21.0"
+            }
+        },
+        "@typescript-eslint/types": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz",
+            "integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==",
+            "dev": true
+        },
+        "@typescript-eslint/typescript-estree": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz",
+            "integrity": "sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/types": "5.30.5",
+                "@typescript-eslint/visitor-keys": "5.30.5",
+                "debug": "^4.3.4",
+                "globby": "^11.1.0",
+                "is-glob": "^4.0.3",
+                "semver": "^7.3.7",
+                "tsutils": "^3.21.0"
+            }
+        },
+        "@typescript-eslint/utils": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.5.tgz",
+            "integrity": "sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA==",
+            "dev": true,
+            "requires": {
+                "@types/json-schema": "^7.0.9",
+                "@typescript-eslint/scope-manager": "5.30.5",
+                "@typescript-eslint/types": "5.30.5",
+                "@typescript-eslint/typescript-estree": "5.30.5",
+                "eslint-scope": "^5.1.1",
+                "eslint-utils": "^3.0.0"
+            }
+        },
+        "@typescript-eslint/visitor-keys": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz",
+            "integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/types": "5.30.5",
+                "eslint-visitor-keys": "^3.3.0"
+            }
+        },
+        "acorn": {
+            "version": "8.7.1",
+            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
+            "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
+            "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": {}
+        },
+        "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-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"
+            }
+        },
+        "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
+        },
+        "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
+        },
+        "azure-devops-node-api": {
+            "version": "11.1.1",
+            "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.1.tgz",
+            "integrity": "sha512-XDG91XzLZ15reP12s3jFkKS8oiagSICjnLwxEYieme4+4h3ZveFOFRA4iYIG40RyHXsiI0mefFYYMFIJbMpWcg==",
+            "dev": true,
+            "requires": {
+                "tunnel": "0.0.6",
+                "typed-rest-client": "^1.8.4"
+            }
+        },
+        "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
+        },
+        "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
+        },
+        "bl": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+            "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+            "dev": true,
+            "requires": {
+                "buffer": "^5.5.0",
+                "inherits": "^2.0.4",
+                "readable-stream": "^3.4.0"
+            }
+        },
+        "boolbase": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+            "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+            "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": "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"
+            }
+        },
+        "buffer": {
+            "version": "5.7.1",
+            "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+            "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+            "dev": true,
+            "requires": {
+                "base64-js": "^1.3.1",
+                "ieee754": "^1.1.13"
+            }
+        },
+        "buffer-crc32": {
+            "version": "0.2.13",
+            "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+            "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+            "dev": true
+        },
+        "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
+        },
+        "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"
+            }
+        },
+        "cheerio": {
+            "version": "1.0.0-rc.12",
+            "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
+            "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
+            "dev": true,
+            "requires": {
+                "cheerio-select": "^2.1.0",
+                "dom-serializer": "^2.0.0",
+                "domhandler": "^5.0.3",
+                "domutils": "^3.0.1",
+                "htmlparser2": "^8.0.1",
+                "parse5": "^7.0.0",
+                "parse5-htmlparser2-tree-adapter": "^7.0.0"
+            }
+        },
+        "cheerio-select": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+            "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+            "dev": true,
+            "requires": {
+                "boolbase": "^1.0.0",
+                "css-select": "^5.1.0",
+                "css-what": "^6.1.0",
+                "domelementtype": "^2.3.0",
+                "domhandler": "^5.0.3",
+                "domutils": "^3.0.1"
+            }
+        },
+        "chownr": {
+            "version": "1.1.4",
+            "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+            "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+            "dev": true
+        },
+        "ci-info": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+            "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+            "dev": true
+        },
+        "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
+        },
+        "commander": {
+            "version": "6.2.1",
+            "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+            "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+            "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
+        },
+        "cross-env": {
+            "version": "7.0.3",
+            "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
+            "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
+            "dev": true,
+            "requires": {
+                "cross-spawn": "^7.0.1"
+            }
+        },
+        "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"
+            }
+        },
+        "css-select": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
+            "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
+            "dev": true,
+            "requires": {
+                "boolbase": "^1.0.0",
+                "css-what": "^6.1.0",
+                "domhandler": "^5.0.2",
+                "domutils": "^3.0.1",
+                "nth-check": "^2.0.1"
+            }
+        },
+        "css-what": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+            "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+            "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"
+            }
+        },
+        "decompress-response": {
+            "version": "6.0.0",
+            "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+            "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+            "dev": true,
+            "requires": {
+                "mimic-response": "^3.1.0"
+            }
+        },
+        "deep-extend": {
+            "version": "0.6.0",
+            "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+            "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+            "dev": true
+        },
+        "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
+        },
+        "detect-libc": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
+            "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==",
+            "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"
+            }
+        },
+        "dom-serializer": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+            "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+            "dev": true,
+            "requires": {
+                "domelementtype": "^2.3.0",
+                "domhandler": "^5.0.2",
+                "entities": "^4.2.0"
+            }
+        },
+        "domelementtype": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+            "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+            "dev": true
+        },
+        "domhandler": {
+            "version": "5.0.3",
+            "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+            "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+            "dev": true,
+            "requires": {
+                "domelementtype": "^2.3.0"
+            }
+        },
+        "domutils": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
+            "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
+            "dev": true,
+            "requires": {
+                "dom-serializer": "^2.0.0",
+                "domelementtype": "^2.3.0",
+                "domhandler": "^5.0.1"
+            }
+        },
+        "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": "4.3.1",
+            "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz",
+            "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==",
+            "dev": true
+        },
+        "esbuild": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz",
+            "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==",
+            "dev": true,
+            "requires": {
+                "esbuild-android-64": "0.14.48",
+                "esbuild-android-arm64": "0.14.48",
+                "esbuild-darwin-64": "0.14.48",
+                "esbuild-darwin-arm64": "0.14.48",
+                "esbuild-freebsd-64": "0.14.48",
+                "esbuild-freebsd-arm64": "0.14.48",
+                "esbuild-linux-32": "0.14.48",
+                "esbuild-linux-64": "0.14.48",
+                "esbuild-linux-arm": "0.14.48",
+                "esbuild-linux-arm64": "0.14.48",
+                "esbuild-linux-mips64le": "0.14.48",
+                "esbuild-linux-ppc64le": "0.14.48",
+                "esbuild-linux-riscv64": "0.14.48",
+                "esbuild-linux-s390x": "0.14.48",
+                "esbuild-netbsd-64": "0.14.48",
+                "esbuild-openbsd-64": "0.14.48",
+                "esbuild-sunos-64": "0.14.48",
+                "esbuild-windows-32": "0.14.48",
+                "esbuild-windows-64": "0.14.48",
+                "esbuild-windows-arm64": "0.14.48"
+            }
+        },
+        "esbuild-android-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz",
+            "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-android-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz",
+            "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-darwin-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz",
+            "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-darwin-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz",
+            "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-freebsd-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz",
+            "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-freebsd-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz",
+            "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-32": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz",
+            "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz",
+            "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-arm": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz",
+            "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz",
+            "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-mips64le": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz",
+            "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-ppc64le": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz",
+            "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-riscv64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz",
+            "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-s390x": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz",
+            "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-netbsd-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz",
+            "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-openbsd-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz",
+            "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-sunos-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz",
+            "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-windows-32": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz",
+            "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-windows-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz",
+            "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-windows-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz",
+            "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==",
+            "dev": true,
+            "optional": 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
+        },
+        "eslint": {
+            "version": "8.19.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz",
+            "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==",
+            "dev": true,
+            "requires": {
+                "@eslint/eslintrc": "^1.3.0",
+                "@humanwhocodes/config-array": "^0.9.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.2",
+                "esquery": "^1.4.0",
+                "esutils": "^2.0.2",
+                "fast-deep-equal": "^3.1.3",
+                "file-entry-cache": "^6.0.1",
+                "functional-red-black-tree": "^1.0.1",
+                "glob-parent": "^6.0.1",
+                "globals": "^13.15.0",
+                "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": {
+                "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"
+                    }
+                },
+                "estraverse": {
+                    "version": "5.3.0",
+                    "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+                    "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+                    "dev": true
+                }
+            }
+        },
+        "eslint-config-prettier": {
+            "version": "8.5.0",
+            "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
+            "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
+            "dev": true,
+            "requires": {}
+        },
+        "eslint-scope": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+            "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+            "dev": true,
+            "requires": {
+                "esrecurse": "^4.3.0",
+                "estraverse": "^4.1.1"
+            }
+        },
+        "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.3.2",
+            "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz",
+            "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==",
+            "dev": true,
+            "requires": {
+                "acorn": "^8.7.1",
+                "acorn-jsx": "^5.3.2",
+                "eslint-visitor-keys": "^3.3.0"
+            }
+        },
+        "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"
+            },
+            "dependencies": {
+                "estraverse": {
+                    "version": "5.3.0",
+                    "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+                    "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+                    "dev": true
+                }
+            }
+        },
+        "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"
+            },
+            "dependencies": {
+                "estraverse": {
+                    "version": "5.3.0",
+                    "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+                    "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+                    "dev": true
+                }
+            }
+        },
+        "estraverse": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+            "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+            "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
+        },
+        "expand-template": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+            "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+            "dev": true
+        },
+        "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
+        },
+        "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"
+            }
+        },
+        "fd-slicer": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+            "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+            "dev": true,
+            "requires": {
+                "pend": "~1.2.0"
+            }
+        },
+        "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"
+            }
+        },
+        "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"
+            }
+        },
+        "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.6",
+            "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz",
+            "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==",
+            "dev": true
+        },
+        "follow-redirects": {
+            "version": "1.15.1",
+            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
+            "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
+            "dev": true
+        },
+        "fs-constants": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+            "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+            "dev": true
+        },
+        "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
+        },
+        "function-bind": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+            "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+            "dev": true
+        },
+        "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
+        },
+        "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"
+            }
+        },
+        "github-from-package": {
+            "version": "0.0.0",
+            "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+            "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
+            "dev": true
+        },
+        "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"
+            }
+        },
+        "globals": {
+            "version": "13.16.0",
+            "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz",
+            "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==",
+            "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"
+            }
+        },
+        "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-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-symbols": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+            "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+            "dev": true
+        },
+        "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"
+            }
+        },
+        "htmlparser2": {
+            "version": "8.0.1",
+            "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
+            "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
+            "dev": true,
+            "requires": {
+                "domelementtype": "^2.3.0",
+                "domhandler": "^5.0.2",
+                "domutils": "^3.0.1",
+                "entities": "^4.3.0"
+            }
+        },
+        "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
+        },
+        "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
+        },
+        "is-ci": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+            "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+            "dev": true,
+            "requires": {
+                "ci-info": "^2.0.0"
+            }
+        },
+        "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-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-number": {
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+            "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+            "dev": true
+        },
+        "isexe": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+            "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+            "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"
+            }
+        },
+        "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
+        },
+        "keytar": {
+            "version": "7.9.0",
+            "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
+            "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==",
+            "dev": true,
+            "requires": {
+                "node-addon-api": "^4.3.0",
+                "prebuild-install": "^7.0.1"
+            }
+        },
+        "leven": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+            "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+            "dev": true
+        },
+        "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"
+            }
+        },
+        "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"
+            }
+        },
+        "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
+        },
+        "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"
+            }
+        },
+        "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"
+            },
+            "dependencies": {
+                "entities": {
+                    "version": "2.1.0",
+                    "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+                    "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+                    "dev": true
+                }
+            }
+        },
+        "mdurl": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+            "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
+            "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"
+            }
+        },
+        "mime": {
+            "version": "1.6.0",
+            "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+            "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+            "dev": true
+        },
+        "mimic-response": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+            "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+            "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
+        },
+        "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
+        },
+        "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-stream": {
+            "version": "0.0.8",
+            "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+            "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+            "dev": true
+        },
+        "napi-build-utils": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
+            "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
+            "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
+        },
+        "node-abi": {
+            "version": "3.22.0",
+            "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz",
+            "integrity": "sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==",
+            "dev": true,
+            "requires": {
+                "semver": "^7.3.5"
+            }
+        },
+        "node-addon-api": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
+            "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
+            "dev": true
+        },
+        "nth-check": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+            "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+            "dev": true,
+            "requires": {
+                "boolbase": "^1.0.0"
+            }
+        },
+        "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
+        },
+        "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.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"
+            }
+        },
+        "ovsx": {
+            "version": "0.5.1",
+            "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.1.tgz",
+            "integrity": "sha512-3OWq0l7DuVHi2bd2aQe5+QVQlFIqvrcw3/2vGXL404L6Tr+R4QHtzfnYYghv8CCa85xJHjU0RhcaC7pyXkAUbg==",
+            "dev": true,
+            "requires": {
+                "commander": "^6.1.0",
+                "follow-redirects": "^1.14.6",
+                "is-ci": "^2.0.0",
+                "leven": "^3.1.0",
+                "tmp": "^0.2.1",
+                "vsce": "^2.6.3"
+            }
+        },
+        "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"
+            }
+        },
+        "parse-semver": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
+            "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==",
+            "dev": true,
+            "requires": {
+                "semver": "^5.1.0"
+            },
+            "dependencies": {
+                "semver": {
+                    "version": "5.7.1",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+                    "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+                    "dev": true
+                }
+            }
+        },
+        "parse5": {
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz",
+            "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==",
+            "dev": true,
+            "requires": {
+                "entities": "^4.3.0"
+            }
+        },
+        "parse5-htmlparser2-tree-adapter": {
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
+            "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
+            "dev": true,
+            "requires": {
+                "domhandler": "^5.0.2",
+                "parse5": "^7.0.0"
+            }
+        },
+        "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-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
+        },
+        "pend": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+            "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+            "dev": true
+        },
+        "picomatch": {
+            "version": "2.3.1",
+            "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+            "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+            "dev": true
+        },
+        "prebuild-install": {
+            "version": "7.1.1",
+            "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz",
+            "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==",
+            "dev": true,
+            "requires": {
+                "detect-libc": "^2.0.0",
+                "expand-template": "^2.0.3",
+                "github-from-package": "0.0.0",
+                "minimist": "^1.2.3",
+                "mkdirp-classic": "^0.5.3",
+                "napi-build-utils": "^1.0.1",
+                "node-abi": "^3.3.0",
+                "pump": "^3.0.0",
+                "rc": "^1.2.7",
+                "simple-get": "^4.0.0",
+                "tar-fs": "^2.0.0",
+                "tunnel-agent": "^0.6.0"
+            }
+        },
+        "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
+        },
+        "prettier": {
+            "version": "2.7.1",
+            "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
+            "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
+            "dev": true
+        },
+        "pump": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+            "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+            "dev": true,
+            "requires": {
+                "end-of-stream": "^1.1.0",
+                "once": "^1.3.1"
+            }
+        },
+        "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
+        },
+        "qs": {
+            "version": "6.11.0",
+            "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+            "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+            "dev": true,
+            "requires": {
+                "side-channel": "^1.0.4"
+            }
+        },
+        "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
+        },
+        "rc": {
+            "version": "1.2.8",
+            "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+            "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+            "dev": true,
+            "requires": {
+                "deep-extend": "^0.6.0",
+                "ini": "~1.3.0",
+                "minimist": "^1.2.0",
+                "strip-json-comments": "~2.0.1"
+            },
+            "dependencies": {
+                "strip-json-comments": {
+                    "version": "2.0.1",
+                    "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+                    "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+                    "dev": true
+                }
+            }
+        },
+        "read": {
+            "version": "1.0.7",
+            "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
+            "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==",
+            "dev": true,
+            "requires": {
+                "mute-stream": "~0.0.4"
+            }
+        },
+        "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"
+            }
+        },
+        "regexpp": {
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+            "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+            "dev": true
+        },
+        "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
+        },
+        "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"
+            }
+        },
+        "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
+        },
+        "sax": {
+            "version": "1.2.4",
+            "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+            "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+            "dev": true
+        },
+        "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"
+            }
+        },
+        "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
+        },
+        "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"
+            }
+        },
+        "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
+        },
+        "simple-get": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+            "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+            "dev": true,
+            "requires": {
+                "decompress-response": "^6.0.0",
+                "once": "^1.3.1",
+                "simple-concat": "^1.0.0"
+            }
+        },
+        "slash": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+            "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+            "dev": true
+        },
+        "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"
+            }
+        },
+        "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-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
+        },
+        "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"
+            }
+        },
+        "tar-fs": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
+            "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+            "dev": true,
+            "requires": {
+                "chownr": "^1.1.1",
+                "mkdirp-classic": "^0.5.2",
+                "pump": "^3.0.0",
+                "tar-stream": "^2.1.4"
+            }
+        },
+        "tar-stream": {
+            "version": "2.2.0",
+            "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+            "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+            "dev": true,
+            "requires": {
+                "bl": "^4.0.3",
+                "end-of-stream": "^1.4.1",
+                "fs-constants": "^1.0.0",
+                "inherits": "^2.0.3",
+                "readable-stream": "^3.1.1"
+            }
+        },
+        "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
+        },
+        "tmp": {
+            "version": "0.2.1",
+            "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+            "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+            "dev": true,
+            "requires": {
+                "rimraf": "^3.0.0"
+            }
+        },
+        "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"
+            }
+        },
+        "tslib": {
+            "version": "2.4.0",
+            "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+            "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
+            "dev": true
+        },
+        "tsutils": {
+            "version": "3.21.0",
+            "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+            "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+            "dev": true,
+            "requires": {
+                "tslib": "^1.8.1"
+            },
+            "dependencies": {
+                "tslib": {
+                    "version": "1.14.1",
+                    "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+                    "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+                    "dev": true
+                }
+            }
+        },
+        "tunnel": {
+            "version": "0.0.6",
+            "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+            "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+            "dev": true
+        },
+        "tunnel-agent": {
+            "version": "0.6.0",
+            "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+            "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+            "dev": true,
+            "requires": {
+                "safe-buffer": "^5.0.1"
+            }
+        },
+        "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
+        },
+        "typed-rest-client": {
+            "version": "1.8.9",
+            "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz",
+            "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==",
+            "dev": true,
+            "requires": {
+                "qs": "^6.9.1",
+                "tunnel": "0.0.6",
+                "underscore": "^1.12.1"
+            }
+        },
+        "typescript": {
+            "version": "4.7.4",
+            "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
+            "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
+            "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
+        },
+        "underscore": {
+            "version": "1.13.4",
+            "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz",
+            "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==",
+            "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"
+            }
+        },
+        "url-join": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
+            "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
+            "dev": true
+        },
+        "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
+        },
+        "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
+        },
+        "vsce": {
+            "version": "2.9.2",
+            "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.9.2.tgz",
+            "integrity": "sha512-xyLqL4U82BilUX1t6Ym2opQEa2tLGWYjbgB7+ETeNVXlIJz5sWBJjQJSYJVFOKJSpiOtQclolu88cj7oY6vvPQ==",
+            "dev": true,
+            "requires": {
+                "azure-devops-node-api": "^11.0.1",
+                "chalk": "^2.4.2",
+                "cheerio": "^1.0.0-rc.9",
+                "commander": "^6.1.0",
+                "glob": "^7.0.6",
+                "hosted-git-info": "^4.0.2",
+                "keytar": "^7.7.0",
+                "leven": "^3.1.0",
+                "markdown-it": "^12.3.2",
+                "mime": "^1.3.4",
+                "minimatch": "^3.0.3",
+                "parse-semver": "^1.1.1",
+                "read": "^1.0.7",
+                "semver": "^5.1.0",
+                "tmp": "^0.2.1",
+                "typed-rest-client": "^1.8.4",
+                "url-join": "^4.0.1",
+                "xml2js": "^0.4.23",
+                "yauzl": "^2.3.1",
+                "yazl": "^2.2.2"
+            },
+            "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
+                },
+                "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"
+                    }
+                }
+            }
+        },
+        "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"
+            }
+        },
+        "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
+        },
+        "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
+        },
+        "xml2js": {
+            "version": "0.4.23",
+            "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+            "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+            "dev": true,
+            "requires": {
+                "sax": ">=0.6.0",
+                "xmlbuilder": "~11.0.0"
+            }
+        },
+        "xmlbuilder": {
+            "version": "11.0.1",
+            "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+            "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+            "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
+        },
+        "yauzl": {
+            "version": "2.10.0",
+            "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+            "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+            "dev": true,
+            "requires": {
+                "buffer-crc32": "~0.2.3",
+                "fd-slicer": "~1.1.0"
+            }
+        },
+        "yazl": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
+            "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==",
+            "dev": true,
+            "requires": {
+                "buffer-crc32": "~0.2.3"
+            }
+        }
+    }
+}

+ 102 - 0
packages/cli/extension/package.json

@@ -0,0 +1,102 @@
+{
+    "name": "dioxus",
+    "displayName": "Dioxus",
+    "description": "Useful tools for working with Dioxus",
+    "version": "0.0.1",
+    "publisher": "DioxusLabs",
+    "private": true,
+    "license": "MIT",
+    "icon": "static/icon.png",
+    "repository": {
+        "type": "git",
+        "url": "https://github.com/DioxusLabs/cli"
+    },
+    "engines": {
+        "vscode": "^1.68.1"
+    },
+    "categories": [
+        "Programming Languages"
+    ],
+    "activationEvents": [
+        "onCommand:extension.htmlToDioxusRsx",
+        "onCommand:extension.htmlToDioxusComponent",
+        "onCommand:extension.formatRsx",
+        "onCommand:extension.formatRsxDocument"
+    ],
+    "main": "./out/main",
+    "contributes": {
+        "commands": [
+            {
+                "command": "extension.htmlToDioxusRsx",
+                "title": "Dioxus: Convert HTML to RSX"
+            },
+            {
+                "command": "extension.htmlToDioxusComponent",
+                "title": "Dioxus: Convert HTML to Component"
+            },
+            {
+                "command": "extension.formatRsx",
+                "title": "Dioxus: Format RSX"
+            },
+            {
+                "command": "extension.formatRsxDocument",
+                "title": "Dioxus: Format RSX Document"
+            }
+        ],
+        "configuration": {
+            "properties": {
+                "dioxus.formatOnSave": {
+                    "type": [
+                        "string"
+                    ],
+                    "default": "followFormatOnSave",
+                    "enum": [
+                        "followFormatOnSave",
+                        "enabled",
+                        "disabled"
+                    ],
+                    "enumItemLabels": [
+                        "Follow the normal formatOnSave config",
+                        "Enabled",
+                        "Disabled"
+                    ],
+                    "enumDescriptions": [
+                        "Only format Rsx when saving files if the editor.formatOnSave config is enabled",
+                        "Always format Rsx when a Rust file is saved",
+                        "Never format Rsx when a file is saved"
+                    ],
+                    "description": "Format RSX when a file is saved."
+                }
+            }
+        }
+    },
+    "scripts": {
+        "vscode:prepublish": "npm run build-base -- --minify",
+        "package": "vsce package -o rust-analyzer.vsix",
+        "build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node16",
+        "build": "npm run build-base -- --sourcemap",
+        "watch": "npm run build-base -- --sourcemap --watch",
+        "lint": "prettier --check . && eslint -c .eslintrc.js --ext ts ./src ./tests",
+        "fix": "prettier --write . && eslint -c .eslintrc.js --ext ts ./src ./tests --fix",
+        "pretest": "tsc && npm run build",
+        "test": "cross-env TEST_VARIABLE=test node ./out/tests/runTests.js"
+    },
+    "devDependencies": {
+        "@types/node": "^18.0.2",
+        "@types/vscode": "^1.68.1",
+        "@typescript-eslint/eslint-plugin": "^5.30.5",
+        "@typescript-eslint/parser": "^5.30.5",
+        "cross-env": "^7.0.3",
+        "esbuild": "^0.14.27",
+        "eslint": "^8.19.0",
+        "typescript": "^4.7.4",
+        "eslint-config-prettier": "^8.5.0",
+        "ovsx": "^0.5.1",
+        "prettier": "^2.6.2",
+        "tslib": "^2.3.0",
+        "vsce": "^2.7.0"
+    },
+    "dependencies": {
+        "vsce": "^2.9.2"
+    }
+}

+ 3 - 0
packages/cli/extension/server/.gitignore

@@ -0,0 +1,3 @@
+**
+!Readme.md
+!.gitignore

+ 282 - 0
packages/cli/extension/src/main.ts

@@ -0,0 +1,282 @@
+import * as vscode from 'vscode';
+import { spawn } from "child_process";
+import { TextEncoder } from 'util';
+
+let serverPath: string = "dioxus";
+
+export async function activate(context: vscode.ExtensionContext) {
+	let somePath = await bootstrap(context);
+
+	if (somePath == undefined) {
+		await vscode.window.showErrorMessage('Could not find bundled Dioxus-CLI. Please install it manually.');
+		return;
+	} else {
+		serverPath = somePath;
+	}
+
+	context.subscriptions.push(
+		// vscode.commands.registerTextEditorCommand('editor.action.clipboardPasteAction', onPasteHandler),
+		vscode.commands.registerCommand('extension.htmlToDioxusRsx', translateBlock),
+		vscode.commands.registerCommand('extension.htmlToDioxusComponent', translateComponent),
+		vscode.commands.registerCommand('extension.formatRsx', fmtSelection),
+		vscode.commands.registerCommand('extension.formatRsxDocument', formatRsxDocument),
+		vscode.workspace.onWillSaveTextDocument(fmtDocumentOnSave)
+	);
+}
+
+
+function translateComponent() {
+	translate(true)
+}
+
+function translateBlock() {
+	translate(false)
+}
+
+function translate(component: boolean) {
+	const editor = vscode.window.activeTextEditor;
+
+	if (!editor) return;
+
+	const html = editor.document.getText(editor.selection);
+	if (html.length == 0) {
+		vscode.window.showWarningMessage("Please select HTML fragment before invoking this command!");
+		return;
+	}
+
+	let params = ["translate"];
+	if (component) params.push("--component");
+	params.push("--raw", html);
+
+	const child_proc = spawn(serverPath, params);
+
+	let result = '';
+	child_proc.stdout?.on('data', data => result += data);
+
+	child_proc.on('close', () => {
+		if (result.length > 0) editor.edit(editBuilder => editBuilder.replace(editor.selection, result));
+	});
+
+	child_proc.on('error', (err) => {
+		vscode.window.showWarningMessage(`Errors occurred while translating. Make sure you have the most recent Dioxus-CLI installed! \n${err}`);
+	});
+}
+
+function onPasteHandler() {
+	// check settings to see if we should convert HTML to Rsx
+	if (vscode.workspace.getConfiguration('dioxus').get('convertOnPaste')) {
+		convertHtmlToRsxOnPaste();
+	}
+}
+
+function convertHtmlToRsxOnPaste() {
+	const editor = vscode.window.activeTextEditor;
+	if (!editor) return;
+
+	// get the cursor location
+	const cursor = editor.selection.active;
+
+	// try to parse the HTML at the cursor location
+	const html = editor.document.getText(new vscode.Range(cursor, cursor));
+}
+
+function formatRsxDocument() {
+	const editor = vscode.window.activeTextEditor;
+	if (!editor) return;
+	fmtDocument(editor.document);
+}
+
+function fmtSelection() {
+	const editor = vscode.window.activeTextEditor;
+	if (!editor) return;
+
+	const unformatted = editor.document.getText(editor.selection);
+
+	if (unformatted.length == 0) {
+		vscode.window.showWarningMessage("Please select rsx invoking this command!");
+		return;
+	}
+
+	const fileDir = editor.document.fileName.slice(0, editor.document.fileName.lastIndexOf('\\'));
+
+	const child_proc = spawn(serverPath, ["fmt", "--raw", unformatted.toString()], {
+		cwd: fileDir ? fileDir : undefined,
+	});
+	let result = '';
+
+	child_proc.stdout?.on('data', data => result += data);
+
+	child_proc.on('close', () => {
+		if (result.length > 0) editor.edit(editBuilder => editBuilder.replace(editor.selection, result));
+	});
+
+	child_proc.on('error', (err) => {
+		vscode.window.showWarningMessage(`Errors occurred while translating. Make sure you have the most recent Dioxus-CLI installed! \n${err}`);
+	});
+}
+
+function fmtDocumentOnSave(e: vscode.TextDocumentWillSaveEvent) {
+	// check the settings to make sure format on save is configured
+	const dioxusConfig = vscode.workspace.getConfiguration('dioxus', e.document).get('formatOnSave');
+	const globalConfig = vscode.workspace.getConfiguration('editor', e.document).get('formatOnSave');
+	if (
+		(dioxusConfig === 'enabled') ||
+		(dioxusConfig !== 'disabled' && globalConfig)
+	) {
+		fmtDocument(e.document);
+	}
+}
+
+function fmtDocument(document: vscode.TextDocument) {
+	try {
+		if (document.languageId !== "rust" || document.uri.scheme !== "file") {
+			return;
+		}
+
+		const [editor,] = vscode.window.visibleTextEditors.filter(editor => editor.document.fileName === document.fileName);
+		if (!editor) return; // Need an editor to apply text edits.
+
+		const fileDir = document.fileName.slice(0, document.fileName.lastIndexOf('\\'));
+		const child_proc = spawn(serverPath, ["fmt", "--file", document.fileName], {
+			cwd: fileDir ? fileDir : undefined,
+		});
+
+		let result = '';
+		child_proc.stdout?.on('data', data => result += data);
+
+		/*type RsxEdit = {
+			formatted: string,
+			start: number,
+			end: number
+		}*/
+
+		child_proc.on('close', () => {
+			if (child_proc.exitCode !== 0) {
+				vscode.window.showWarningMessage(`Errors occurred while formatting. Make sure you have the most recent Dioxus-CLI installed!\nDioxus-CLI exited with exit code ${child_proc.exitCode}\n\nData from Dioxus-CLI:\n${result}`);
+				return;
+			}
+			/*if (result.length === 0) return;
+
+			// Used for error message:
+			const originalResult = result;
+			try {
+				// Only parse the last non empty line, to skip log warning messages:
+				const lines = result.replaceAll('\r\n', '\n').split('\n');
+				const nonEmptyLines = lines.filter(line => line.trim().length !== 0);
+				result = nonEmptyLines[nonEmptyLines.length - 1] ?? '';
+
+				if (result.length === 0) return;
+
+				const decoded: RsxEdit[] = JSON.parse(result);
+				if (decoded.length === 0) return;
+
+				// Preform edits at the end of the file
+				// first (to not change previous text file
+				// offsets):
+				decoded.sort((a, b) => b.start - a.start);
+
+
+				// Convert from utf8 offsets to utf16 offsets used by VS Code:
+
+				const utf8Text = new TextEncoder().encode(text);
+				const utf8ToUtf16Pos = (posUtf8: number) => {
+					// Find the line of the position as well as the utf8 and
+					// utf16 indexes for the start of that line:
+					let startOfLineUtf8 = 0;
+					let lineIndex = 0;
+					const newLineUtf8 = '\n'.charCodeAt(0);
+					// eslint-disable-next-line no-constant-condition
+					while (true) {
+						const nextLineAt = utf8Text.indexOf(newLineUtf8, startOfLineUtf8);
+						if (nextLineAt < 0 || posUtf8 <= nextLineAt) break;
+						startOfLineUtf8 = nextLineAt + 1;
+						lineIndex++;
+					}
+					const lineUtf16 = document.lineAt(lineIndex);
+
+					// Move forward from a synced position in the text until the
+					// target pos is found:
+					let currentUtf8 = startOfLineUtf8;
+					let currentUtf16 = document.offsetAt(lineUtf16.range.start);
+
+					const decodeBuffer = new Uint8Array(10);
+					const utf8Encoder = new TextEncoder();
+					while (currentUtf8 < posUtf8) {
+						const { written } = utf8Encoder.encodeInto(text.charAt(currentUtf16), decodeBuffer);
+						currentUtf8 += written;
+						currentUtf16++;
+					}
+					return currentUtf16;
+				};
+
+
+				type FixedEdit = {
+					range: vscode.Range,
+					formatted: string,
+				};
+
+				const edits: FixedEdit[] = [];
+				for (const edit of decoded) {
+					// Convert from utf8 to utf16:
+					const range = new vscode.Range(
+						document.positionAt(utf8ToUtf16Pos(edit.start)),
+						document.positionAt(utf8ToUtf16Pos(edit.end))
+					);
+
+					if (editor.document.getText(range) !== document.getText(range)) {
+						// The text that was formatted has changed while we were working.
+						vscode.window.showWarningMessage(`Dioxus formatting was ignored since the source file changed before the change could be applied.`);
+						continue;
+					}
+
+					edits.push({
+						range,
+						formatted: edit.formatted,
+					});
+				}
+
+
+				// Apply edits:
+				editor.edit(editBuilder => {
+					edits.forEach((edit) => editBuilder.replace(edit.range, edit.formatted));
+				}, {
+					undoStopAfter: false,
+					undoStopBefore: false
+				});
+		
+			} catch (err) {
+				vscode.window.showWarningMessage(`Errors occurred while formatting. Make sure you have the most recent Dioxus-CLI installed!\n${err}\n\nData from Dioxus-CLI:\n${originalResult}`);
+			}*/
+		});
+
+		child_proc.on('error', (err) => {
+			vscode.window.showWarningMessage(`Errors occurred while formatting. Make sure you have the most recent Dioxus-CLI installed! \n${err}`);
+		});
+	} catch (error) {
+		vscode.window.showWarningMessage(`Errors occurred while formatting. Make sure you have the most recent Dioxus-CLI installed! \n${error}`);
+	}
+}
+
+
+
+// I'm using the approach defined in rust-analyzer here
+//
+// We ship the server as part of the extension, but we need to handle external paths and such
+//
+// https://github.com/rust-lang/rust-analyzer/blob/fee5555cfabed4b8abbd40983fc4442df4007e49/editors/code/src/main.ts#L270
+async function bootstrap(context: vscode.ExtensionContext): Promise<string | undefined> {
+
+	const ext = process.platform === "win32" ? ".exe" : "";
+	const bundled = vscode.Uri.joinPath(context.extensionUri, "server", `dioxus${ext}`);
+	const bundledExists = await vscode.workspace.fs.stat(bundled).then(
+		() => true,
+		() => false
+	);
+
+	// if bunddled doesn't exist, try using a locally-installed version
+	if (!bundledExists) {
+		return "dioxus";
+	}
+
+	return bundled.fsPath;
+}

BIN
packages/cli/extension/static/icon.png


+ 12 - 0
packages/cli/extension/tsconfig.json

@@ -0,0 +1,12 @@
+{
+	"compilerOptions": {
+		"module": "commonjs",
+		"target": "es2021",
+		"lib": ["ES2021"],
+		"outDir": "out",
+		"sourceMap": true,
+		"strict": true,
+		"rootDir": "src"
+	},
+	"exclude": ["node_modules", ".vscode-test"]
+}

+ 8 - 0
packages/cli/rustfmt.toml

@@ -0,0 +1,8 @@
+version = "Two"
+edition = "2021"
+
+imports_granularity = "Crate"
+#use_small_heuristics = "Max"
+#control_brace_style = "ClosingNextLine"
+normalize_comments = true
+format_code_in_doc_comments = true

+ 25 - 0
packages/cli/src/assets/autoreload.js

@@ -0,0 +1,25 @@
+// Dioxus-CLI
+// https://github.com/DioxusLabs/cli
+
+(function () {
+  var protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
+  var url = protocol + '//' + window.location.host + '/_dioxus/ws';
+  var poll_interval = 8080;
+  var reload_upon_connect = () => {
+      window.setTimeout(
+          () => {
+              var ws = new WebSocket(url);
+              ws.onopen = () => window.location.reload();
+              ws.onclose = reload_upon_connect;
+          },
+          poll_interval);
+  };
+
+  var ws = new WebSocket(url);
+  ws.onmessage = (ev) => {
+      if (ev.data == "reload") {
+          window.location.reload();
+      }
+  };
+  ws.onclose = reload_upon_connect;
+})()

+ 47 - 0
packages/cli/src/assets/dioxus.toml

@@ -0,0 +1,47 @@
+[application]
+
+# dioxus project name
+name = "{{project-name}}"
+
+# default platfrom
+# you can also use `dioxus serve/build --platform XXX` to use other platform
+# value: web | desktop
+default_platform = "{{default-platform}}"
+
+# Web `build` & `serve` dist path
+out_dir = "dist"
+
+# resource (static) file folder
+asset_dir = "public"
+
+[web.app]
+
+# HTML title tag content
+title = "Dioxus | An elegant GUI library for Rust"
+
+[web.watcher]
+
+index_on_404 = true
+
+watch_path = ["src"]
+
+# include `assets` in web platform
+[web.resource]
+
+# CSS style file
+style = []
+
+# Javascript code file
+script = []
+
+[web.resource.dev]
+
+# Javascript code file
+# serve: [dev-server] only
+script = []
+
+[application.plugins]
+
+available = true
+
+required = []

+ 22 - 0
packages/cli/src/assets/index.html

@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>{app_title}</title>
+  <meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <meta charset="UTF-8" />
+  {style_include}
+</head>
+<body>
+  <div id="main"></div>
+  <script type="module">
+    import init from "/{base_path}/assets/dioxus/{app_name}.js";
+    init("/{base_path}/assets/dioxus/{app_name}_bg.wasm").then(wasm => {
+      if (wasm.__wbindgen_start == undefined) {
+        wasm.main();
+      }
+    });
+  </script>
+  {script_include}
+</body>
+</html>

+ 725 - 0
packages/cli/src/builder.rs

@@ -0,0 +1,725 @@
+use crate::{
+    config::{CrateConfig, ExecutableType},
+    error::{Error, Result},
+    tools::Tool,
+    DioxusConfig,
+};
+use cargo_metadata::{diagnostic::Diagnostic, Message};
+use indicatif::{ProgressBar, ProgressStyle};
+use serde::Serialize;
+use std::{
+    fs::{copy, create_dir_all, File},
+    io::Read,
+    panic,
+    path::PathBuf,
+    process::Command,
+    time::Duration,
+};
+use wasm_bindgen_cli_support::Bindgen;
+
+#[derive(Serialize, Debug, Clone)]
+pub struct BuildResult {
+    pub warnings: Vec<Diagnostic>,
+    pub elapsed_time: u128,
+}
+
+pub fn build(config: &CrateConfig, quiet: bool) -> Result<BuildResult> {
+    // [1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?)
+    // [2] Generate the appropriate build folders
+    // [3] Wasm-bindgen the .wasm fiile, and move it into the {builddir}/modules/xxxx/xxxx_bg.wasm
+    // [4] Wasm-opt the .wasm file with whatever optimizations need to be done
+    // [5][OPTIONAL] Builds the Tailwind CSS file using the Tailwind standalone binary
+    // [6] Link up the html page to the wasm module
+
+    let CrateConfig {
+        out_dir,
+        crate_dir,
+        target_dir,
+        asset_dir,
+        executable,
+        dioxus_config,
+        ..
+    } = config;
+
+    // start to build the assets
+    let ignore_files = build_assets(config)?;
+
+    let t_start = std::time::Instant::now();
+
+    // [1] Build the .wasm module
+    log::info!("🚅 Running build command...");
+    let cmd = subprocess::Exec::cmd("cargo");
+    let cmd = cmd
+        .cwd(&crate_dir)
+        .arg("build")
+        .arg("--target")
+        .arg("wasm32-unknown-unknown")
+        .arg("--message-format=json");
+
+    let cmd = if config.release {
+        cmd.arg("--release")
+    } else {
+        cmd
+    };
+    let cmd = if config.verbose {
+        cmd.arg("--verbose")
+    } else {
+        cmd
+    };
+
+    let cmd = if quiet { cmd.arg("--quiet") } else { cmd };
+
+    let cmd = if config.custom_profile.is_some() {
+        let custom_profile = config.custom_profile.as_ref().unwrap();
+        cmd.arg("--profile").arg(custom_profile)
+    } else {
+        cmd
+    };
+
+    let cmd = if config.features.is_some() {
+        let features_str = config.features.as_ref().unwrap().join(" ");
+        cmd.arg("--features").arg(features_str)
+    } else {
+        cmd
+    };
+
+    let cmd = match executable {
+        ExecutableType::Binary(name) => cmd.arg("--bin").arg(name),
+        ExecutableType::Lib(name) => cmd.arg("--lib").arg(name),
+        ExecutableType::Example(name) => cmd.arg("--example").arg(name),
+    };
+
+    let warning_messages = prettier_build(cmd)?;
+
+    // [2] Establish the output directory structure
+    let bindgen_outdir = out_dir.join("assets").join("dioxus");
+
+    let release_type = match config.release {
+        true => "release",
+        false => "debug",
+    };
+
+    let input_path = match executable {
+        ExecutableType::Binary(name) | ExecutableType::Lib(name) => target_dir
+            .join(format!("wasm32-unknown-unknown/{}", release_type))
+            .join(format!("{}.wasm", name)),
+
+        ExecutableType::Example(name) => target_dir
+            .join(format!("wasm32-unknown-unknown/{}/examples", release_type))
+            .join(format!("{}.wasm", name)),
+    };
+
+    let bindgen_result = panic::catch_unwind(move || {
+        // [3] Bindgen the final binary for use easy linking
+        let mut bindgen_builder = Bindgen::new();
+
+        bindgen_builder
+            .input_path(input_path)
+            .web(true)
+            .unwrap()
+            .debug(true)
+            .demangle(true)
+            .keep_debug(true)
+            .remove_name_section(false)
+            .remove_producers_section(false)
+            .out_name(&dioxus_config.application.name)
+            .generate(&bindgen_outdir)
+            .unwrap();
+    });
+    if bindgen_result.is_err() {
+        return Err(Error::BuildFailed("Bindgen build failed! \nThis is probably due to the Bindgen version, dioxus-cli using `0.2.81` Bindgen crate.".to_string()));
+    }
+
+    // check binaryen:wasm-opt tool
+    let dioxus_tools = dioxus_config.application.tools.clone().unwrap_or_default();
+    if dioxus_tools.contains_key("binaryen") {
+        let info = dioxus_tools.get("binaryen").unwrap();
+        let binaryen = crate::tools::Tool::Binaryen;
+
+        if binaryen.is_installed() {
+            if let Some(sub) = info.as_table() {
+                if sub.contains_key("wasm_opt")
+                    && sub.get("wasm_opt").unwrap().as_bool().unwrap_or(false)
+                {
+                    log::info!("Optimizing WASM size with wasm-opt...");
+                    let target_file = out_dir
+                        .join("assets")
+                        .join("dioxus")
+                        .join(format!("{}_bg.wasm", dioxus_config.application.name));
+                    if target_file.is_file() {
+                        let mut args = vec![
+                            target_file.to_str().unwrap(),
+                            "-o",
+                            target_file.to_str().unwrap(),
+                        ];
+                        if config.release == true {
+                            args.push("-Oz");
+                        }
+                        binaryen.call("wasm-opt", args)?;
+                    }
+                }
+            }
+        } else {
+            log::warn!(
+                "Binaryen tool not found, you can use `dioxus tool add binaryen` to install it."
+            );
+        }
+    }
+
+    // [5][OPTIONAL] If tailwind is enabled and installed we run it to generate the CSS
+    if dioxus_tools.contains_key("tailwindcss") {
+        let info = dioxus_tools.get("tailwindcss").unwrap();
+        let tailwind = crate::tools::Tool::Tailwind;
+
+        if tailwind.is_installed() {
+            if let Some(sub) = info.as_table() {
+                log::info!("Building Tailwind bundle CSS file...");
+
+                let input_path = match sub.get("input") {
+                    Some(val) => val.as_str().unwrap(),
+                    None => "./public",
+                };
+                let config_path = match sub.get("config") {
+                    Some(val) => val.as_str().unwrap(),
+                    None => "./src/tailwind.config.js",
+                };
+                let mut args = vec![
+                    "-i",
+                    input_path,
+                    "-o",
+                    "dist/tailwind.css",
+                    "-c",
+                    config_path,
+                ];
+
+                if config.release == true {
+                    args.push("--minify");
+                }
+
+                tailwind.call("tailwindcss", args)?;
+            }
+        } else {
+            log::warn!(
+                "Tailwind tool not found, you can use `dioxus tool add tailwindcss` to install it."
+            );
+        }
+    }
+
+    // this code will copy all public file to the output dir
+    let copy_options = fs_extra::dir::CopyOptions {
+        overwrite: true,
+        skip_exist: false,
+        buffer_size: 64000,
+        copy_inside: false,
+        content_only: false,
+        depth: 0,
+    };
+    if asset_dir.is_dir() {
+        for entry in std::fs::read_dir(&asset_dir)? {
+            let path = entry?.path();
+            if path.is_file() {
+                std::fs::copy(&path, out_dir.join(path.file_name().unwrap()))?;
+            } else {
+                match fs_extra::dir::copy(&path, out_dir, &copy_options) {
+                    Ok(_) => {}
+                    Err(_e) => {
+                        log::warn!("Error copying dir: {}", _e);
+                    }
+                }
+                for ignore in &ignore_files {
+                    let ignore = ignore.strip_prefix(&config.asset_dir).unwrap();
+                    let ignore = config.out_dir.join(ignore);
+                    if ignore.is_file() {
+                        std::fs::remove_file(ignore)?;
+                    }
+                }
+            }
+        }
+    }
+
+    let t_end = std::time::Instant::now();
+    Ok(BuildResult {
+        warnings: warning_messages,
+        elapsed_time: (t_end - t_start).as_millis(),
+    })
+}
+
+pub fn build_desktop(config: &CrateConfig, _is_serve: bool) -> Result<()> {
+    log::info!("🚅 Running build [Desktop] command...");
+
+    let ignore_files = build_assets(config)?;
+
+    let mut cmd = Command::new("cargo");
+    cmd.current_dir(&config.crate_dir)
+        .arg("build")
+        .stdout(std::process::Stdio::inherit())
+        .stderr(std::process::Stdio::inherit());
+
+    if config.release {
+        cmd.arg("--release");
+    }
+    if config.verbose {
+        cmd.arg("--verbose");
+    }
+
+    if config.custom_profile.is_some() {
+        let custom_profile = config.custom_profile.as_ref().unwrap();
+        cmd.arg("--profile");
+        cmd.arg(custom_profile);
+    }
+
+    if config.features.is_some() {
+        let features_str = config.features.as_ref().unwrap().join(" ");
+        cmd.arg("--features");
+        cmd.arg(features_str);
+    }
+
+    match &config.executable {
+        crate::ExecutableType::Binary(name) => cmd.arg("--bin").arg(name),
+        crate::ExecutableType::Lib(name) => cmd.arg("--lib").arg(name),
+        crate::ExecutableType::Example(name) => cmd.arg("--example").arg(name),
+    };
+
+    let output = cmd.output()?;
+
+    if !output.status.success() {
+        return Err(Error::BuildFailed("Program build failed.".into()));
+    }
+
+    if output.status.success() {
+        let release_type = match config.release {
+            true => "release",
+            false => "debug",
+        };
+
+        let file_name: String;
+        let mut res_path = match &config.executable {
+            crate::ExecutableType::Binary(name) | crate::ExecutableType::Lib(name) => {
+                file_name = name.clone();
+                config.target_dir.join(release_type).join(name)
+            }
+            crate::ExecutableType::Example(name) => {
+                file_name = name.clone();
+                config
+                    .target_dir
+                    .join(release_type)
+                    .join("examples")
+                    .join(name)
+            }
+        };
+
+        let target_file = if cfg!(windows) {
+            res_path.set_extension("exe");
+            format!("{}.exe", &file_name)
+        } else {
+            file_name
+        };
+
+        if !config.out_dir.is_dir() {
+            create_dir_all(&config.out_dir)?;
+        }
+        copy(res_path, &config.out_dir.join(target_file))?;
+
+        // this code will copy all public file to the output dir
+        if config.asset_dir.is_dir() {
+            let copy_options = fs_extra::dir::CopyOptions {
+                overwrite: true,
+                skip_exist: false,
+                buffer_size: 64000,
+                copy_inside: false,
+                content_only: false,
+                depth: 0,
+            };
+
+            for entry in std::fs::read_dir(&config.asset_dir)? {
+                let path = entry?.path();
+                if path.is_file() {
+                    std::fs::copy(&path, &config.out_dir.join(path.file_name().unwrap()))?;
+                } else {
+                    match fs_extra::dir::copy(&path, &config.out_dir, &copy_options) {
+                        Ok(_) => {}
+                        Err(e) => {
+                            log::warn!("Error copying dir: {}", e);
+                        }
+                    }
+                    for ignore in &ignore_files {
+                        let ignore = ignore.strip_prefix(&config.asset_dir).unwrap();
+                        let ignore = config.out_dir.join(ignore);
+                        if ignore.is_file() {
+                            std::fs::remove_file(ignore)?;
+                        }
+                    }
+                }
+            }
+        }
+
+        log::info!(
+            "🚩 Build completed: [./{}]",
+            config
+                .dioxus_config
+                .application
+                .out_dir
+                .clone()
+                .unwrap_or_else(|| PathBuf::from("dist"))
+                .display()
+        );
+    }
+
+    Ok(())
+}
+
+fn prettier_build(cmd: subprocess::Exec) -> anyhow::Result<Vec<Diagnostic>> {
+    let mut warning_messages: Vec<Diagnostic> = vec![];
+
+    let pb = ProgressBar::new_spinner();
+    pb.enable_steady_tick(Duration::from_millis(200));
+    pb.set_style(
+        ProgressStyle::with_template("{spinner:.dim.bold} {wide_msg}")
+            .unwrap()
+            .tick_chars("/|\\- "),
+    );
+    pb.set_message("💼 Waiting to start build the project...");
+
+    struct StopSpinOnDrop(ProgressBar);
+
+    impl Drop for StopSpinOnDrop {
+        fn drop(&mut self) {
+            self.0.finish_and_clear();
+        }
+    }
+
+    StopSpinOnDrop(pb.clone());
+
+    let stdout = cmd.detached().stream_stdout()?;
+    let reader = std::io::BufReader::new(stdout);
+    for message in cargo_metadata::Message::parse_stream(reader) {
+        match message.unwrap() {
+            Message::CompilerMessage(msg) => {
+                let message = msg.message;
+                match message.level {
+                    cargo_metadata::diagnostic::DiagnosticLevel::Error => {
+                        return {
+                            Err(anyhow::anyhow!(message
+                                .rendered
+                                .unwrap_or("Unknown".into())))
+                        };
+                    }
+                    cargo_metadata::diagnostic::DiagnosticLevel::Warning => {
+                        warning_messages.push(message.clone());
+                    }
+                    _ => {}
+                }
+            }
+            Message::CompilerArtifact(artifact) => {
+                pb.set_message(format!("Compiling {} ", artifact.package_id));
+                pb.tick();
+            }
+            Message::BuildScriptExecuted(script) => {
+                let _package_id = script.package_id.to_string();
+            }
+            Message::BuildFinished(finished) => {
+                if finished.success {
+                    log::info!("👑 Build done.");
+                } else {
+                    std::process::exit(1);
+                }
+            }
+            _ => (), // Unknown message
+        }
+    }
+    Ok(warning_messages)
+}
+
+pub fn gen_page(config: &DioxusConfig, serve: bool) -> String {
+    let crate_root = crate::cargo::crate_root().unwrap();
+    let custom_html_file = crate_root.join("index.html");
+    let mut html = if custom_html_file.is_file() {
+        let mut buf = String::new();
+        let mut file = File::open(custom_html_file).unwrap();
+        if file.read_to_string(&mut buf).is_ok() {
+            buf
+        } else {
+            String::from(include_str!("./assets/index.html"))
+        }
+    } else {
+        String::from(include_str!("./assets/index.html"))
+    };
+
+    let resouces = config.web.resource.clone();
+
+    let mut style_list = resouces.style.unwrap_or_default();
+    let mut script_list = resouces.script.unwrap_or_default();
+
+    if serve {
+        let mut dev_style = resouces.dev.style.clone().unwrap_or_default();
+        let mut dev_script = resouces.dev.script.unwrap_or_default();
+        style_list.append(&mut dev_style);
+        script_list.append(&mut dev_script);
+    }
+
+    let mut style_str = String::new();
+    for style in style_list {
+        style_str.push_str(&format!(
+            "<link rel=\"stylesheet\" href=\"{}\">\n",
+            &style.to_str().unwrap(),
+        ))
+    }
+    if config
+        .application
+        .tools
+        .clone()
+        .unwrap_or_default()
+        .contains_key("tailwindcss")
+    {
+        style_str.push_str("<link rel=\"stylesheet\" href=\"tailwind.css\">\n");
+    }
+
+    replace_or_insert_before("{style_include}", &style_str, "</head", &mut html);
+
+    let mut script_str = String::new();
+    for script in script_list {
+        script_str.push_str(&format!(
+            "<script src=\"{}\"></script>\n",
+            &script.to_str().unwrap(),
+        ))
+    }
+
+    replace_or_insert_before("{script_include}", &script_str, "</body", &mut html);
+
+    if serve {
+        html += &format!(
+            "<script>{}</script>",
+            include_str!("./assets/autoreload.js")
+        );
+    }
+
+    let base_path = match &config.web.app.base_path {
+        Some(path) => path,
+        None => ".",
+    };
+    let app_name = &config.application.name;
+    // Check if a script already exists
+    if html.contains("{app_name}") && html.contains("{base_path}") {
+        html = html.replace("{app_name}", app_name);
+
+        html = html.replace("{base_path}", base_path);
+    } else {
+        // If not, insert the script
+        html = html.replace(
+            "</body",
+            &format!(
+                r#"<script type="module">
+    import init from "/{base_path}/assets/dioxus/{app_name}.js";
+    init("/{base_path}/assets/dioxus/{app_name}_bg.wasm").then(wasm => {{
+      if (wasm.__wbindgen_start == undefined) {{
+        wasm.main();
+      }}
+    }});
+    </script>
+    </body"#
+            ),
+        );
+    }
+
+    let title = config
+        .web
+        .app
+        .title
+        .clone()
+        .unwrap_or_else(|| "dioxus | ⛺".into());
+
+    replace_or_insert_before("{app_title}", &title, "</title", &mut html);
+
+    html
+}
+
+fn replace_or_insert_before(
+    replace: &str,
+    with: &str,
+    or_insert_before: &str,
+    content: &mut String,
+) {
+    if content.contains(replace) {
+        *content = content.replace(replace, with);
+    } else {
+        *content = content.replace(or_insert_before, &format!("{}{}", with, or_insert_before));
+    }
+}
+
+// this function will build some assets file
+// like sass tool resources
+// this function will return a array which file don't need copy to out_dir.
+fn build_assets(config: &CrateConfig) -> Result<Vec<PathBuf>> {
+    let mut result = vec![];
+
+    let dioxus_config = &config.dioxus_config;
+    let dioxus_tools = dioxus_config.application.tools.clone().unwrap_or_default();
+
+    // check sass tool state
+    let sass = Tool::Sass;
+    if sass.is_installed() && dioxus_tools.contains_key("sass") {
+        let sass_conf = dioxus_tools.get("sass").unwrap();
+        if let Some(tab) = sass_conf.as_table() {
+            let source_map = tab.contains_key("source_map");
+            let source_map = if source_map && tab.get("source_map").unwrap().is_bool() {
+                if tab.get("source_map").unwrap().as_bool().unwrap_or_default() {
+                    "--source-map"
+                } else {
+                    "--no-source-map"
+                }
+            } else {
+                "--source-map"
+            };
+
+            if tab.contains_key("input") {
+                if tab.get("input").unwrap().is_str() {
+                    let file = tab.get("input").unwrap().as_str().unwrap().trim();
+
+                    if file == "*" {
+                        // if the sass open auto, we need auto-check the assets dir.
+                        let asset_dir = config.asset_dir.clone();
+                        if asset_dir.is_dir() {
+                            for entry in walkdir::WalkDir::new(&asset_dir)
+                                .into_iter()
+                                .filter_map(|e| e.ok())
+                            {
+                                let temp = entry.path();
+                                if temp.is_file() {
+                                    let suffix = temp.extension();
+                                    if suffix.is_none() {
+                                        continue;
+                                    }
+                                    let suffix = suffix.unwrap().to_str().unwrap();
+                                    if suffix == "scss" || suffix == "sass" {
+                                        // if file suffix is `scss` / `sass` we need transform it.
+                                        let out_file = format!(
+                                            "{}.css",
+                                            temp.file_stem().unwrap().to_str().unwrap()
+                                        );
+                                        let target_path = config
+                                            .out_dir
+                                            .join(
+                                                temp.strip_prefix(&asset_dir)
+                                                    .unwrap()
+                                                    .parent()
+                                                    .unwrap(),
+                                            )
+                                            .join(out_file);
+                                        let res = sass.call(
+                                            "sass",
+                                            vec![
+                                                temp.to_str().unwrap(),
+                                                target_path.to_str().unwrap(),
+                                                source_map,
+                                            ],
+                                        );
+                                        if res.is_ok() {
+                                            result.push(temp.to_path_buf());
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    } else {
+                        // just transform one file.
+                        let relative_path = if &file[0..1] == "/" {
+                            &file[1..file.len()]
+                        } else {
+                            file
+                        };
+                        let path = config.asset_dir.join(relative_path);
+                        let out_file =
+                            format!("{}.css", path.file_stem().unwrap().to_str().unwrap());
+                        let target_path = config
+                            .out_dir
+                            .join(PathBuf::from(relative_path).parent().unwrap())
+                            .join(out_file);
+                        if path.is_file() {
+                            let res = sass.call(
+                                "sass",
+                                vec![
+                                    path.to_str().unwrap(),
+                                    target_path.to_str().unwrap(),
+                                    source_map,
+                                ],
+                            );
+                            if res.is_ok() {
+                                result.push(path);
+                            } else {
+                                log::error!("{:?}", res);
+                            }
+                        }
+                    }
+                } else if tab.get("input").unwrap().is_array() {
+                    // check files list.
+                    let list = tab.get("input").unwrap().as_array().unwrap();
+                    for i in list {
+                        if i.is_str() {
+                            let path = i.as_str().unwrap();
+                            let relative_path = if &path[0..1] == "/" {
+                                &path[1..path.len()]
+                            } else {
+                                path
+                            };
+                            let path = config.asset_dir.join(relative_path);
+                            let out_file =
+                                format!("{}.css", path.file_stem().unwrap().to_str().unwrap());
+                            let target_path = config
+                                .out_dir
+                                .join(PathBuf::from(relative_path).parent().unwrap())
+                                .join(out_file);
+                            if path.is_file() {
+                                let res = sass.call(
+                                    "sass",
+                                    vec![
+                                        path.to_str().unwrap(),
+                                        target_path.to_str().unwrap(),
+                                        source_map,
+                                    ],
+                                );
+                                if res.is_ok() {
+                                    result.push(path);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    // SASS END
+
+    Ok(result)
+}
+
+// use binary_install::{Cache, Download};
+
+// /// Attempts to find `wasm-opt` in `PATH` locally, or failing that downloads a
+// /// precompiled binary.
+// ///
+// /// Returns `Some` if a binary was found or it was successfully downloaded.
+// /// Returns `None` if a binary wasn't found in `PATH` and this platform doesn't
+// /// have precompiled binaries. Returns an error if we failed to download the
+// /// binary.
+// pub fn find_wasm_opt(
+//     cache: &Cache,
+//     install_permitted: bool,
+// ) -> Result<install::Status, failure::Error> {
+//     // First attempt to look up in PATH. If found assume it works.
+//     if let Ok(path) = which::which("wasm-opt") {
+//         PBAR.info(&format!("found wasm-opt at {:?}", path));
+
+//         match path.as_path().parent() {
+//             Some(path) => return Ok(install::Status::Found(Download::at(path))),
+//             None => {}
+//         }
+//     }
+
+//     let version = "version_78";
+//     Ok(install::download_prebuilt(
+//         &install::Tool::WasmOpt,
+//         cache,
+//         version,
+//         install_permitted,
+//     )?)
+// }

+ 94 - 0
packages/cli/src/cargo.rs

@@ -0,0 +1,94 @@
+//! Utilities for working with cargo and rust files
+use crate::error::{Error, Result};
+use std::{
+    env, fs,
+    path::{Path, PathBuf},
+    process::Command,
+    str,
+};
+
+/// How many parent folders are searched for a `Cargo.toml`
+const MAX_ANCESTORS: u32 = 10;
+
+/// Some fields parsed from `cargo metadata` command
+pub struct Metadata {
+    pub workspace_root: PathBuf,
+    pub target_directory: PathBuf,
+}
+
+/// Returns the root of the crate that the command is run from
+///
+/// If the command is run from the workspace root, this will return the top-level Cargo.toml
+pub fn crate_root() -> Result<PathBuf> {
+    // From the current directory we work our way up, looking for `Cargo.toml`
+    env::current_dir()
+        .ok()
+        .and_then(|mut wd| {
+            for _ in 0..MAX_ANCESTORS {
+                if contains_manifest(&wd) {
+                    return Some(wd);
+                }
+                if !wd.pop() {
+                    break;
+                }
+            }
+            None
+        })
+        .ok_or_else(|| {
+            Error::CargoError("Failed to find directory containing Cargo.toml".to_string())
+        })
+}
+
+/// Checks if the directory contains `Cargo.toml`
+fn contains_manifest(path: &Path) -> bool {
+    fs::read_dir(path)
+        .map(|entries| {
+            entries
+                .filter_map(Result::ok)
+                .any(|ent| &ent.file_name() == "Cargo.toml")
+        })
+        .unwrap_or(false)
+}
+
+impl Metadata {
+    /// Returns the struct filled from `cargo metadata` output
+    /// TODO @Jon, find a different way that doesn't rely on the cargo metadata command (it's slow)
+    pub fn get() -> Result<Self> {
+        let output = Command::new("cargo")
+            .args(&["metadata"])
+            .output()
+            .map_err(|_| Error::CargoError("Manifset".to_string()))?;
+
+        if !output.status.success() {
+            let mut msg = str::from_utf8(&output.stderr).unwrap().trim();
+            if msg.starts_with("error: ") {
+                msg = &msg[7..];
+            }
+
+            return Err(Error::CargoError(msg.to_string()));
+        }
+
+        let stdout = str::from_utf8(&output.stdout).unwrap();
+        if let Some(line) = stdout.lines().next() {
+            let meta: serde_json::Value = serde_json::from_str(line)
+                .map_err(|_| Error::CargoError("InvalidOutput".to_string()))?;
+
+            let workspace_root = meta["workspace_root"]
+                .as_str()
+                .ok_or_else(|| Error::CargoError("InvalidOutput".to_string()))?
+                .into();
+
+            let target_directory = meta["target_directory"]
+                .as_str()
+                .ok_or_else(|| Error::CargoError("InvalidOutput".to_string()))?
+                .into();
+
+            return Ok(Self {
+                workspace_root,
+                target_directory,
+            });
+        }
+
+        Err(Error::CargoError("InvalidOutput".to_string()))
+    }
+}

+ 184 - 0
packages/cli/src/cli/autoformat/mod.rs

@@ -0,0 +1,184 @@
+use futures::{stream::FuturesUnordered, StreamExt};
+use std::{fs, process::exit};
+
+use super::*;
+
+// For reference, the rustfmt main.rs file
+// https://github.com/rust-lang/rustfmt/blob/master/src/bin/main.rs
+
+/// Build the Rust WASM app and all of its assets.
+#[derive(Clone, Debug, Parser)]
+pub struct Autoformat {
+    /// Run in 'check' mode. Exits with 0 if input is formatted correctly. Exits
+    /// with 1 and prints a diff if formatting is required.
+    #[clap(short, long)]
+    pub check: bool,
+
+    /// Input rsx (selection)
+    #[clap(short, long)]
+    pub raw: Option<String>,
+
+    /// Input file
+    #[clap(short, long)]
+    pub file: Option<String>,
+}
+
+impl Autoformat {
+    // Todo: autoformat the entire crate
+    pub async fn autoformat(self) -> Result<()> {
+        // Default to formatting the project
+        if self.raw.is_none() && self.file.is_none() {
+            if let Err(e) = autoformat_project(self.check).await {
+                eprintln!("error formatting project: {}", e);
+                exit(1);
+            }
+        }
+
+        if let Some(raw) = self.raw {
+            if let Some(inner) = dioxus_autofmt::fmt_block(&raw, 0) {
+                println!("{}", inner);
+            } else {
+                // exit process with error
+                eprintln!("error formatting codeblock");
+                exit(1);
+            }
+        }
+
+        // Format single file
+        if let Some(file) = self.file {
+            let file_content = fs::read_to_string(&file);
+
+            match file_content {
+                Ok(s) => {
+                    let edits = dioxus_autofmt::fmt_file(&s);
+                    let out = dioxus_autofmt::apply_formats(&s, edits);
+                    match fs::write(&file, out) {
+                        Ok(_) => {
+                            println!("formatted {}", file);
+                        }
+                        Err(e) => {
+                            eprintln!("failed to write formatted content to file: {}", e);
+                        }
+                    }
+                }
+                Err(e) => {
+                    eprintln!("failed to open file: {}", e);
+                    exit(1);
+                }
+            }
+        }
+
+        Ok(())
+    }
+}
+
+/// Read every .rs file accessible when considering the .gitignore and try to format it
+///
+/// Runs using Tokio for multithreading, so it should be really really fast
+///
+/// Doesn't do mod-descending, so it will still try to format unreachable files. TODO.
+async fn autoformat_project(check: bool) -> Result<()> {
+    let crate_config = crate::CrateConfig::new()?;
+
+    let mut files_to_format = vec![];
+    collect_rs_files(&crate_config.crate_dir, &mut files_to_format);
+
+    let counts = files_to_format
+        .into_iter()
+        .filter(|file| {
+            if file.components().any(|f| f.as_os_str() == "target") {
+                return false;
+            }
+
+            true
+        })
+        .map(|path| async {
+            let _path = path.clone();
+            let res = tokio::spawn(async move {
+                let contents = tokio::fs::read_to_string(&path).await?;
+
+                let edits = dioxus_autofmt::fmt_file(&contents);
+                let len = edits.len();
+
+                if !edits.is_empty() {
+                    let out = dioxus_autofmt::apply_formats(&contents, edits);
+                    tokio::fs::write(&path, out).await?;
+                }
+
+                Ok(len) as Result<usize, tokio::io::Error>
+            })
+            .await;
+
+            if res.is_err() {
+                eprintln!("error formatting file: {}", _path.display());
+            }
+
+            res
+        })
+        .collect::<FuturesUnordered<_>>()
+        .collect::<Vec<_>>()
+        .await;
+
+    let files_formatted: usize = counts
+        .into_iter()
+        .map(|f| match f {
+            Ok(Ok(res)) => res,
+            _ => 0,
+        })
+        .sum();
+
+    if files_formatted > 0 && check {
+        eprintln!("{} files needed formatting", files_formatted);
+        exit(1);
+    }
+
+    Ok(())
+}
+
+fn collect_rs_files(folder: &PathBuf, files: &mut Vec<PathBuf>) {
+    let Ok(folder) = folder.read_dir() else { return };
+
+    // load the gitignore
+
+    for entry in folder {
+        let Ok(entry) = entry else { continue; };
+
+        let path = entry.path();
+
+        if path.is_dir() {
+            collect_rs_files(&path, files);
+        }
+
+        if let Some(ext) = path.extension() {
+            if ext == "rs" {
+                files.push(path);
+            }
+        }
+    }
+}
+
+#[test]
+fn spawn_properly() {
+    let out = Command::new("dioxus")
+        .args([
+            "fmt",
+            "-f",
+            r#"
+//
+
+rsx! {
+
+    div {}
+}
+
+//
+//
+//
+
+        "#,
+        ])
+        .output()
+        .expect("failed to execute process");
+
+    dbg!(out);
+}

+ 76 - 0
packages/cli/src/cli/build/mod.rs

@@ -0,0 +1,76 @@
+use crate::plugin::PluginManager;
+
+use super::*;
+
+/// Build the Rust WASM app and all of its assets.
+#[derive(Clone, Debug, Parser)]
+#[clap(name = "build")]
+pub struct Build {
+    #[clap(flatten)]
+    pub build: ConfigOptsBuild,
+}
+
+impl Build {
+    pub fn build(self) -> Result<()> {
+        let mut crate_config = crate::CrateConfig::new()?;
+
+        // change the release state.
+        crate_config.with_release(self.build.release);
+        crate_config.with_verbose(self.build.verbose);
+
+        if self.build.example.is_some() {
+            crate_config.as_example(self.build.example.unwrap());
+        }
+
+        if self.build.profile.is_some() {
+            crate_config.set_profile(self.build.profile.unwrap());
+        }
+
+        if self.build.features.is_some() {
+            crate_config.set_features(self.build.features.unwrap());
+        }
+
+        let platform = self.build.platform.unwrap_or_else(|| {
+            crate_config
+                .dioxus_config
+                .application
+                .default_platform
+                .clone()
+        });
+
+        let _ = PluginManager::on_build_start(&crate_config, &platform);
+
+        match platform.as_str() {
+            "web" => {
+                crate::builder::build(&crate_config, false)?;
+            }
+            "desktop" => {
+                crate::builder::build_desktop(&crate_config, false)?;
+            }
+            _ => {
+                return custom_error!("Unsupported platform target.");
+            }
+        }
+
+        let temp = gen_page(&crate_config.dioxus_config, false);
+
+        let mut file = std::fs::File::create(
+            crate_config
+                .crate_dir
+                .join(
+                    crate_config
+                        .dioxus_config
+                        .application
+                        .out_dir
+                        .clone()
+                        .unwrap_or_else(|| PathBuf::from("dist")),
+                )
+                .join("index.html"),
+        )?;
+        file.write_all(temp.as_bytes())?;
+
+        let _ = PluginManager::on_build_finish(&crate_config, &platform);
+
+        Ok(())
+    }
+}

+ 96 - 0
packages/cli/src/cli/cfg.rs

@@ -0,0 +1,96 @@
+use super::*;
+
+/// Config options for the build system.
+#[derive(Clone, Debug, Default, Deserialize, Parser)]
+pub struct ConfigOptsBuild {
+    /// The index HTML file to drive the bundling process [default: index.html]
+    #[arg(long)]
+    pub target: Option<PathBuf>,
+
+    /// Build in release mode [default: false]
+    #[clap(long)]
+    #[serde(default)]
+    pub release: bool,
+
+    // Use verbose output [default: false]
+    #[clap(long)]
+    #[serde(default)]
+    pub verbose: bool,
+
+    /// Build a example [default: ""]
+    #[clap(long)]
+    pub example: Option<String>,
+
+    /// Build with custom profile
+    #[clap(long)]
+    pub profile: Option<String>,
+
+    /// Build platform: support Web & Desktop [default: "default_platform"]
+    #[clap(long)]
+    pub platform: Option<String>,
+
+    /// Space separated list of features to activate
+    #[clap(long)]
+    pub features: Option<Vec<String>>,
+}
+
+#[derive(Clone, Debug, Default, Deserialize, Parser)]
+pub struct ConfigOptsServe {
+    /// The index HTML file to drive the bundling process [default: index.html]
+    #[arg(short, long)]
+    pub target: Option<PathBuf>,
+
+    /// Port of dev server
+    #[clap(long)]
+    #[clap(default_value_t = 8080)]
+    pub port: u16,
+
+    /// Open the app in the default browser [default: false]
+    #[clap(long)]
+    #[serde(default)]
+    pub open: bool,
+
+    /// Build a example [default: ""]
+    #[clap(long)]
+    pub example: Option<String>,
+
+    /// Build in release mode [default: false]
+    #[clap(long)]
+    #[serde(default)]
+    pub release: bool,
+
+    // Use verbose output [default: false]
+    #[clap(long)]
+    #[serde(default)]
+    pub verbose: bool,
+
+    /// Build with custom profile
+    #[clap(long)]
+    pub profile: Option<String>,
+
+    /// Build platform: support Web & Desktop [default: "default_platform"]
+    #[clap(long)]
+    pub platform: Option<String>,
+
+    /// Build with hot reloading rsx [default: false]
+    #[clap(long)]
+    #[serde(default)]
+    pub hot_reload: bool,
+
+    /// Set cross-origin-policy to same-origin [default: false]
+    #[clap(name = "cross-origin-policy")]
+    #[clap(long)]
+    #[serde(default)]
+    pub cross_origin_policy: bool,
+
+    /// Space separated list of features to activate
+    #[clap(long)]
+    pub features: Option<Vec<String>>,
+}
+
+/// Ensure the given value for `--public-url` is formatted correctly.
+pub fn parse_public_url(val: &str) -> String {
+    let prefix = if !val.starts_with('/') { "/" } else { "" };
+    let suffix = if !val.ends_with('/') { "/" } else { "" };
+    format!("{}{}{}", prefix, val, suffix)
+}

+ 33 - 0
packages/cli/src/cli/clean/mod.rs

@@ -0,0 +1,33 @@
+use super::*;
+
+/// Build the Rust WASM app and all of its assets.
+#[derive(Clone, Debug, Parser)]
+#[clap(name = "clean")]
+pub struct Clean {}
+
+impl Clean {
+    pub fn clean(self) -> Result<()> {
+        let crate_config = crate::CrateConfig::new()?;
+
+        let output = Command::new("cargo")
+            .arg("clean")
+            .stdout(Stdio::piped())
+            .stderr(Stdio::piped())
+            .output()?;
+
+        if !output.status.success() {
+            return custom_error!("Cargo clean failed.");
+        }
+
+        let out_dir = crate_config
+            .dioxus_config
+            .application
+            .out_dir
+            .unwrap_or_else(|| PathBuf::from("dist"));
+        if crate_config.crate_dir.join(&out_dir).is_dir() {
+            remove_dir_all(crate_config.crate_dir.join(&out_dir))?;
+        }
+
+        Ok(())
+    }
+}

+ 63 - 0
packages/cli/src/cli/config/mod.rs

@@ -0,0 +1,63 @@
+use super::*;
+
+/// Build the Rust WASM app and all of its assets.
+#[derive(Clone, Debug, Deserialize, Subcommand)]
+#[clap(name = "config")]
+pub enum Config {
+    /// Init `Dioxus.toml` for project/folder.
+    Init {
+        /// Init project name
+        name: String,
+
+        /// Cover old config
+        #[clap(long)]
+        #[serde(default)]
+        force: bool,
+
+        /// Project default platform
+        #[clap(long, default_value = "web")]
+        platform: String,
+    },
+    /// Format print Dioxus config.
+    FormatPrint {},
+    /// Create a custom html file.
+    CustomHtml {},
+}
+
+impl Config {
+    pub fn config(self) -> Result<()> {
+        let crate_root = crate::cargo::crate_root()?;
+        match self {
+            Config::Init {
+                name,
+                force,
+                platform,
+            } => {
+                let conf_path = crate_root.join("Dioxus.toml");
+                if conf_path.is_file() && !force {
+                    log::warn!(
+                        "config file `Dioxus.toml` already exist, use `--force` to overwrite it."
+                    );
+                    return Ok(());
+                }
+                let mut file = File::create(conf_path)?;
+                let content = String::from(include_str!("../../assets/dioxus.toml"))
+                    .replace("{{project-name}}", &name)
+                    .replace("{{default-platform}}", &platform);
+                file.write_all(content.as_bytes())?;
+                log::info!("🚩 Init config file completed.");
+            }
+            Config::FormatPrint {} => {
+                println!("{:#?}", crate::CrateConfig::new()?.dioxus_config);
+            }
+            Config::CustomHtml {} => {
+                let html_path = crate_root.join("index.html");
+                let mut file = File::create(html_path)?;
+                let content = include_str!("../../assets/index.html");
+                file.write_all(content.as_bytes())?;
+                log::info!("🚩 Create custom html file done.");
+            }
+        }
+        Ok(())
+    }
+}

+ 76 - 0
packages/cli/src/cli/create/mod.rs

@@ -0,0 +1,76 @@
+use super::*;
+use cargo_generate::{GenerateArgs, TemplatePath};
+
+#[derive(Clone, Debug, Default, Deserialize, Parser)]
+#[clap(name = "create")]
+pub struct Create {
+    /// Template path
+    #[clap(default_value = "gh:dioxuslabs/dioxus-template", long)]
+    template: String,
+}
+
+impl Create {
+    pub fn create(self) -> Result<()> {
+        let mut args = GenerateArgs::default();
+        args.template_path = TemplatePath {
+            auto_path: Some(self.template),
+            ..Default::default()
+        };
+
+        let path = cargo_generate::generate(args)?;
+
+        // first run cargo fmt
+        let mut cmd = Command::new("cargo");
+        let cmd = cmd.arg("fmt").current_dir(&path);
+        let output = cmd.output().expect("failed to execute process");
+        if !output.status.success() {
+            log::error!("cargo fmt failed");
+            log::error!("stdout: {}", String::from_utf8_lossy(&output.stdout));
+            log::error!("stderr: {}", String::from_utf8_lossy(&output.stderr));
+        }
+
+        // then format the toml
+        let toml_paths = [path.join("Cargo.toml"), path.join("Dioxus.toml")];
+        for toml_path in &toml_paths {
+            let toml = std::fs::read_to_string(toml_path)?;
+            let mut toml = toml.parse::<toml_edit::Document>().map_err(|e| {
+                anyhow::anyhow!(
+                    "failed to parse toml at {}: {}",
+                    toml_path.display(),
+                    e.to_string()
+                )
+            })?;
+
+            toml.as_table_mut().fmt();
+
+            let as_string = toml.to_string();
+            let new_string = remove_tripple_newlines(&as_string);
+            let mut file = std::fs::File::create(toml_path)?;
+            file.write_all(new_string.as_bytes())?;
+        }
+
+        // remove any tripple newlines from the readme
+        let readme_path = path.join("README.md");
+        let readme = std::fs::read_to_string(&readme_path)?;
+        let new_readme = remove_tripple_newlines(&readme);
+        let mut file = std::fs::File::create(readme_path)?;
+        file.write_all(new_readme.as_bytes())?;
+
+        log::info!("Generated project at {}", path.display());
+
+        Ok(())
+    }
+}
+
+fn remove_tripple_newlines(string: &str) -> String {
+    let mut new_string = String::new();
+    for char in string.chars() {
+        if char == '\n' {
+            if new_string.ends_with("\n\n") {
+                continue;
+            }
+        }
+        new_string.push(char);
+    }
+    new_string
+}

+ 89 - 0
packages/cli/src/cli/mod.rs

@@ -0,0 +1,89 @@
+pub mod autoformat;
+pub mod build;
+pub mod cfg;
+pub mod clean;
+pub mod config;
+pub mod create;
+pub mod plugin;
+pub mod serve;
+pub mod translate;
+pub mod version;
+
+use crate::{
+    cfg::{ConfigOptsBuild, ConfigOptsServe},
+    custom_error,
+    error::Result,
+    gen_page, server, CrateConfig, Error,
+};
+use clap::{Parser, Subcommand};
+use html_parser::Dom;
+use serde::Deserialize;
+use std::{
+    fs::{remove_dir_all, File},
+    io::{Read, Write},
+    path::PathBuf,
+    process::{Command, Stdio},
+};
+
+/// Build, Bundle & Ship Dioxus Apps.
+#[derive(Parser)]
+#[clap(name = "dioxus", version)]
+pub struct Cli {
+    #[clap(subcommand)]
+    pub action: Commands,
+
+    /// Enable verbose logging.
+    #[clap(short)]
+    pub v: bool,
+}
+
+#[derive(Parser)]
+pub enum Commands {
+    /// Build the Rust WASM app and all of its assets.
+    Build(build::Build),
+
+    /// Translate some source file into Dioxus code.
+    Translate(translate::Translate),
+
+    /// Build, watch & serve the Rust WASM app and all of its assets.
+    Serve(serve::Serve),
+
+    /// Init a new project for Dioxus.
+    Create(create::Create),
+
+    /// Clean output artifacts.
+    Clean(clean::Clean),
+
+    /// Print the version of this extension
+    #[clap(name = "version")]
+    Version(version::Version),
+
+    /// Format some rsx
+    #[clap(name = "fmt")]
+    Autoformat(autoformat::Autoformat),
+
+    /// Dioxus config file controls.
+    #[clap(subcommand)]
+    Config(config::Config),
+
+    /// Manage plugins for dioxus cli
+    #[clap(subcommand)]
+    Plugin(plugin::Plugin),
+}
+
+impl Commands {
+    pub fn to_string(&self) -> String {
+        match self {
+            Commands::Build(_) => "build",
+            Commands::Translate(_) => "translate",
+            Commands::Serve(_) => "serve",
+            Commands::Create(_) => "create",
+            Commands::Clean(_) => "clean",
+            Commands::Config(_) => "config",
+            Commands::Plugin(_) => "plugin",
+            Commands::Version(_) => "version",
+            Commands::Autoformat(_) => "fmt",
+        }
+        .to_string()
+    }
+}

+ 37 - 0
packages/cli/src/cli/plugin/mod.rs

@@ -0,0 +1,37 @@
+use super::*;
+
+/// Build the Rust WASM app and all of its assets.
+#[derive(Clone, Debug, Deserialize, Subcommand)]
+#[clap(name = "plugin")]
+pub enum Plugin {
+    /// Return all dioxus-cli support tools.
+    List {},
+    /// Get default app install path.
+    AppPath {},
+    /// Install a new tool.
+    Add { name: String },
+}
+
+impl Plugin {
+    pub async fn plugin(self) -> Result<()> {
+        match self {
+            Plugin::List {} => {
+                for item in crate::plugin::PluginManager::plugin_list() {
+                    println!("- {item}");
+                }
+            }
+            Plugin::AppPath {} => {
+                let plugin_dir = crate::plugin::PluginManager::init_plugin_dir();
+                if let Some(v) = plugin_dir.to_str() {
+                    println!("{}", v);
+                } else {
+                    log::error!("Plugin path get failed.");
+                }
+            }
+            Plugin::Add { name: _ } => {
+                log::info!("You can use `dioxus plugin app-path` to get Installation position");
+            }
+        }
+        Ok(())
+    }
+}

+ 100 - 0
packages/cli/src/cli/serve/mod.rs

@@ -0,0 +1,100 @@
+use super::*;
+use std::{
+    fs::create_dir_all,
+    io::Write,
+    path::PathBuf,
+    process::{Command, Stdio},
+};
+
+/// Run the WASM project on dev-server
+#[derive(Clone, Debug, Parser)]
+#[clap(name = "serve")]
+pub struct Serve {
+    #[clap(flatten)]
+    pub serve: ConfigOptsServe,
+}
+
+impl Serve {
+    pub async fn serve(self) -> Result<()> {
+        let mut crate_config = crate::CrateConfig::new()?;
+
+        // change the relase state.
+        crate_config.with_hot_reload(self.serve.hot_reload);
+        crate_config.with_cross_origin_policy(self.serve.cross_origin_policy);
+        crate_config.with_release(self.serve.release);
+        crate_config.with_verbose(self.serve.verbose);
+
+        if self.serve.example.is_some() {
+            crate_config.as_example(self.serve.example.unwrap());
+        }
+
+        if self.serve.profile.is_some() {
+            crate_config.set_profile(self.serve.profile.unwrap());
+        }
+
+        if self.serve.features.is_some() {
+            crate_config.set_features(self.serve.features.unwrap());
+        }
+
+        // Subdirectories don't work with the server
+        crate_config.dioxus_config.web.app.base_path = None;
+
+        let platform = self.serve.platform.unwrap_or_else(|| {
+            crate_config
+                .dioxus_config
+                .application
+                .default_platform
+                .clone()
+        });
+
+        if platform.as_str() == "desktop" {
+            crate::builder::build_desktop(&crate_config, true)?;
+
+            match &crate_config.executable {
+                crate::ExecutableType::Binary(name)
+                | crate::ExecutableType::Lib(name)
+                | crate::ExecutableType::Example(name) => {
+                    let mut file = crate_config.out_dir.join(name);
+                    if cfg!(windows) {
+                        file.set_extension("exe");
+                    }
+                    Command::new(file.to_str().unwrap())
+                        .stdout(Stdio::inherit())
+                        .output()?;
+                }
+            }
+            return Ok(());
+        } else if platform != "web" {
+            return custom_error!("Unsupported platform target.");
+        }
+
+        // generate dev-index page
+        Serve::regen_dev_page(&crate_config)?;
+
+        // start the develop server
+        server::startup(self.serve.port, crate_config.clone(), self.serve.open).await?;
+
+        Ok(())
+    }
+
+    pub fn regen_dev_page(crate_config: &CrateConfig) -> Result<()> {
+        let serve_html = gen_page(&crate_config.dioxus_config, true);
+
+        let dist_path = crate_config.crate_dir.join(
+            crate_config
+                .dioxus_config
+                .application
+                .out_dir
+                .clone()
+                .unwrap_or_else(|| PathBuf::from("dist")),
+        );
+        if !dist_path.is_dir() {
+            create_dir_all(&dist_path)?;
+        }
+        let index_path = dist_path.join("index.html");
+        let mut file = std::fs::File::create(index_path)?;
+        file.write_all(serve_html.as_bytes())?;
+
+        Ok(())
+    }
+}

+ 64 - 0
packages/cli/src/cli/tool/mod.rs

@@ -0,0 +1,64 @@
+use crate::tools;
+
+use super::*;
+
+/// Build the Rust WASM app and all of its assets.
+#[derive(Clone, Debug, Deserialize, Subcommand)]
+#[clap(name = "tool")]
+pub enum Tool {
+    /// Return all dioxus-cli support tools.
+    List {},
+    /// Get default app install path.
+    AppPath {},
+    /// Install a new tool.
+    Add { name: String },
+}
+
+impl Tool {
+    pub async fn tool(self) -> Result<()> {
+        match self {
+            Tool::List {} => {
+                for item in tools::tool_list() {
+                    if tools::Tool::from_str(item).unwrap().is_installed() {
+                        println!("- {item} [installed]");
+                    } else {
+                        println!("- {item}");
+                    }
+                }
+            }
+            Tool::AppPath {} => {
+                if let Some(v) = tools::tools_path().to_str() {
+                    println!("{}", v);
+                } else {
+                    return custom_error!("Tools path get failed.");
+                }
+            }
+            Tool::Add { name } => {
+                let tool_list = tools::tool_list();
+
+                if !tool_list.contains(&name.as_str()) {
+                    return custom_error!("Tool {name} not found.");
+                }
+                let target_tool = tools::Tool::from_str(&name).unwrap();
+
+                if target_tool.is_installed() {
+                    log::warn!("Tool {name} is installed.");
+                    return Ok(());
+                }
+
+                log::info!("Start to download tool package...");
+                if let Err(e) = target_tool.download_package().await {
+                    return custom_error!("Tool download failed: {e}");
+                }
+
+                log::info!("Start to install tool package...");
+                if let Err(e) = target_tool.install_package().await {
+                    return custom_error!("Tool install failed: {e}");
+                }
+
+                log::info!("Tool {name} installed successfully!");
+            }
+        }
+        Ok(())
+    }
+}

+ 138 - 0
packages/cli/src/cli/translate/mod.rs

@@ -0,0 +1,138 @@
+use std::process::exit;
+
+use dioxus_rsx::{BodyNode, CallBody};
+
+use super::*;
+
+/// Build the Rust WASM app and all of its assets.
+#[derive(Clone, Debug, Parser)]
+#[clap(name = "translate")]
+pub struct Translate {
+    /// Activate debug mode
+    // short and long flags (-d, --debug) will be deduced from the field's name
+    #[clap(short, long)]
+    pub component: bool,
+
+    /// Input file
+    #[clap(short, long)]
+    pub file: Option<String>,
+
+    /// Input file
+    #[clap(short, long)]
+    pub raw: Option<String>,
+
+    /// Output file, stdout if not present
+    #[arg(short, long)]
+    pub output: Option<PathBuf>,
+}
+
+impl Translate {
+    pub fn translate(self) -> Result<()> {
+        // Get the right input for the translation
+        let contents = determine_input(self.file, self.raw)?;
+
+        // Ensure we're loading valid HTML
+        let dom = html_parser::Dom::parse(&contents)?;
+
+        // Convert the HTML to RSX
+        let out = convert_html_to_formatted_rsx(&dom, self.component);
+
+        // Write the output
+        match self.output {
+            Some(output) => std::fs::write(&output, out)?,
+            None => print!("{}", out),
+        }
+
+        Ok(())
+    }
+}
+
+pub fn convert_html_to_formatted_rsx(dom: &Dom, component: bool) -> String {
+    let callbody = rsx_rosetta::rsx_from_html(&dom);
+
+    match component {
+        true => write_callbody_with_icon_section(callbody),
+        false => dioxus_autofmt::write_block_out(callbody).unwrap(),
+    }
+}
+
+fn write_callbody_with_icon_section(mut callbody: CallBody) -> String {
+    let mut svgs = vec![];
+
+    rsx_rosetta::collect_svgs(&mut callbody.roots, &mut svgs);
+
+    let mut out = write_component_body(dioxus_autofmt::write_block_out(callbody).unwrap());
+
+    if !svgs.is_empty() {
+        write_svg_section(&mut out, svgs);
+    }
+
+    out
+}
+
+fn write_component_body(raw: String) -> String {
+    let mut out = String::from("fn component(cx: Scope) -> Element {\n    cx.render(rsx! {");
+    indent_and_write(&raw, 1, &mut out);
+    out.push_str("    })\n}");
+    out
+}
+
+fn write_svg_section(out: &mut String, svgs: Vec<BodyNode>) {
+    out.push_str("\n\nmod icons {");
+    out.push_str("\n    use super::*;");
+    for (idx, icon) in svgs.into_iter().enumerate() {
+        let raw = dioxus_autofmt::write_block_out(CallBody { roots: vec![icon] }).unwrap();
+        out.push_str("\n\n    pub fn icon_");
+        out.push_str(&idx.to_string());
+        out.push_str("(cx: Scope) -> Element {\n        cx.render(rsx! {");
+        indent_and_write(&raw, 2, out);
+        out.push_str("        })\n    }");
+    }
+
+    out.push_str("\n}");
+}
+
+fn indent_and_write(raw: &str, idx: usize, out: &mut String) {
+    for line in raw.lines() {
+        for _ in 0..idx {
+            out.push_str("    ");
+        }
+        out.push_str(line);
+        out.push('\n');
+    }
+}
+
+fn determine_input(file: Option<String>, raw: Option<String>) -> Result<String> {
+    // Make sure not both are specified
+    if file.is_some() && raw.is_some() {
+        log::error!("Only one of --file or --raw should be specified.");
+        exit(0);
+    }
+
+    if let Some(raw) = raw {
+        return Ok(raw);
+    }
+
+    if let Some(file) = file {
+        return Ok(std::fs::read_to_string(&file)?);
+    }
+
+    // If neither exist, we try to read from stdin
+    if atty::is(atty::Stream::Stdin) {
+        return custom_error!("No input file, source, or stdin to translate from.");
+    }
+
+    let mut buffer = String::new();
+    std::io::stdin().read_to_string(&mut buffer).unwrap();
+
+    Ok(buffer.trim().to_string())
+}
+
+#[test]
+fn generates_svgs() {
+    let st = include_str!("../../../tests/svg.html");
+
+    let out = convert_html_to_formatted_rsx(&html_parser::Dom::parse(st).unwrap(), true);
+
+    println!("{}", out);
+}

+ 76 - 0
packages/cli/src/cli/version.rs

@@ -0,0 +1,76 @@
+use super::*;
+
+/// Build the Rust WASM app and all of its assets.
+#[derive(Clone, Debug, Parser)]
+#[clap(name = "version")]
+pub struct Version {}
+
+impl Version {
+    pub fn version(self) -> VersionInfo {
+        version()
+    }
+}
+
+use std::fmt;
+
+/// Information about the git repository where rust-analyzer was built from.
+pub struct CommitInfo {
+    pub short_commit_hash: &'static str,
+    pub commit_hash: &'static str,
+    pub commit_date: &'static str,
+}
+
+/// Cargo's version.
+pub struct VersionInfo {
+    /// rust-analyzer's version, such as "1.57.0", "1.58.0-beta.1", "1.59.0-nightly", etc.
+    pub version: &'static str,
+
+    /// The release channel we were built for (stable/beta/nightly/dev).
+    ///
+    /// `None` if not built via rustbuild.
+    pub release_channel: Option<&'static str>,
+
+    /// Information about the Git repository we may have been built from.
+    ///
+    /// `None` if not built from a git repo.
+    pub commit_info: Option<CommitInfo>,
+}
+
+impl fmt::Display for VersionInfo {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.version)?;
+
+        if let Some(ci) = &self.commit_info {
+            write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?;
+        };
+        Ok(())
+    }
+}
+
+/// Returns information about cargo's version.
+pub const fn version() -> VersionInfo {
+    let version = match option_env!("CFG_RELEASE") {
+        Some(x) => x,
+        None => "0.0.0",
+    };
+
+    let release_channel = option_env!("CFG_RELEASE_CHANNEL");
+    let commit_info = match (
+        option_env!("RA_COMMIT_SHORT_HASH"),
+        option_env!("RA_COMMIT_HASH"),
+        option_env!("RA_COMMIT_DATE"),
+    ) {
+        (Some(short_commit_hash), Some(commit_hash), Some(commit_date)) => Some(CommitInfo {
+            short_commit_hash,
+            commit_hash,
+            commit_date,
+        }),
+        _ => None,
+    };
+
+    VersionInfo {
+        version,
+        release_channel,
+        commit_info,
+    }
+}

+ 264 - 0
packages/cli/src/config.rs

@@ -0,0 +1,264 @@
+use crate::error::Result;
+use serde::{Deserialize, Serialize};
+use std::{collections::HashMap, path::PathBuf};
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct DioxusConfig {
+    pub application: ApplicationConfig,
+
+    pub web: WebConfig,
+
+    #[serde(default = "default_plugin")]
+    pub plugin: toml::Value,
+}
+
+fn default_plugin() -> toml::Value {
+    toml::Value::Boolean(true)
+}
+
+impl DioxusConfig {
+    pub fn load() -> crate::error::Result<Option<DioxusConfig>> {
+        let Ok(crate_dir) = crate::cargo::crate_root() else { return Ok(None); };
+
+        // we support either `Dioxus.toml` or `Cargo.toml`
+        let Some(dioxus_conf_file) = acquire_dioxus_toml(crate_dir) else {
+            return Ok(None);
+        };
+
+        toml::from_str::<DioxusConfig>(&std::fs::read_to_string(dioxus_conf_file)?)
+            .map_err(|_| crate::Error::Unique("Dioxus.toml parse failed".into()))
+            .map(Some)
+    }
+}
+
+fn acquire_dioxus_toml(dir: PathBuf) -> Option<PathBuf> {
+    // prefer uppercase
+    if dir.join("Dioxus.toml").is_file() {
+        return Some(dir.join("Dioxus.toml"));
+    }
+
+    // lowercase is fine too
+    if dir.join("dioxus.toml").is_file() {
+        return Some(dir.join("Dioxus.toml"));
+    }
+
+    None
+}
+
+impl Default for DioxusConfig {
+    fn default() -> Self {
+        Self {
+            application: ApplicationConfig {
+                name: "dioxus".into(),
+                default_platform: "web".to_string(),
+                out_dir: Some(PathBuf::from("dist")),
+                asset_dir: Some(PathBuf::from("public")),
+
+                tools: None,
+
+                sub_package: None,
+            },
+            web: WebConfig {
+                app: WebAppConfig {
+                    title: Some("dioxus | ⛺".into()),
+                    base_path: None,
+                },
+                proxy: Some(vec![]),
+                watcher: WebWatcherConfig {
+                    watch_path: Some(vec![PathBuf::from("src")]),
+                    reload_html: Some(false),
+                    index_on_404: Some(true),
+                },
+                resource: WebResourceConfig {
+                    dev: WebDevResourceConfig {
+                        style: Some(vec![]),
+                        script: Some(vec![]),
+                    },
+                    style: Some(vec![]),
+                    script: Some(vec![]),
+                },
+            },
+            plugin: toml::Value::Table(toml::map::Map::new()),
+        }
+    }
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct ApplicationConfig {
+    pub name: String,
+    pub default_platform: String,
+    pub out_dir: Option<PathBuf>,
+    pub asset_dir: Option<PathBuf>,
+
+    pub tools: Option<HashMap<String, toml::Value>>,
+
+    pub sub_package: Option<String>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct WebConfig {
+    pub app: WebAppConfig,
+    pub proxy: Option<Vec<WebProxyConfig>>,
+    pub watcher: WebWatcherConfig,
+    pub resource: WebResourceConfig,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct WebAppConfig {
+    pub title: Option<String>,
+    pub base_path: Option<String>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct WebProxyConfig {
+    pub backend: String,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct WebWatcherConfig {
+    pub watch_path: Option<Vec<PathBuf>>,
+    pub reload_html: Option<bool>,
+    pub index_on_404: Option<bool>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct WebResourceConfig {
+    pub dev: WebDevResourceConfig,
+    pub style: Option<Vec<PathBuf>>,
+    pub script: Option<Vec<PathBuf>>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct WebDevResourceConfig {
+    pub style: Option<Vec<PathBuf>>,
+    pub script: Option<Vec<PathBuf>>,
+}
+
+#[derive(Debug, Clone)]
+pub struct CrateConfig {
+    pub out_dir: PathBuf,
+    pub crate_dir: PathBuf,
+    pub workspace_dir: PathBuf,
+    pub target_dir: PathBuf,
+    pub asset_dir: PathBuf,
+    pub manifest: cargo_toml::Manifest<cargo_toml::Value>,
+    pub executable: ExecutableType,
+    pub dioxus_config: DioxusConfig,
+    pub release: bool,
+    pub hot_reload: bool,
+    pub cross_origin_policy: bool,
+    pub verbose: bool,
+    pub custom_profile: Option<String>,
+    pub features: Option<Vec<String>>,
+}
+
+#[derive(Debug, Clone)]
+pub enum ExecutableType {
+    Binary(String),
+    Lib(String),
+    Example(String),
+}
+
+impl CrateConfig {
+    pub fn new() -> Result<Self> {
+        let dioxus_config = DioxusConfig::load()?.unwrap_or_default();
+
+        let crate_dir = if let Some(package) = &dioxus_config.application.sub_package {
+            crate::cargo::crate_root()?.join(package)
+        } else {
+            crate::cargo::crate_root()?
+        };
+        let meta = crate::cargo::Metadata::get()?;
+        let workspace_dir = meta.workspace_root;
+        let target_dir = meta.target_directory;
+
+        let out_dir = match dioxus_config.application.out_dir {
+            Some(ref v) => crate_dir.join(v),
+            None => crate_dir.join("dist"),
+        };
+
+        let cargo_def = &crate_dir.join("Cargo.toml");
+
+        let asset_dir = match dioxus_config.application.asset_dir {
+            Some(ref v) => crate_dir.join(v),
+            None => crate_dir.join("public"),
+        };
+
+        let manifest = cargo_toml::Manifest::from_path(&cargo_def).unwrap();
+
+        let output_filename = {
+            match &manifest.package.as_ref().unwrap().default_run {
+                Some(default_run_target) => {
+                    default_run_target.to_owned()
+                },
+                None => {
+                    manifest.bin.iter().find(|b| b.name == manifest.package.as_ref().map(|pkg| pkg.name.clone()))
+                        .or(manifest.bin.iter().find(|b| b.path == Some("src/main.rs".to_owned())))
+                        .or(manifest.bin.first())
+                        .or(manifest.lib.as_ref())
+                        .and_then(|prod| prod.name.clone())
+                        .expect("No executable or library found from cargo metadata.")
+                }
+            }
+        };
+        let executable = ExecutableType::Binary(output_filename);
+
+        let release = false;
+        let hot_reload = false;
+        let verbose = false;
+        let custom_profile = None;
+        let features = None;
+
+        Ok(Self {
+            out_dir,
+            crate_dir,
+            workspace_dir,
+            target_dir,
+            asset_dir,
+            manifest,
+            executable,
+            release,
+            dioxus_config,
+            hot_reload,
+            cross_origin_policy: false,
+            custom_profile,
+            features,
+            verbose,
+        })
+    }
+
+    pub fn as_example(&mut self, example_name: String) -> &mut Self {
+        self.executable = ExecutableType::Example(example_name);
+        self
+    }
+
+    pub fn with_release(&mut self, release: bool) -> &mut Self {
+        self.release = release;
+        self
+    }
+
+    pub fn with_hot_reload(&mut self, hot_reload: bool) -> &mut Self {
+        self.hot_reload = hot_reload;
+        self
+    }
+
+    pub fn with_cross_origin_policy(&mut self, cross_origin_policy: bool) -> &mut Self {
+        self.cross_origin_policy = cross_origin_policy;
+        self
+    }
+
+    pub fn with_verbose(&mut self, verbose: bool) -> &mut Self {
+        self.verbose = verbose;
+        self
+    }
+
+    pub fn set_profile(&mut self, profile: String) -> &mut Self {
+        self.custom_profile = Some(profile);
+        self
+    }
+
+    pub fn set_features(&mut self, features: Vec<String>) -> &mut Self {
+        self.features = Some(features);
+        self
+    }
+}

+ 80 - 0
packages/cli/src/error.rs

@@ -0,0 +1,80 @@
+use thiserror::Error as ThisError;
+
+pub type Result<T, E = Error> = std::result::Result<T, E>;
+
+#[derive(ThisError, Debug)]
+pub enum Error {
+    /// Used when errors need to propogate but are too unique to be typed
+    #[error("{0}")]
+    Unique(String),
+
+    #[error("I/O Error: {0}")]
+    IO(#[from] std::io::Error),
+
+    #[error("Format Error: {0}")]
+    FormatError(#[from] std::fmt::Error),
+
+    #[error("Format failed: {0}")]
+    ParseError(String),
+
+    #[error("Runtime Error: {0}")]
+    RuntimeError(String),
+
+    #[error("Failed to write error")]
+    FailedToWrite,
+
+    #[error("Build Failed: {0}")]
+    BuildFailed(String),
+
+    #[error("Cargo Error: {0}")]
+    CargoError(String),
+
+    #[error("{0}")]
+    CustomError(String),
+
+    #[error("Invalid proxy URL: {0}")]
+    InvalidProxy(#[from] hyper::http::uri::InvalidUri),
+
+    #[error("Error proxying request: {0}")]
+    ProxyRequestError(hyper::Error),
+
+    #[error(transparent)]
+    Other(#[from] anyhow::Error),
+}
+
+impl From<&str> for Error {
+    fn from(s: &str) -> Self {
+        Error::Unique(s.to_string())
+    }
+}
+
+impl From<String> for Error {
+    fn from(s: String) -> Self {
+        Error::Unique(s)
+    }
+}
+
+impl From<html_parser::Error> for Error {
+    fn from(e: html_parser::Error) -> Self {
+        Self::ParseError(e.to_string())
+    }
+}
+
+impl From<hyper::Error> for Error {
+    fn from(e: hyper::Error) -> Self {
+        Self::RuntimeError(e.to_string())
+    }
+}
+
+#[macro_export]
+macro_rules! custom_error {
+    ($msg:literal $(,)?) => {
+        Err(Error::CustomError(format!($msg)))
+    };
+    ($err:expr $(,)?) => {
+        Err(Error::from($err))
+    };
+    ($fmt:expr, $($arg:tt)*) => {
+        Err(Error::CustomError(format!($fmt, $($arg)*)))
+    };
+}

+ 24 - 0
packages/cli/src/lib.rs

@@ -0,0 +1,24 @@
+pub const DIOXUS_CLI_VERSION: &str = "0.1.5";
+
+pub mod builder;
+pub mod server;
+pub mod tools;
+
+pub use builder::*;
+
+pub mod cargo;
+pub use cargo::*;
+
+pub mod cli;
+pub use cli::*;
+
+pub mod config;
+pub use config::*;
+
+pub mod error;
+pub use error::*;
+
+pub mod logging;
+pub use logging::*;
+
+pub mod plugin;

+ 35 - 0
packages/cli/src/logging.rs

@@ -0,0 +1,35 @@
+use fern::colors::{Color, ColoredLevelConfig};
+
+pub fn set_up_logging() {
+    // configure colors for the whole line
+    let colors_line = ColoredLevelConfig::new()
+        .error(Color::Red)
+        .warn(Color::Yellow)
+        // we actually don't need to specify the color for debug and info, they are white by default
+        .info(Color::White)
+        .debug(Color::White)
+        // depending on the terminals color scheme, this is the same as the background color
+        .trace(Color::BrightBlack);
+
+    // configure colors for the name of the level.
+    // since almost all of them are the same as the color for the whole line, we
+    // just clone `colors_line` and overwrite our changes
+    let colors_level = colors_line.info(Color::Green);
+    // here we set up our fern Dispatch
+    fern::Dispatch::new()
+        .format(move |out, message, record| {
+            out.finish(format_args!(
+                "{color_line}[{level}{color_line}] {message}\x1B[0m",
+                color_line = format_args!(
+                    "\x1B[{}m",
+                    colors_line.get_color(&record.level()).to_fg_str()
+                ),
+                level = colors_level.color(record.level()),
+                message = message,
+            ));
+        })
+        .level(log::LevelFilter::Info)
+        .chain(std::io::stdout())
+        .apply()
+        .unwrap();
+}

+ 65 - 0
packages/cli/src/main.rs

@@ -0,0 +1,65 @@
+use anyhow::anyhow;
+use clap::Parser;
+use dioxus_cli::{plugin::PluginManager, *};
+use Commands::*;
+
+#[tokio::main]
+async fn main() -> anyhow::Result<()> {
+    let args = Cli::parse();
+
+    set_up_logging();
+
+    let dioxus_config = DioxusConfig::load()
+        .map_err(|e| anyhow!("Failed to load `Dioxus.toml` because: {e}"))?
+        .unwrap_or_else(|| {
+            log::warn!("You appear to be creating a Dioxus project from scratch; we will use the default config");
+            DioxusConfig::default()
+        });
+
+    PluginManager::init(dioxus_config.plugin)
+        .map_err(|e| anyhow!("🚫 Plugin system initialization failed: {e}"))?;
+
+    match args.action {
+        Translate(opts) => opts
+            .translate()
+            .map_err(|e| anyhow!("🚫 Translation of HTML into RSX failed: {}", e)),
+
+        Build(opts) => opts
+            .build()
+            .map_err(|e| anyhow!("🚫 Building project failed: {}", e)),
+
+        Clean(opts) => opts
+            .clean()
+            .map_err(|e| anyhow!("🚫 Cleaning project failed: {}", e)),
+
+        Serve(opts) => opts
+            .serve()
+            .await
+            .map_err(|e| anyhow!("🚫 Serving project failed: {}", e)),
+
+        Create(opts) => opts
+            .create()
+            .map_err(|e| anyhow!("🚫 Creating new project failed: {}", e)),
+
+        Config(opts) => opts
+            .config()
+            .map_err(|e| anyhow!("🚫 Configuring new project failed: {}", e)),
+
+        Plugin(opts) => opts
+            .plugin()
+            .await
+            .map_err(|e| anyhow!("🚫 Error with plugin: {}", e)),
+
+        Autoformat(opts) => opts
+            .autoformat()
+            .await
+            .map_err(|e| anyhow!("🚫 Error autoformatting RSX: {}", e)),
+
+        Version(opt) => {
+            let version = opt.version();
+            println!("{}", version);
+
+            Ok(())
+        }
+    }
+}

+ 64 - 0
packages/cli/src/plugin/interface/command.rs

@@ -0,0 +1,64 @@
+use std::process::{Command, Stdio};
+
+use mlua::{FromLua, UserData};
+
+enum StdioFromString {
+    Inherit,
+    Piped,
+    Null,
+}
+impl<'lua> FromLua<'lua> for StdioFromString {
+    fn from_lua(lua_value: mlua::Value<'lua>, _lua: &'lua mlua::Lua) -> mlua::Result<Self> {
+        if let mlua::Value::String(v) = lua_value {
+            let v = v.to_str().unwrap();
+            return Ok(match v.to_lowercase().as_str() {
+                "inherit" => Self::Inherit,
+                "piped" => Self::Piped,
+                "null" => Self::Null,
+                _ => Self::Inherit,
+            });
+        }
+        Ok(Self::Inherit)
+    }
+}
+impl StdioFromString {
+    pub fn to_stdio(self) -> Stdio {
+        match self {
+            StdioFromString::Inherit => Stdio::inherit(),
+            StdioFromString::Piped => Stdio::piped(),
+            StdioFromString::Null => Stdio::null(),
+        }
+    }
+}
+
+pub struct PluginCommander;
+impl UserData for PluginCommander {
+    fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
+        methods.add_function(
+            "exec",
+            |_, args: (Vec<String>, StdioFromString, StdioFromString)| {
+                let cmd = args.0;
+                let stdout = args.1;
+                let stderr = args.2;
+
+                if cmd.len() == 0 {
+                    return Ok(());
+                }
+                let cmd_name = cmd.get(0).unwrap();
+                let mut command = Command::new(cmd_name);
+                let t = cmd
+                    .iter()
+                    .enumerate()
+                    .filter(|(i, _)| *i > 0)
+                    .map(|v| v.1.clone())
+                    .collect::<Vec<String>>();
+                command.args(t);
+                command.stdout(stdout.to_stdio()).stderr(stderr.to_stdio());
+                command.output()?;
+                Ok(())
+            },
+        );
+    }
+
+    fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(_fields: &mut F) {}
+}

+ 13 - 0
packages/cli/src/plugin/interface/dirs.rs

@@ -0,0 +1,13 @@
+use mlua::UserData;
+
+use crate::tools::app_path;
+
+pub struct PluginDirs;
+impl UserData for PluginDirs {
+    fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
+        methods.add_function("plugins_dir", |_, ()| {
+            let path = app_path().join("plugins");
+            Ok(path.to_str().unwrap().to_string())
+        });
+    }
+}

+ 85 - 0
packages/cli/src/plugin/interface/fs.rs

@@ -0,0 +1,85 @@
+use std::{
+    fs::{create_dir, create_dir_all, remove_dir_all, File},
+    io::{Read, Write},
+    path::PathBuf,
+};
+
+use crate::tools::extract_zip;
+use flate2::read::GzDecoder;
+use mlua::UserData;
+use tar::Archive;
+
+pub struct PluginFileSystem;
+impl UserData for PluginFileSystem {
+    fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
+        methods.add_function("create_dir", |_, args: (String, bool)| {
+            let path = args.0;
+            let recursive = args.1;
+            let path = PathBuf::from(path);
+            if !path.exists() {
+                let v = if recursive {
+                    create_dir_all(path)
+                } else {
+                    create_dir(path)
+                };
+                return Ok(v.is_ok());
+            }
+            Ok(true)
+        });
+        methods.add_function("remove_dir", |_, path: String| {
+            let path = PathBuf::from(path);
+            let r = remove_dir_all(path);
+            Ok(r.is_ok())
+        });
+        methods.add_function("file_get_content", |_, path: String| {
+            let path = PathBuf::from(path);
+            let mut file = std::fs::File::open(path)?;
+            let mut buffer = String::new();
+            file.read_to_string(&mut buffer)?;
+            Ok(buffer)
+        });
+        methods.add_function("file_set_content", |_, args: (String, String)| {
+            let path = args.0;
+            let content = args.1;
+            let path = PathBuf::from(path);
+
+            let file = std::fs::File::create(path);
+            if file.is_err() {
+                return Ok(false);
+            }
+
+            if file.unwrap().write_all(content.as_bytes()).is_err() {
+                return Ok(false);
+            }
+
+            Ok(true)
+        });
+        methods.add_function("unzip_file", |_, args: (String, String)| {
+            let file = PathBuf::from(args.0);
+            let target = PathBuf::from(args.1);
+            let res = extract_zip(&file, &target);
+            if let Err(_) = res {
+                return Ok(false);
+            }
+            Ok(true)
+        });
+        methods.add_function("untar_gz_file", |_, args: (String, String)| {
+            let file = PathBuf::from(args.0);
+            let target = PathBuf::from(args.1);
+
+            let tar_gz = if let Ok(v) = File::open(file) {
+                v
+            } else {
+                return Ok(false);
+            };
+
+            let tar = GzDecoder::new(tar_gz);
+            let mut archive = Archive::new(tar);
+            if archive.unpack(&target).is_err() {
+                return Ok(false);
+            }
+
+            Ok(true)
+        });
+    }
+}

+ 28 - 0
packages/cli/src/plugin/interface/log.rs

@@ -0,0 +1,28 @@
+use log;
+use mlua::UserData;
+
+pub struct PluginLogger;
+impl UserData for PluginLogger {
+    fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
+        methods.add_function("trace", |_, info: String| {
+            log::trace!("{}", info);
+            Ok(())
+        });
+        methods.add_function("info", |_, info: String| {
+            log::info!("{}", info);
+            Ok(())
+        });
+        methods.add_function("debug", |_, info: String| {
+            log::debug!("{}", info);
+            Ok(())
+        });
+        methods.add_function("warn", |_, info: String| {
+            log::warn!("{}", info);
+            Ok(())
+        });
+        methods.add_function("error", |_, info: String| {
+            log::error!("{}", info);
+            Ok(())
+        });
+    }
+}

+ 233 - 0
packages/cli/src/plugin/interface/mod.rs

@@ -0,0 +1,233 @@
+use mlua::{FromLua, Function, ToLua};
+
+pub mod command;
+pub mod dirs;
+pub mod fs;
+pub mod log;
+pub mod network;
+pub mod os;
+pub mod path;
+
+#[derive(Debug, Clone)]
+pub struct PluginInfo<'lua> {
+    pub name: String,
+    pub repository: String,
+    pub author: String,
+    pub version: String,
+
+    pub inner: PluginInner,
+
+    pub on_init: Option<Function<'lua>>,
+    pub build: PluginBuildInfo<'lua>,
+    pub serve: PluginServeInfo<'lua>,
+}
+
+impl<'lua> FromLua<'lua> for PluginInfo<'lua> {
+    fn from_lua(lua_value: mlua::Value<'lua>, _lua: &'lua mlua::Lua) -> mlua::Result<Self> {
+        let mut res = Self {
+            name: String::default(),
+            repository: String::default(),
+            author: String::default(),
+            version: String::from("0.1.0"),
+
+            inner: Default::default(),
+
+            on_init: None,
+            build: Default::default(),
+            serve: Default::default(),
+        };
+        if let mlua::Value::Table(tab) = lua_value {
+            if let Ok(v) = tab.get::<_, String>("name") {
+                res.name = v;
+            }
+            if let Ok(v) = tab.get::<_, String>("repository") {
+                res.repository = v;
+            }
+            if let Ok(v) = tab.get::<_, String>("author") {
+                res.author = v;
+            }
+            if let Ok(v) = tab.get::<_, String>("version") {
+                res.version = v;
+            }
+
+            if let Ok(v) = tab.get::<_, PluginInner>("inner") {
+                res.inner = v;
+            }
+
+            if let Ok(v) = tab.get::<_, Function>("on_init") {
+                res.on_init = Some(v);
+            }
+
+            if let Ok(v) = tab.get::<_, PluginBuildInfo>("build") {
+                res.build = v;
+            }
+
+            if let Ok(v) = tab.get::<_, PluginServeInfo>("serve") {
+                res.serve = v;
+            }
+        }
+
+        Ok(res)
+    }
+}
+
+impl<'lua> ToLua<'lua> for PluginInfo<'lua> {
+    fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result<mlua::Value<'lua>> {
+        let res = lua.create_table()?;
+
+        res.set("name", self.name.to_string())?;
+        res.set("repository", self.repository.to_string())?;
+        res.set("author", self.author.to_string())?;
+        res.set("version", self.version.to_string())?;
+
+        res.set("inner", self.inner)?;
+
+        if let Some(e) = self.on_init {
+            res.set("on_init", e)?;
+        }
+        res.set("build", self.build)?;
+        res.set("serve", self.serve)?;
+
+        Ok(mlua::Value::Table(res))
+    }
+}
+
+#[derive(Debug, Clone, Default)]
+pub struct PluginInner {
+    pub plugin_dir: String,
+    pub from_loader: bool,
+}
+
+impl<'lua> FromLua<'lua> for PluginInner {
+    fn from_lua(lua_value: mlua::Value<'lua>, _lua: &'lua mlua::Lua) -> mlua::Result<Self> {
+        let mut res = Self {
+            plugin_dir: String::new(),
+            from_loader: false,
+        };
+
+        if let mlua::Value::Table(t) = lua_value {
+            if let Ok(v) = t.get::<_, String>("plugin_dir") {
+                res.plugin_dir = v;
+            }
+            if let Ok(v) = t.get::<_, bool>("from_loader") {
+                res.from_loader = v;
+            }
+        }
+        Ok(res)
+    }
+}
+
+impl<'lua> ToLua<'lua> for PluginInner {
+    fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result<mlua::Value<'lua>> {
+        let res = lua.create_table()?;
+
+        res.set("plugin_dir", self.plugin_dir)?;
+        res.set("from_loader", self.from_loader)?;
+
+        Ok(mlua::Value::Table(res))
+    }
+}
+
+#[derive(Debug, Clone, Default)]
+pub struct PluginBuildInfo<'lua> {
+    pub on_start: Option<Function<'lua>>,
+    pub on_finish: Option<Function<'lua>>,
+}
+
+impl<'lua> FromLua<'lua> for PluginBuildInfo<'lua> {
+    fn from_lua(lua_value: mlua::Value<'lua>, _lua: &'lua mlua::Lua) -> mlua::Result<Self> {
+        let mut res = Self {
+            on_start: None,
+            on_finish: None,
+        };
+
+        if let mlua::Value::Table(t) = lua_value {
+            if let Ok(v) = t.get::<_, Function>("on_start") {
+                res.on_start = Some(v);
+            }
+            if let Ok(v) = t.get::<_, Function>("on_finish") {
+                res.on_finish = Some(v);
+            }
+        }
+
+        Ok(res)
+    }
+}
+
+impl<'lua> ToLua<'lua> for PluginBuildInfo<'lua> {
+    fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result<mlua::Value<'lua>> {
+        let res = lua.create_table()?;
+
+        if let Some(v) = self.on_start {
+            res.set("on_start", v)?;
+        }
+
+        if let Some(v) = self.on_finish {
+            res.set("on_finish", v)?;
+        }
+
+        Ok(mlua::Value::Table(res))
+    }
+}
+
+#[derive(Debug, Clone, Default)]
+pub struct PluginServeInfo<'lua> {
+    pub interval: i32,
+
+    pub on_start: Option<Function<'lua>>,
+    pub on_interval: Option<Function<'lua>>,
+    pub on_rebuild: Option<Function<'lua>>,
+    pub on_shutdown: Option<Function<'lua>>,
+}
+
+impl<'lua> FromLua<'lua> for PluginServeInfo<'lua> {
+    fn from_lua(lua_value: mlua::Value<'lua>, _lua: &'lua mlua::Lua) -> mlua::Result<Self> {
+        let mut res = Self::default();
+
+        if let mlua::Value::Table(tab) = lua_value {
+            if let Ok(v) = tab.get::<_, i32>("interval") {
+                res.interval = v;
+            }
+            if let Ok(v) = tab.get::<_, Function>("on_start") {
+                res.on_start = Some(v);
+            }
+            if let Ok(v) = tab.get::<_, Function>("on_interval") {
+                res.on_interval = Some(v);
+            }
+            if let Ok(v) = tab.get::<_, Function>("on_rebuild") {
+                res.on_rebuild = Some(v);
+            }
+            if let Ok(v) = tab.get::<_, Function>("on_shutdown") {
+                res.on_shutdown = Some(v);
+            }
+        }
+
+        Ok(res)
+    }
+}
+
+impl<'lua> ToLua<'lua> for PluginServeInfo<'lua> {
+    fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result<mlua::Value<'lua>> {
+        let res = lua.create_table()?;
+
+        res.set("interval", self.interval)?;
+
+        if let Some(v) = self.on_start {
+            res.set("on_start", v)?;
+        }
+
+        if let Some(v) = self.on_interval {
+            res.set("on_interval", v)?;
+        }
+
+        if let Some(v) = self.on_rebuild {
+            res.set("on_rebuild", v)?;
+        }
+
+        if let Some(v) = self.on_shutdown {
+            res.set("on_shutdown", v)?;
+        }
+
+        Ok(mlua::Value::Table(res))
+    }
+}

+ 27 - 0
packages/cli/src/plugin/interface/network.rs

@@ -0,0 +1,27 @@
+use std::{io::Cursor, path::PathBuf};
+
+use mlua::UserData;
+
+pub struct PluginNetwork;
+impl UserData for PluginNetwork {
+    fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
+        methods.add_function("download_file", |_, args: (String, String)| {
+            let url = args.0;
+            let path = args.1;
+
+            let resp = reqwest::blocking::get(url);
+            if let Ok(resp) = resp {
+                let mut content = Cursor::new(resp.bytes().unwrap());
+                let file = std::fs::File::create(PathBuf::from(path));
+                if file.is_err() {
+                    return Ok(false);
+                }
+                let mut file = file.unwrap();
+                let res = std::io::copy(&mut content, &mut file);
+                return Ok(res.is_ok());
+            }
+
+            Ok(false)
+        });
+    }
+}

+ 18 - 0
packages/cli/src/plugin/interface/os.rs

@@ -0,0 +1,18 @@
+use mlua::UserData;
+
+pub struct PluginOS;
+impl UserData for PluginOS {
+    fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
+        methods.add_function("current_platform", |_, ()| {
+            if cfg!(target_os = "windows") {
+                Ok("windows")
+            } else if cfg!(target_os = "macos") {
+                Ok("macos")
+            } else if cfg!(target_os = "linux") {
+                Ok("linux")
+            } else {
+                panic!("unsupported platformm");
+            }
+        });
+    }
+}

+ 40 - 0
packages/cli/src/plugin/interface/path.rs

@@ -0,0 +1,40 @@
+use std::path::PathBuf;
+
+use mlua::{UserData, Variadic};
+
+pub struct PluginPath;
+impl UserData for PluginPath {
+    fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
+        // join function
+        methods.add_function("join", |_, args: Variadic<String>| {
+            let mut path = PathBuf::new();
+            for i in args {
+                path = path.join(i);
+            }
+            Ok(path.to_str().unwrap().to_string())
+        });
+
+        // parent function
+        methods.add_function("parent", |_, path: String| {
+            let current_path = PathBuf::from(&path);
+            let parent = current_path.parent();
+            if parent.is_none() {
+                return Ok(path);
+            } else {
+                return Ok(parent.unwrap().to_str().unwrap().to_string());
+            }
+        });
+        methods.add_function("exists", |_, path: String| {
+            let path = PathBuf::from(path);
+            Ok(path.exists())
+        });
+        methods.add_function("is_dir", |_, path: String| {
+            let path = PathBuf::from(path);
+            Ok(path.is_dir())
+        });
+        methods.add_function("is_file", |_, path: String| {
+            let path = PathBuf::from(path);
+            Ok(path.is_file())
+        });
+    }
+}

+ 333 - 0
packages/cli/src/plugin/mod.rs

@@ -0,0 +1,333 @@
+use std::{
+    io::{Read, Write},
+    path::PathBuf,
+    sync::Mutex,
+};
+
+use mlua::{Lua, Table};
+use serde_json::json;
+
+use crate::{
+    tools::{app_path, clone_repo},
+    CrateConfig,
+};
+
+use self::{
+    interface::{
+        command::PluginCommander, dirs::PluginDirs, fs::PluginFileSystem, log::PluginLogger,
+        network::PluginNetwork, os::PluginOS, path::PluginPath, PluginInfo,
+    },
+    types::PluginConfig,
+};
+
+pub mod interface;
+mod types;
+
+lazy_static::lazy_static! {
+    static ref LUA: Mutex<Lua> = Mutex::new(Lua::new());
+}
+
+pub struct PluginManager;
+
+impl PluginManager {
+    pub fn init(config: toml::Value) -> anyhow::Result<()> {
+        let config = PluginConfig::from_toml_value(config);
+
+        if !config.available {
+            return Ok(());
+        }
+
+        let lua = LUA.lock().unwrap();
+
+        let manager = lua.create_table().unwrap();
+        let name_index = lua.create_table().unwrap();
+
+        let plugin_dir = Self::init_plugin_dir();
+
+        let api = lua.create_table().unwrap();
+
+        api.set("log", PluginLogger).unwrap();
+        api.set("command", PluginCommander).unwrap();
+        api.set("network", PluginNetwork).unwrap();
+        api.set("dirs", PluginDirs).unwrap();
+        api.set("fs", PluginFileSystem).unwrap();
+        api.set("path", PluginPath).unwrap();
+        api.set("os", PluginOS).unwrap();
+
+        lua.globals().set("plugin_lib", api).unwrap();
+        lua.globals()
+            .set("library_dir", plugin_dir.to_str().unwrap())
+            .unwrap();
+        lua.globals().set("config_info", config.clone())?;
+
+        let mut index: u32 = 1;
+        let dirs = std::fs::read_dir(&plugin_dir)?;
+
+        let mut path_list = dirs
+            .filter(|v| v.is_ok())
+            .map(|v| (v.unwrap().path(), false))
+            .collect::<Vec<(PathBuf, bool)>>();
+        for i in &config.loader {
+            let path = PathBuf::from(i);
+            if !path.is_dir() {
+                // for loader dir, we need check first, because we need give a error log.
+                log::error!("Plugin loader: {:?} path is not a exists directory.", path);
+            }
+            path_list.push((path, true));
+        }
+
+        for entry in path_list {
+            let plugin_dir = entry.0.to_path_buf();
+
+            if plugin_dir.is_dir() {
+                let init_file = plugin_dir.join("init.lua");
+                if init_file.is_file() {
+                    let mut file = std::fs::File::open(init_file).unwrap();
+                    let mut buffer = String::new();
+                    file.read_to_string(&mut buffer).unwrap();
+
+                    let current_plugin_dir = plugin_dir.to_str().unwrap().to_string();
+                    let from_loader = entry.1;
+
+                    lua.globals()
+                        .set("_temp_plugin_dir", current_plugin_dir.clone())?;
+                    lua.globals().set("_temp_from_loader", from_loader)?;
+
+                    let info = lua.load(&buffer).eval::<PluginInfo>();
+                    match info {
+                        Ok(mut info) => {
+                            if name_index.contains_key(info.name.clone()).unwrap_or(false)
+                                && !from_loader
+                            {
+                                // found same name plugin, intercept load
+                                log::warn!(
+                                    "Plugin {} has been intercepted. [mulit-load]",
+                                    info.name
+                                );
+                                continue;
+                            }
+                            info.inner.plugin_dir = current_plugin_dir;
+                            info.inner.from_loader = from_loader;
+
+                            // call `on_init` if file "dcp.json" not exists
+                            let dcp_file = plugin_dir.join("dcp.json");
+                            if !dcp_file.is_file() {
+                                if let Some(func) = info.clone().on_init {
+                                    let result = func.call::<_, bool>(());
+                                    match result {
+                                        Ok(true) => {
+                                            // plugin init success, create `dcp.json` file.
+                                            let mut file = std::fs::File::create(dcp_file).unwrap();
+                                            let value = json!({
+                                                "name": info.name,
+                                                "author": info.author,
+                                                "repository": info.repository,
+                                                "version": info.version,
+                                                "generate_time": chrono::Local::now().timestamp(),
+                                            });
+                                            let buffer =
+                                                serde_json::to_string_pretty(&value).unwrap();
+                                            let buffer = buffer.as_bytes();
+                                            file.write_all(buffer).unwrap();
+
+                                            // insert plugin-info into plugin-manager
+                                            if let Ok(index) =
+                                                name_index.get::<_, u32>(info.name.clone())
+                                            {
+                                                let _ = manager.set(index, info.clone());
+                                            } else {
+                                                let _ = manager.set(index, info.clone());
+                                                index += 1;
+                                                let _ = name_index.set(info.name, index);
+                                            }
+                                        }
+                                        Ok(false) => {
+                                            log::warn!(
+                                                "Plugin init function result is `false`, init failed."
+                                            );
+                                        }
+                                        Err(e) => {
+                                            log::warn!("Plugin init failed: {e}");
+                                        }
+                                    }
+                                }
+                            } else {
+                                if let Ok(index) = name_index.get::<_, u32>(info.name.clone()) {
+                                    let _ = manager.set(index, info.clone());
+                                } else {
+                                    let _ = manager.set(index, info.clone());
+                                    index += 1;
+                                    let _ = name_index.set(info.name, index);
+                                }
+                            }
+                        }
+                        Err(_e) => {
+                            let dir_name = plugin_dir.file_name().unwrap().to_str().unwrap();
+                            log::error!("Plugin '{dir_name}' load failed.");
+                        }
+                    }
+                }
+            }
+        }
+
+        lua.globals().set("manager", manager).unwrap();
+
+        return Ok(());
+    }
+
+    pub fn on_build_start(crate_config: &CrateConfig, platform: &str) -> anyhow::Result<()> {
+        let lua = LUA.lock().unwrap();
+
+        if !lua.globals().contains_key("manager")? {
+            return Ok(());
+        }
+        let manager = lua.globals().get::<_, Table>("manager")?;
+
+        let args = lua.create_table()?;
+        args.set("name", crate_config.dioxus_config.application.name.clone())?;
+        args.set("platform", platform)?;
+        args.set("out_dir", crate_config.out_dir.to_str().unwrap())?;
+        args.set("asset_dir", crate_config.asset_dir.to_str().unwrap())?;
+
+        for i in 1..(manager.len()? as i32 + 1) {
+            let info = manager.get::<i32, PluginInfo>(i)?;
+            if let Some(func) = info.build.on_start {
+                func.call::<Table, ()>(args.clone())?;
+            }
+        }
+
+        Ok(())
+    }
+
+    pub fn on_build_finish(crate_config: &CrateConfig, platform: &str) -> anyhow::Result<()> {
+        let lua = LUA.lock().unwrap();
+
+        if !lua.globals().contains_key("manager")? {
+            return Ok(());
+        }
+        let manager = lua.globals().get::<_, Table>("manager")?;
+
+        let args = lua.create_table()?;
+        args.set("name", crate_config.dioxus_config.application.name.clone())?;
+        args.set("platform", platform)?;
+        args.set("out_dir", crate_config.out_dir.to_str().unwrap())?;
+        args.set("asset_dir", crate_config.asset_dir.to_str().unwrap())?;
+
+        for i in 1..(manager.len()? as i32 + 1) {
+            let info = manager.get::<i32, PluginInfo>(i)?;
+            if let Some(func) = info.build.on_finish {
+                func.call::<Table, ()>(args.clone())?;
+            }
+        }
+
+        Ok(())
+    }
+
+    pub fn on_serve_start(crate_config: &CrateConfig) -> anyhow::Result<()> {
+        let lua = LUA.lock().unwrap();
+
+        if !lua.globals().contains_key("manager")? {
+            return Ok(());
+        }
+        let manager = lua.globals().get::<_, Table>("manager")?;
+
+        let args = lua.create_table()?;
+        args.set("name", crate_config.dioxus_config.application.name.clone())?;
+
+        for i in 1..(manager.len()? as i32 + 1) {
+            let info = manager.get::<i32, PluginInfo>(i)?;
+            if let Some(func) = info.serve.on_start {
+                func.call::<Table, ()>(args.clone())?;
+            }
+        }
+
+        Ok(())
+    }
+
+    pub fn on_serve_rebuild(timestamp: i64, files: Vec<PathBuf>) -> anyhow::Result<()> {
+        let lua = LUA.lock().unwrap();
+
+        let manager = lua.globals().get::<_, Table>("manager")?;
+
+        let args = lua.create_table()?;
+        args.set("timestamp", timestamp)?;
+        let files: Vec<String> = files
+            .iter()
+            .map(|v| v.to_str().unwrap().to_string())
+            .collect();
+        args.set("changed_files", files)?;
+
+        for i in 1..(manager.len()? as i32 + 1) {
+            let info = manager.get::<i32, PluginInfo>(i)?;
+            if let Some(func) = info.serve.on_rebuild {
+                func.call::<Table, ()>(args.clone())?;
+            }
+        }
+
+        Ok(())
+    }
+
+    pub fn on_serve_shutdown(crate_config: &CrateConfig) -> anyhow::Result<()> {
+        let lua = LUA.lock().unwrap();
+
+        if !lua.globals().contains_key("manager")? {
+            return Ok(());
+        }
+        let manager = lua.globals().get::<_, Table>("manager")?;
+
+        let args = lua.create_table()?;
+        args.set("name", crate_config.dioxus_config.application.name.clone())?;
+
+        for i in 1..(manager.len()? as i32 + 1) {
+            let info = manager.get::<i32, PluginInfo>(i)?;
+            if let Some(func) = info.serve.on_shutdown {
+                func.call::<Table, ()>(args.clone())?;
+            }
+        }
+
+        Ok(())
+    }
+
+    pub fn init_plugin_dir() -> PathBuf {
+        let app_path = app_path();
+        let plugin_path = app_path.join("plugins");
+        if !plugin_path.is_dir() {
+            log::info!("📖 Start to init plugin library ...");
+            let url = "https://github.com/DioxusLabs/cli-plugin-library";
+            if let Err(err) = clone_repo(&plugin_path, url) {
+                log::error!("Failed to init plugin dir, error caused by {}. ", err);
+            }
+        }
+        plugin_path
+    }
+
+    pub fn plugin_list() -> Vec<String> {
+        let mut res = vec![];
+
+        if let Ok(lua) = LUA.lock() {
+            let list = lua
+                .load(mlua::chunk!(
+                    local list = {}
+                    for key, value in ipairs(manager) do
+                        table.insert(list, {name = value.name, loader = value.inner.from_loader})
+                    end
+                    return list
+                ))
+                .eval::<Vec<Table>>()
+                .unwrap_or_default();
+            for i in list {
+                let name = i.get::<_, String>("name").unwrap();
+                let loader = i.get::<_, bool>("loader").unwrap();
+
+                let text = if loader {
+                    format!("{name} [:loader]")
+                } else {
+                    name
+                };
+                res.push(text);
+            }
+        }
+
+        res
+    }
+}

+ 138 - 0
packages/cli/src/plugin/types.rs

@@ -0,0 +1,138 @@
+use std::collections::HashMap;
+
+use mlua::ToLua;
+
+#[derive(Debug, Clone)]
+pub struct PluginConfig {
+    pub available: bool,
+    pub loader: Vec<String>,
+    pub config_info: HashMap<String, HashMap<String, Value>>,
+}
+
+impl<'lua> ToLua<'lua> for PluginConfig {
+    fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result<mlua::Value<'lua>> {
+        let table = lua.create_table()?;
+
+        table.set("available", self.available)?;
+        table.set("loader", self.loader)?;
+
+        let config_info = lua.create_table()?;
+
+        for (name, data) in self.config_info {
+            config_info.set(name, data)?;
+        }
+
+        table.set("config_info", config_info)?;
+
+        Ok(mlua::Value::Table(table))
+    }
+}
+
+impl PluginConfig {
+    pub fn from_toml_value(val: toml::Value) -> Self {
+        if let toml::Value::Table(tab) = val {
+            let available = tab
+                .get::<_>("available")
+                .unwrap_or(&toml::Value::Boolean(true));
+            let available = available.as_bool().unwrap_or(true);
+
+            let mut loader = vec![];
+            if let Some(origin) = tab.get("loader") {
+                if origin.is_array() {
+                    for i in origin.as_array().unwrap() {
+                        loader.push(i.as_str().unwrap_or_default().to_string());
+                    }
+                }
+            }
+
+            let mut config_info = HashMap::new();
+
+            for (name, value) in tab {
+                if name == "available" || name == "loader" {
+                    continue;
+                }
+                if let toml::Value::Table(value) = value {
+                    let mut map = HashMap::new();
+                    for (item, info) in value {
+                        map.insert(item, Value::from_toml(info));
+                    }
+                    config_info.insert(name, map);
+                }
+            }
+
+            Self {
+                available,
+                loader,
+                config_info,
+            }
+        } else {
+            Self {
+                available: false,
+                loader: vec![],
+                config_info: HashMap::new(),
+            }
+        }
+    }
+}
+
+#[allow(dead_code)]
+#[derive(Debug, Clone)]
+pub enum Value {
+    String(String),
+    Integer(i64),
+    Float(f64),
+    Boolean(bool),
+    Array(Vec<Value>),
+    Table(HashMap<String, Value>),
+}
+
+impl Value {
+    pub fn from_toml(origin: toml::Value) -> Self {
+        match origin {
+            cargo_toml::Value::String(s) => Value::String(s),
+            cargo_toml::Value::Integer(i) => Value::Integer(i),
+            cargo_toml::Value::Float(f) => Value::Float(f),
+            cargo_toml::Value::Boolean(b) => Value::Boolean(b),
+            cargo_toml::Value::Datetime(d) => Value::String(d.to_string()),
+            cargo_toml::Value::Array(a) => {
+                let mut v = vec![];
+                for i in a {
+                    v.push(Value::from_toml(i));
+                }
+                Value::Array(v)
+            }
+            cargo_toml::Value::Table(t) => {
+                let mut h = HashMap::new();
+                for (n, v) in t {
+                    h.insert(n, Value::from_toml(v));
+                }
+                Value::Table(h)
+            }
+        }
+    }
+}
+
+impl<'lua> ToLua<'lua> for Value {
+    fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result<mlua::Value<'lua>> {
+        Ok(match self {
+            Value::String(s) => mlua::Value::String(lua.create_string(&s)?),
+            Value::Integer(i) => mlua::Value::Integer(i),
+            Value::Float(f) => mlua::Value::Number(f),
+            Value::Boolean(b) => mlua::Value::Boolean(b),
+            Value::Array(a) => {
+                let table = lua.create_table()?;
+                for (i, v) in a.iter().enumerate() {
+                    table.set(i, v.clone())?;
+                }
+                mlua::Value::Table(table)
+            }
+            Value::Table(t) => {
+                let table = lua.create_table()?;
+                for (i, v) in t.iter() {
+                    table.set(i.clone(), v.clone())?;
+                }
+                mlua::Value::Table(table)
+            }
+        })
+    }
+}

+ 752 - 0
packages/cli/src/server/mod.rs

@@ -0,0 +1,752 @@
+use crate::{builder, plugin::PluginManager, serve::Serve, BuildResult, CrateConfig, Result};
+use axum::{
+    body::{Full, HttpBody},
+    extract::{ws::Message, Extension, TypedHeader, WebSocketUpgrade},
+    http::{
+        header::{HeaderName, HeaderValue},
+        Method, Response, StatusCode,
+    },
+    response::IntoResponse,
+    routing::{get, get_service},
+    Router,
+};
+use cargo_metadata::diagnostic::Diagnostic;
+use colored::Colorize;
+use dioxus_core::Template;
+use dioxus_html::HtmlCtx;
+use dioxus_rsx::hot_reload::*;
+use notify::{RecommendedWatcher, Watcher};
+use std::{
+    net::UdpSocket,
+    path::PathBuf,
+    process::Command,
+    sync::{Arc, Mutex},
+};
+use tokio::sync::broadcast;
+use tower::ServiceBuilder;
+use tower_http::services::fs::{ServeDir, ServeFileSystemResponseBody};
+use tower_http::{
+    cors::{Any, CorsLayer},
+    ServiceBuilderExt,
+};
+mod proxy;
+
+pub struct BuildManager {
+    config: CrateConfig,
+    reload_tx: broadcast::Sender<()>,
+}
+
+impl BuildManager {
+    fn rebuild(&self) -> Result<BuildResult> {
+        log::info!("🪁 Rebuild project");
+        let result = builder::build(&self.config, true)?;
+        // change the websocket reload state to true;
+        // the page will auto-reload.
+        if self
+            .config
+            .dioxus_config
+            .web
+            .watcher
+            .reload_html
+            .unwrap_or(false)
+        {
+            let _ = Serve::regen_dev_page(&self.config);
+        }
+        let _ = self.reload_tx.send(());
+        Ok(result)
+    }
+}
+
+struct WsReloadState {
+    update: broadcast::Sender<()>,
+}
+
+pub async fn startup(port: u16, config: CrateConfig, start_browser: bool) -> Result<()> {
+    // ctrl-c shutdown checker
+    let crate_config = config.clone();
+    let _ = ctrlc::set_handler(move || {
+        let _ = PluginManager::on_serve_shutdown(&crate_config);
+        std::process::exit(0);
+    });
+
+    let ip = get_ip().unwrap_or(String::from("0.0.0.0"));
+
+    if config.hot_reload {
+        startup_hot_reload(ip, port, config, start_browser).await?
+    } else {
+        startup_default(ip, port, config, start_browser).await?
+    }
+    Ok(())
+}
+
+pub struct HotReloadState {
+    pub messages: broadcast::Sender<Template<'static>>,
+    pub build_manager: Arc<BuildManager>,
+    pub file_map: Arc<Mutex<FileMap<HtmlCtx>>>,
+    pub watcher_config: CrateConfig,
+}
+
+pub async fn hot_reload_handler(
+    ws: WebSocketUpgrade,
+    _: Option<TypedHeader<headers::UserAgent>>,
+    Extension(state): Extension<Arc<HotReloadState>>,
+) -> impl IntoResponse {
+    ws.on_upgrade(|mut socket| async move {
+        log::info!("🔥 Hot Reload WebSocket connected");
+        {
+            // update any rsx calls that changed before the websocket connected.
+            {
+                log::info!("🔮 Finding updates since last compile...");
+                let templates: Vec<_> = {
+                    state
+                        .file_map
+                        .lock()
+                        .unwrap()
+                        .map
+                        .values()
+                        .filter_map(|(_, template_slot)| *template_slot)
+                        .collect()
+                };
+                for template in templates {
+                    if socket
+                        .send(Message::Text(serde_json::to_string(&template).unwrap()))
+                        .await
+                        .is_err()
+                    {
+                        return;
+                    }
+                }
+            }
+            log::info!("finished");
+        }
+
+        let mut rx = state.messages.subscribe();
+        loop {
+            if let Ok(rsx) = rx.recv().await {
+                if socket
+                    .send(Message::Text(serde_json::to_string(&rsx).unwrap()))
+                    .await
+                    .is_err()
+                {
+                    break;
+                };
+            }
+        }
+    })
+}
+
+#[allow(unused_assignments)]
+pub async fn startup_hot_reload(
+    ip: String,
+    port: u16,
+    config: CrateConfig,
+    start_browser: bool,
+) -> Result<()> {
+    let first_build_result = crate::builder::build(&config, false)?;
+
+    log::info!("🚀 Starting development server...");
+
+    PluginManager::on_serve_start(&config)?;
+
+    let dist_path = config.out_dir.clone();
+    let (reload_tx, _) = broadcast::channel(100);
+    let FileMapBuildResult { map, errors } =
+        FileMap::<HtmlCtx>::create(config.crate_dir.clone()).unwrap();
+    for err in errors {
+        log::error!("{}", err);
+    }
+    let file_map = Arc::new(Mutex::new(map));
+    let build_manager = Arc::new(BuildManager {
+        config: config.clone(),
+        reload_tx: reload_tx.clone(),
+    });
+    let hot_reload_tx = broadcast::channel(100).0;
+    let hot_reload_state = Arc::new(HotReloadState {
+        messages: hot_reload_tx.clone(),
+        build_manager: build_manager.clone(),
+        file_map: file_map.clone(),
+        watcher_config: config.clone(),
+    });
+
+    let crate_dir = config.crate_dir.clone();
+    let ws_reload_state = Arc::new(WsReloadState {
+        update: reload_tx.clone(),
+    });
+
+    // file watcher: check file change
+    let allow_watch_path = config
+        .dioxus_config
+        .web
+        .watcher
+        .watch_path
+        .clone()
+        .unwrap_or_else(|| vec![PathBuf::from("src")]);
+
+    let watcher_config = config.clone();
+    let watcher_ip = ip.clone();
+    let mut last_update_time = chrono::Local::now().timestamp();
+
+    let mut watcher = RecommendedWatcher::new(
+        move |evt: notify::Result<notify::Event>| {
+            let config = watcher_config.clone();
+            // Give time for the change to take effect before reading the file
+            std::thread::sleep(std::time::Duration::from_millis(100));
+            if chrono::Local::now().timestamp() > last_update_time {
+                if let Ok(evt) = evt {
+                    let mut messages: Vec<Template<'static>> = Vec::new();
+                    for path in evt.paths.clone() {
+                        // if this is not a rust file, rebuild the whole project
+                        if path.extension().and_then(|p| p.to_str()) != Some("rs") {
+                            match build_manager.rebuild() {
+                                Ok(res) => {
+                                    print_console_info(
+                                        &watcher_ip,
+                                        port,
+                                        &config,
+                                        PrettierOptions {
+                                            changed: evt.paths,
+                                            warnings: res.warnings,
+                                            elapsed_time: res.elapsed_time,
+                                        },
+                                    );
+                                }
+                                Err(err) => {
+                                    log::error!("{}", err);
+                                }
+                            }
+                            return;
+                        }
+                        // find changes to the rsx in the file
+                        let mut map = file_map.lock().unwrap();
+
+                        match map.update_rsx(&path, &crate_dir) {
+                            Ok(UpdateResult::UpdatedRsx(msgs)) => {
+                                messages.extend(msgs);
+                            }
+                            Ok(UpdateResult::NeedsRebuild) => {
+                                match build_manager.rebuild() {
+                                    Ok(res) => {
+                                        print_console_info(
+                                            &watcher_ip,
+                                            port,
+                                            &config,
+                                            PrettierOptions {
+                                                changed: evt.paths,
+                                                warnings: res.warnings,
+                                                elapsed_time: res.elapsed_time,
+                                            },
+                                        );
+                                    }
+                                    Err(err) => {
+                                        log::error!("{}", err);
+                                    }
+                                }
+                                return;
+                            }
+                            Err(err) => {
+                                log::error!("{}", err);
+                            }
+                        }
+                    }
+                    for msg in messages {
+                        let _ = hot_reload_tx.send(msg);
+                    }
+                }
+                last_update_time = chrono::Local::now().timestamp();
+            }
+        },
+        notify::Config::default(),
+    )
+    .unwrap();
+
+    for sub_path in allow_watch_path {
+        if let Err(err) = watcher.watch(
+            &config.crate_dir.join(&sub_path),
+            notify::RecursiveMode::Recursive,
+        ) {
+            log::error!("error watching {sub_path:?}: \n{}", err);
+        }
+    }
+
+    // start serve dev-server at 0.0.0.0:8080
+    print_console_info(
+        &ip,
+        port,
+        &config,
+        PrettierOptions {
+            changed: vec![],
+            warnings: first_build_result.warnings,
+            elapsed_time: first_build_result.elapsed_time,
+        },
+    );
+
+    let cors = CorsLayer::new()
+        // allow `GET` and `POST` when accessing the resource
+        .allow_methods([Method::GET, Method::POST])
+        // allow requests from any origin
+        .allow_origin(Any)
+        .allow_headers(Any);
+
+    let (coep, coop) = if config.cross_origin_policy {
+        (
+            HeaderValue::from_static("require-corp"),
+            HeaderValue::from_static("same-origin"),
+        )
+    } else {
+        (
+            HeaderValue::from_static("unsafe-none"),
+            HeaderValue::from_static("unsafe-none"),
+        )
+    };
+
+    let file_service_config = config.clone();
+    let file_service = ServiceBuilder::new()
+        .override_response_header(
+            HeaderName::from_static("cross-origin-embedder-policy"),
+            coep,
+        )
+        .override_response_header(HeaderName::from_static("cross-origin-opener-policy"), coop)
+        .and_then(
+            move |response: Response<ServeFileSystemResponseBody>| async move {
+                let response = if file_service_config
+                    .dioxus_config
+                    .web
+                    .watcher
+                    .index_on_404
+                    .unwrap_or(false)
+                    && response.status() == StatusCode::NOT_FOUND
+                {
+                    let body = Full::from(
+                        // TODO: Cache/memoize this.
+                        std::fs::read_to_string(
+                            file_service_config
+                                .crate_dir
+                                .join(file_service_config.out_dir)
+                                .join("index.html"),
+                        )
+                        .ok()
+                        .unwrap(),
+                    )
+                    .map_err(|err| match err {})
+                    .boxed();
+                    Response::builder()
+                        .status(StatusCode::OK)
+                        .body(body)
+                        .unwrap()
+                } else {
+                    response.map(|body| body.boxed())
+                };
+                Ok(response)
+            },
+        )
+        .service(ServeDir::new(config.crate_dir.join(&dist_path)));
+
+    let mut router = Router::new().route("/_dioxus/ws", get(ws_handler));
+    for proxy_config in config.dioxus_config.web.proxy.unwrap_or_default() {
+        router = proxy::add_proxy(router, &proxy_config)?;
+    }
+    router = router.fallback(get_service(file_service).handle_error(
+        |error: std::io::Error| async move {
+            (
+                StatusCode::INTERNAL_SERVER_ERROR,
+                format!("Unhandled internal error: {}", error),
+            )
+        },
+    ));
+
+    let router = router
+        .route("/_dioxus/hot_reload", get(hot_reload_handler))
+        .layer(cors)
+        .layer(Extension(ws_reload_state))
+        .layer(Extension(hot_reload_state));
+
+    let addr = format!("0.0.0.0:{}", port).parse().unwrap();
+
+    let server = axum::Server::bind(&addr).serve(router.into_make_service());
+
+    if start_browser {
+        let _ = open::that(format!("http://{}", addr));
+    }
+
+    server.await?;
+
+    Ok(())
+}
+
+pub async fn startup_default(
+    ip: String,
+    port: u16,
+    config: CrateConfig,
+    start_browser: bool,
+) -> Result<()> {
+    let first_build_result = crate::builder::build(&config, false)?;
+
+    log::info!("🚀 Starting development server...");
+
+    let dist_path = config.out_dir.clone();
+
+    let (reload_tx, _) = broadcast::channel(100);
+
+    let build_manager = BuildManager {
+        config: config.clone(),
+        reload_tx: reload_tx.clone(),
+    };
+
+    let ws_reload_state = Arc::new(WsReloadState {
+        update: reload_tx.clone(),
+    });
+
+    let mut last_update_time = chrono::Local::now().timestamp();
+
+    // file watcher: check file change
+    let allow_watch_path = config
+        .dioxus_config
+        .web
+        .watcher
+        .watch_path
+        .clone()
+        .unwrap_or_else(|| vec![PathBuf::from("src")]);
+
+    let watcher_config = config.clone();
+    let watcher_ip = ip.clone();
+    let mut watcher = notify::recommended_watcher(move |info: notify::Result<notify::Event>| {
+        let config = watcher_config.clone();
+        if let Ok(e) = info {
+            if chrono::Local::now().timestamp() > last_update_time {
+                match build_manager.rebuild() {
+                    Ok(res) => {
+                        last_update_time = chrono::Local::now().timestamp();
+                        print_console_info(
+                            &watcher_ip,
+                            port,
+                            &config,
+                            PrettierOptions {
+                                changed: e.paths.clone(),
+                                warnings: res.warnings,
+                                elapsed_time: res.elapsed_time,
+                            },
+                        );
+                        let _ = PluginManager::on_serve_rebuild(
+                            chrono::Local::now().timestamp(),
+                            e.paths,
+                        );
+                    }
+                    Err(e) => log::error!("{}", e),
+                }
+            }
+        }
+    })
+    .unwrap();
+
+    for sub_path in allow_watch_path {
+        watcher
+            .watch(
+                &config.crate_dir.join(sub_path),
+                notify::RecursiveMode::Recursive,
+            )
+            .unwrap();
+    }
+
+    // start serve dev-server at 0.0.0.0
+    print_console_info(
+        &ip,
+        port,
+        &config,
+        PrettierOptions {
+            changed: vec![],
+            warnings: first_build_result.warnings,
+            elapsed_time: first_build_result.elapsed_time,
+        },
+    );
+
+    PluginManager::on_serve_start(&config)?;
+
+    let cors = CorsLayer::new()
+        // allow `GET` and `POST` when accessing the resource
+        .allow_methods([Method::GET, Method::POST])
+        // allow requests from any origin
+        .allow_origin(Any)
+        .allow_headers(Any);
+
+    let (coep, coop) = if config.cross_origin_policy {
+        (
+            HeaderValue::from_static("require-corp"),
+            HeaderValue::from_static("same-origin"),
+        )
+    } else {
+        (
+            HeaderValue::from_static("unsafe-none"),
+            HeaderValue::from_static("unsafe-none"),
+        )
+    };
+
+    let file_service_config = config.clone();
+    let file_service = ServiceBuilder::new()
+        .override_response_header(
+            HeaderName::from_static("cross-origin-embedder-policy"),
+            coep,
+        )
+        .override_response_header(HeaderName::from_static("cross-origin-opener-policy"), coop)
+        .and_then(
+            move |response: Response<ServeFileSystemResponseBody>| async move {
+                let response = if file_service_config
+                    .dioxus_config
+                    .web
+                    .watcher
+                    .index_on_404
+                    .unwrap_or(false)
+                    && response.status() == StatusCode::NOT_FOUND
+                {
+                    let body = Full::from(
+                        // TODO: Cache/memoize this.
+                        std::fs::read_to_string(
+                            file_service_config
+                                .crate_dir
+                                .join(file_service_config.out_dir)
+                                .join("index.html"),
+                        )
+                        .ok()
+                        .unwrap(),
+                    )
+                    .map_err(|err| match err {})
+                    .boxed();
+                    Response::builder()
+                        .status(StatusCode::OK)
+                        .body(body)
+                        .unwrap()
+                } else {
+                    response.map(|body| body.boxed())
+                };
+                Ok(response)
+            },
+        )
+        .service(ServeDir::new(config.crate_dir.join(&dist_path)));
+
+    let mut router = Router::new().route("/_dioxus/ws", get(ws_handler));
+    for proxy_config in config.dioxus_config.web.proxy.unwrap_or_default() {
+        router = proxy::add_proxy(router, &proxy_config)?;
+    }
+    router = router
+        .fallback(
+            get_service(file_service).handle_error(|error: std::io::Error| async move {
+                (
+                    StatusCode::INTERNAL_SERVER_ERROR,
+                    format!("Unhandled internal error: {}", error),
+                )
+            }),
+        )
+        .layer(cors)
+        .layer(Extension(ws_reload_state));
+
+    let addr = format!("0.0.0.0:{}", port).parse().unwrap();
+    let server = axum::Server::bind(&addr).serve(router.into_make_service());
+
+    if start_browser {
+        let _ = open::that(format!("http://{}", addr));
+    }
+
+    server.await?;
+
+    Ok(())
+}
+
+#[derive(Debug, Default)]
+pub struct PrettierOptions {
+    changed: Vec<PathBuf>,
+    warnings: Vec<Diagnostic>,
+    elapsed_time: u128,
+}
+
+fn print_console_info(ip: &String, port: u16, config: &CrateConfig, options: PrettierOptions) {
+    if let Ok(native_clearseq) = Command::new(if cfg!(target_os = "windows") {
+        "cls"
+    } else {
+        "clear"
+    })
+    .output()
+    {
+        print!("{}", String::from_utf8_lossy(&native_clearseq.stdout));
+    } else {
+        // Try ANSI-Escape characters
+        print!("\x1b[2J\x1b[H");
+    }
+
+    // for path in &changed {
+    //     let path = path
+    //         .strip_prefix(crate::crate_root().unwrap())
+    //         .unwrap()
+    //         .to_path_buf();
+    //     log::info!("Updated {}", format!("{}", path.to_str().unwrap()).green());
+    // }
+
+    let mut profile = if config.release { "Release" } else { "Debug" }.to_string();
+    if config.custom_profile.is_some() {
+        profile = config.custom_profile.as_ref().unwrap().to_string();
+    }
+    let hot_reload = if config.hot_reload { "RSX" } else { "Normal" };
+    let crate_root = crate::cargo::crate_root().unwrap();
+    let custom_html_file = if crate_root.join("index.html").is_file() {
+        "Custom [index.html]"
+    } else {
+        "Default"
+    };
+    let url_rewrite = if config
+        .dioxus_config
+        .web
+        .watcher
+        .index_on_404
+        .unwrap_or(false)
+    {
+        "True"
+    } else {
+        "False"
+    };
+
+    let proxies = config.dioxus_config.web.proxy.as_ref();
+
+    if options.changed.is_empty() {
+        println!(
+            "{} @ v{} [{}] \n",
+            "Dioxus".bold().green(),
+            crate::DIOXUS_CLI_VERSION,
+            chrono::Local::now().format("%H:%M:%S").to_string().dimmed()
+        );
+    } else {
+        println!(
+            "Project Reloaded: {}\n",
+            format!(
+                "Changed {} files. [{}]",
+                options.changed.len(),
+                chrono::Local::now().format("%H:%M:%S").to_string().dimmed()
+            )
+            .purple()
+            .bold()
+        );
+    }
+    println!(
+        "\t> Local : {}",
+        format!("http://localhost:{}/", port).blue()
+    );
+    println!(
+        "\t> Network : {}",
+        format!("http://{}:{}/", ip, port).blue()
+    );
+    println!("");
+    println!("\t> Profile : {}", profile.green());
+    println!("\t> Hot Reload : {}", hot_reload.cyan());
+    if let Some(proxies) = proxies {
+        if !proxies.is_empty() {
+            println!("\t> Proxies :");
+            for proxy in proxies {
+                println!("\t\t- {}", proxy.backend.blue());
+            }
+        }
+    }
+    println!("\t> Index Template : {}", custom_html_file.green());
+    println!("\t> URL Rewrite [index_on_404] : {}", url_rewrite.purple());
+    println!("");
+    println!(
+        "\t> Build Time Use : {} millis",
+        options.elapsed_time.to_string().green().bold()
+    );
+    println!("");
+
+    if options.warnings.len() == 0 {
+        log::info!("{}\n", "A perfect compilation!".green().bold());
+    } else {
+        log::warn!(
+            "{}",
+            format!(
+                "There were {} warning messages during the build.",
+                options.warnings.len() - 1
+            )
+            .yellow()
+            .bold()
+        );
+        // for info in &options.warnings {
+        //     let message = info.message.clone();
+        //     if message == format!("{} warnings emitted", options.warnings.len() - 1) {
+        //         continue;
+        //     }
+        //     let mut console = String::new();
+        //     for span in &info.spans {
+        //         let file = &span.file_name;
+        //         let line = (span.line_start, span.line_end);
+        //         let line_str = if line.0 == line.1 {
+        //             line.0.to_string()
+        //         } else {
+        //             format!("{}~{}", line.0, line.1)
+        //         };
+        //         let code = span.text.clone();
+        //         let span_info = if code.len() == 1 {
+        //             let code = code.get(0).unwrap().text.trim().blue().bold().to_string();
+        //             format!(
+        //                 "[{}: {}]: '{}' --> {}",
+        //                 file,
+        //                 line_str,
+        //                 code,
+        //                 message.yellow().bold()
+        //             )
+        //         } else {
+        //             let code = code
+        //                 .iter()
+        //                 .enumerate()
+        //                 .map(|(_i, s)| format!("\t{}\n", s.text).blue().bold().to_string())
+        //                 .collect::<String>();
+        //             format!("[{}: {}]:\n{}\n#:{}", file, line_str, code, message)
+        //         };
+        //         console = format!("{console}\n\t{span_info}");
+        //     }
+        //     println!("{console}");
+        // }
+        // println!(
+        //     "\n{}\n",
+        //     "Resolving all warnings will help your code run better!".yellow()
+        // );
+    }
+}
+
+fn get_ip() -> Option<String> {
+    let socket = match UdpSocket::bind("0.0.0.0:0") {
+        Ok(s) => s,
+        Err(_) => return None,
+    };
+
+    match socket.connect("8.8.8.8:80") {
+        Ok(()) => (),
+        Err(_) => return None,
+    };
+
+    match socket.local_addr() {
+        Ok(addr) => return Some(addr.ip().to_string()),
+        Err(_) => return None,
+    };
+}
+
+async fn ws_handler(
+    ws: WebSocketUpgrade,
+    _: Option<TypedHeader<headers::UserAgent>>,
+    Extension(state): Extension<Arc<WsReloadState>>,
+) -> impl IntoResponse {
+    ws.on_upgrade(|mut socket| async move {
+        let mut rx = state.update.subscribe();
+        let reload_watcher = tokio::spawn(async move {
+            loop {
+                rx.recv().await.unwrap();
+                // ignore the error
+                if socket
+                    .send(Message::Text(String::from("reload")))
+                    .await
+                    .is_err()
+                {
+                    break;
+                }
+
+                // flush the errors after recompling
+                rx = rx.resubscribe();
+            }
+        });
+
+        reload_watcher.await.unwrap();
+    })
+}

+ 171 - 0
packages/cli/src/server/proxy.rs

@@ -0,0 +1,171 @@
+use crate::{Result, WebProxyConfig};
+
+use anyhow::Context;
+use axum::{http::StatusCode, routing::any, Router};
+use hyper::{Request, Response, Uri};
+
+#[derive(Debug, Clone)]
+struct ProxyClient {
+    inner: hyper::Client<hyper_rustls::HttpsConnector<hyper::client::HttpConnector>>,
+    url: Uri,
+}
+
+impl ProxyClient {
+    fn new(url: Uri) -> Self {
+        let https = hyper_rustls::HttpsConnectorBuilder::new()
+            .with_native_roots()
+            .https_or_http()
+            .enable_http1()
+            .build();
+        Self {
+            inner: hyper::Client::builder().build(https),
+            url,
+        }
+    }
+
+    async fn send(
+        &self,
+        mut req: Request<hyper::body::Body>,
+    ) -> Result<Response<hyper::body::Body>> {
+        let mut uri_parts = req.uri().clone().into_parts();
+        uri_parts.authority = self.url.authority().cloned();
+        uri_parts.scheme = self.url.scheme().cloned();
+        *req.uri_mut() = Uri::from_parts(uri_parts).context("Invalid URI parts")?;
+        self.inner
+            .request(req)
+            .await
+            .map_err(crate::error::Error::ProxyRequestError)
+    }
+}
+
+/// Add routes to the router handling the specified proxy config.
+///
+/// We will proxy requests directed at either:
+///
+/// - the exact path of the proxy config's backend URL, e.g. /api
+/// - the exact path with a trailing slash, e.g. /api/
+/// - any subpath of the backend URL, e.g. /api/foo/bar
+pub fn add_proxy(mut router: Router, proxy: &WebProxyConfig) -> Result<Router> {
+    let url: Uri = proxy.backend.parse()?;
+    let path = url.path().to_string();
+    let client = ProxyClient::new(url);
+
+    // We also match everything after the path using a wildcard matcher.
+    let wildcard_client = client.clone();
+
+    router = router.route(
+        // Always remove trailing /'s so that the exact route
+        // matches.
+        path.trim_end_matches('/'),
+        any(move |req| async move {
+            client
+                .send(req)
+                .await
+                .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
+        }),
+    );
+
+    // Wildcard match anything else _after_ the backend URL's path.
+    // Note that we know `path` ends with a trailing `/` in this branch,
+    // so `wildcard` will look like `http://localhost/api/*proxywildcard`.
+    let wildcard = format!("{}/*proxywildcard", path.trim_end_matches('/'));
+    router = router.route(
+        &wildcard,
+        any(move |req| async move {
+            wildcard_client
+                .send(req)
+                .await
+                .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
+        }),
+    );
+    Ok(router)
+}
+
+#[cfg(test)]
+mod test {
+
+    use super::*;
+
+    use axum::{extract::Path, Router};
+
+    fn setup_servers(
+        mut config: WebProxyConfig,
+    ) -> (
+        tokio::task::JoinHandle<()>,
+        tokio::task::JoinHandle<()>,
+        String,
+    ) {
+        let backend_router = Router::new().route(
+            "/*path",
+            any(|path: Path<String>| async move { format!("backend: {}", path.0) }),
+        );
+        let backend_server = axum::Server::bind(&"127.0.0.1:0".parse().unwrap())
+            .serve(backend_router.into_make_service());
+        let backend_addr = backend_server.local_addr();
+        let backend_handle = tokio::spawn(async move { backend_server.await.unwrap() });
+        config.backend = format!("http://{}{}", backend_addr, config.backend);
+        let router = super::add_proxy(Router::new(), &config);
+        let server = axum::Server::bind(&"127.0.0.1:0".parse().unwrap())
+            .serve(router.unwrap().into_make_service());
+        let server_addr = server.local_addr();
+        let server_handle = tokio::spawn(async move { server.await.unwrap() });
+        (backend_handle, server_handle, server_addr.to_string())
+    }
+
+    async fn test_proxy_requests(path: String) {
+        let config = WebProxyConfig {
+            // Normally this would be an absolute URL including scheme/host/port,
+            // but in these tests we need to let the OS choose the port so tests
+            // don't conflict, so we'll concatenate the final address and this
+            // path together.
+            // So in day to day usage, use `http://localhost:8000/api` instead!
+            backend: path,
+        };
+        let (backend_handle, server_handle, server_addr) = setup_servers(config);
+        let resp = hyper::Client::new()
+            .get(format!("http://{}/api", server_addr).parse().unwrap())
+            .await
+            .unwrap();
+        assert_eq!(resp.status(), StatusCode::OK);
+        assert_eq!(
+            hyper::body::to_bytes(resp.into_body()).await.unwrap(),
+            "backend: /api"
+        );
+
+        let resp = hyper::Client::new()
+            .get(format!("http://{}/api/", server_addr).parse().unwrap())
+            .await
+            .unwrap();
+        assert_eq!(resp.status(), StatusCode::OK);
+        assert_eq!(
+            hyper::body::to_bytes(resp.into_body()).await.unwrap(),
+            "backend: /api/"
+        );
+
+        let resp = hyper::Client::new()
+            .get(
+                format!("http://{}/api/subpath", server_addr)
+                    .parse()
+                    .unwrap(),
+            )
+            .await
+            .unwrap();
+        assert_eq!(resp.status(), StatusCode::OK);
+        assert_eq!(
+            hyper::body::to_bytes(resp.into_body()).await.unwrap(),
+            "backend: /api/subpath"
+        );
+        backend_handle.abort();
+        server_handle.abort();
+    }
+
+    #[tokio::test]
+    async fn add_proxy() {
+        test_proxy_requests("/api".to_string()).await;
+    }
+
+    #[tokio::test]
+    async fn add_proxy_trailing_slash() {
+        test_proxy_requests("/api/".to_string()).await;
+    }
+}

+ 349 - 0
packages/cli/src/tools.rs

@@ -0,0 +1,349 @@
+use std::{
+    fs::{create_dir_all, File},
+    io::{ErrorKind, Read, Write},
+    path::{Path, PathBuf},
+    process::Command,
+};
+
+use anyhow::Context;
+use flate2::read::GzDecoder;
+use futures::StreamExt;
+use tar::Archive;
+use tokio::io::AsyncWriteExt;
+
+#[derive(Debug, PartialEq, Eq)]
+pub enum Tool {
+    Binaryen,
+    Sass,
+    Tailwind,
+}
+
+// pub fn tool_list() -> Vec<&'static str> {
+//     vec!["binaryen", "sass", "tailwindcss"]
+// }
+
+pub fn app_path() -> PathBuf {
+    let data_local = dirs::data_local_dir().unwrap();
+    let dioxus_dir = data_local.join("dioxus");
+    if !dioxus_dir.is_dir() {
+        create_dir_all(&dioxus_dir).unwrap();
+    }
+    dioxus_dir
+}
+
+pub fn temp_path() -> PathBuf {
+    let app_path = app_path();
+    let temp_path = app_path.join("temp");
+    if !temp_path.is_dir() {
+        create_dir_all(&temp_path).unwrap();
+    }
+    temp_path
+}
+
+pub fn clone_repo(dir: &Path, url: &str) -> anyhow::Result<()> {
+    let target_dir = dir.parent().unwrap();
+    let dir_name = dir.file_name().unwrap();
+
+    let mut cmd = Command::new("git");
+    let cmd = cmd.current_dir(target_dir);
+    let res = cmd.arg("clone").arg(url).arg(dir_name).output();
+    if let Err(err) = res {
+        if ErrorKind::NotFound == err.kind() {
+            log::warn!("Git program not found. Hint: Install git or check $PATH.");
+            return Err(err.into());
+        }
+    }
+    Ok(())
+}
+
+pub fn tools_path() -> PathBuf {
+    let app_path = app_path();
+    let temp_path = app_path.join("tools");
+    if !temp_path.is_dir() {
+        create_dir_all(&temp_path).unwrap();
+    }
+    temp_path
+}
+
+#[allow(clippy::should_implement_trait)]
+impl Tool {
+    /// from str to tool enum
+    pub fn from_str(name: &str) -> Option<Self> {
+        match name {
+            "binaryen" => Some(Self::Binaryen),
+            "sass" => Some(Self::Sass),
+            "tailwindcss" => Some(Self::Tailwind),
+            _ => None,
+        }
+    }
+
+    /// get current tool name str
+    pub fn name(&self) -> &str {
+        match self {
+            Self::Binaryen => "binaryen",
+            Self::Sass => "sass",
+            Self::Tailwind => "tailwindcss",
+        }
+    }
+
+    /// get tool bin dir path
+    pub fn bin_path(&self) -> &str {
+        match self {
+            Self::Binaryen => "bin",
+            Self::Sass => ".",
+            Self::Tailwind => ".",
+        }
+    }
+
+    /// get target platform
+    pub fn target_platform(&self) -> &str {
+        match self {
+            Self::Binaryen => {
+                if cfg!(target_os = "windows") {
+                    "windows"
+                } else if cfg!(target_os = "macos") {
+                    "macos"
+                } else if cfg!(target_os = "linux") {
+                    "linux"
+                } else {
+                    panic!("unsupported platformm");
+                }
+            }
+            Self::Sass => {
+                if cfg!(target_os = "windows") {
+                    "windows"
+                } else if cfg!(target_os = "macos") {
+                    "macos"
+                } else if cfg!(target_os = "linux") {
+                    "linux"
+                } else {
+                    panic!("unsupported platformm");
+                }
+            }
+            Self::Tailwind => {
+                if cfg!(target_os = "windows") {
+                    "windows"
+                } else if cfg!(target_os = "macos") {
+                    "macos"
+                } else if cfg!(target_os = "linux") {
+                    "linux"
+                } else {
+                    panic!("unsupported platformm");
+                }
+            }
+        }
+    }
+
+    /// get tool version
+    pub fn tool_version(&self) -> &str {
+        match self {
+            Self::Binaryen => "version_105",
+            Self::Sass => "1.51.0",
+            Self::Tailwind => "v3.1.6",
+        }
+    }
+
+    /// get tool package download url
+    pub fn download_url(&self) -> String {
+        match self {
+            Self::Binaryen => {
+                format!(
+                    "https://github.com/WebAssembly/binaryen/releases/download/{version}/binaryen-{version}-x86_64-{target}.tar.gz",
+                    version = self.tool_version(),
+                    target = self.target_platform()
+                )
+            }
+            Self::Sass => {
+                format!(
+                    "https://github.com/sass/dart-sass/releases/download/{version}/dart-sass-{version}-{target}-x64.{extension}",
+                    version = self.tool_version(),
+                    target = self.target_platform(),
+                    extension = self.extension()
+                )
+            }
+            Self::Tailwind => {
+                let windows_extension = match self.target_platform() {
+                    "windows" => ".exe",
+                    _ => "",
+                };
+                format!(
+                    "https://github.com/tailwindlabs/tailwindcss/releases/download/{version}/tailwindcss-{target}-x64{optional_ext}",
+                    version = self.tool_version(),
+                    target = self.target_platform(),
+                    optional_ext = windows_extension
+                )
+            }
+        }
+    }
+
+    /// get package extension name
+    pub fn extension(&self) -> &str {
+        match self {
+            Self::Binaryen => "tar.gz",
+            Self::Sass => {
+                if cfg!(target_os = "windows") {
+                    "zip"
+                } else {
+                    "tar.gz"
+                }
+            }
+            Self::Tailwind => "bin",
+        }
+    }
+
+    /// check tool state
+    pub fn is_installed(&self) -> bool {
+        tools_path().join(self.name()).is_dir()
+    }
+
+    /// get download temp path
+    pub fn temp_out_path(&self) -> PathBuf {
+        temp_path().join(format!("{}-tool.tmp", self.name()))
+    }
+
+    /// start to download package
+    pub async fn download_package(&self) -> anyhow::Result<PathBuf> {
+        let download_url = self.download_url();
+        let temp_out = self.temp_out_path();
+        let mut file = tokio::fs::File::create(&temp_out)
+            .await
+            .context("failed creating temporary output file")?;
+
+        let resp = reqwest::get(download_url).await.unwrap();
+
+        let mut res_bytes = resp.bytes_stream();
+        while let Some(chunk_res) = res_bytes.next().await {
+            let chunk = chunk_res.context("error reading chunk from download")?;
+            let _ = file.write(chunk.as_ref()).await;
+        }
+        // log::info!("temp file path: {:?}", temp_out);
+        Ok(temp_out)
+    }
+
+    /// start to install package
+    pub async fn install_package(&self) -> anyhow::Result<()> {
+        let temp_path = self.temp_out_path();
+        let tool_path = tools_path();
+
+        let dir_name = match self {
+            Self::Binaryen => format!("binaryen-{}", self.tool_version()),
+            Self::Sass => "dart-sass".to_string(),
+            Self::Tailwind => self.name().to_string(),
+        };
+
+        if self.extension() == "tar.gz" {
+            let tar_gz = File::open(temp_path)?;
+            let tar = GzDecoder::new(tar_gz);
+            let mut archive = Archive::new(tar);
+            archive.unpack(&tool_path)?;
+            std::fs::rename(tool_path.join(dir_name), tool_path.join(self.name()))?;
+        } else if self.extension() == "zip" {
+            // decompress the `zip` file
+            extract_zip(&temp_path, &tool_path)?;
+            std::fs::rename(tool_path.join(dir_name), tool_path.join(self.name()))?;
+        } else if self.extension() == "bin" {
+            let bin_path = match self.target_platform() {
+                "windows" => tool_path.join(&dir_name).join(self.name()).join(".exe"),
+                _ => tool_path.join(&dir_name).join(self.name()),
+            };
+            // Manualy creating tool directory because we directly download the binary via Github
+            std::fs::create_dir(tool_path.join(dir_name))?;
+
+            let mut final_file = std::fs::File::create(&bin_path)?;
+            let mut temp_file = File::open(&temp_path)?;
+            let mut content = Vec::new();
+
+            temp_file.read_to_end(&mut content)?;
+            final_file.write_all(&content)?;
+
+            if self.target_platform() == "linux" {
+                // This code does not update permissions idk why
+                // let mut perms = final_file.metadata()?.permissions();
+                // perms.set_mode(0o744);
+
+                // Adding to the binary execution rights with "chmod"
+                let mut command = Command::new("chmod");
+
+                let _ = command
+                    .args(vec!["+x", bin_path.to_str().unwrap()])
+                    .stdout(std::process::Stdio::inherit())
+                    .stderr(std::process::Stdio::inherit())
+                    .output()?;
+            }
+
+            std::fs::remove_file(&temp_path)?;
+        }
+
+        Ok(())
+    }
+
+    pub fn call(&self, command: &str, args: Vec<&str>) -> anyhow::Result<Vec<u8>> {
+        let bin_path = tools_path().join(self.name()).join(self.bin_path());
+
+        let command_file = match self {
+            Tool::Binaryen => {
+                if cfg!(target_os = "windows") {
+                    format!("{}.exe", command)
+                } else {
+                    command.to_string()
+                }
+            }
+            Tool::Sass => {
+                if cfg!(target_os = "windows") {
+                    format!("{}.bat", command)
+                } else {
+                    command.to_string()
+                }
+            }
+            Tool::Tailwind => {
+                if cfg!(target_os = "windows") {
+                    format!("{}.exe", command)
+                } else {
+                    command.to_string()
+                }
+            }
+        };
+
+        if !bin_path.join(&command_file).is_file() {
+            return Err(anyhow::anyhow!("Command file not found."));
+        }
+
+        let mut command = Command::new(bin_path.join(&command_file).to_str().unwrap());
+
+        let output = command
+            .args(&args[..])
+            .stdout(std::process::Stdio::inherit())
+            .stderr(std::process::Stdio::inherit())
+            .output()?;
+        Ok(output.stdout)
+    }
+}
+
+pub fn extract_zip(file: &Path, target: &Path) -> anyhow::Result<()> {
+    let zip_file = std::fs::File::open(&file)?;
+    let mut zip = zip::ZipArchive::new(zip_file)?;
+
+    if !target.exists() {
+        let _ = std::fs::create_dir_all(target)?;
+    }
+
+    for i in 0..zip.len() {
+        let mut file = zip.by_index(i)?;
+        if file.is_dir() {
+            // dir
+            let target = target.join(Path::new(&file.name().replace('\\', "")));
+            let _ = std::fs::create_dir_all(target)?;
+        } else {
+            // file
+            let file_path = target.join(Path::new(file.name()));
+            let mut target_file = if !file_path.exists() {
+                std::fs::File::create(file_path)?
+            } else {
+                std::fs::File::open(file_path)?
+            };
+            let _num = std::io::copy(&mut file, &mut target_file)?;
+        }
+    }
+
+    Ok(())
+}

+ 4 - 0
packages/cli/tests/main.rs

@@ -0,0 +1,4 @@
+#[test]
+fn ready() {
+    println!("Compiled successfully!")
+}

+ 30 - 0
packages/cli/tests/svg.html

@@ -0,0 +1,30 @@
+<div>
+    <svg class="h-5 w-5 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
+    <path
+        fill-rule="evenodd"
+        d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
+        clip-rule="evenodd"
+    />
+    </svg>
+    <svg class="h-5 w-5 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
+    <path
+        fill-rule="evenodd"
+        d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
+        clip-rule="evenodd"
+    />
+    </svg>
+    <svg class="h-5 w-5 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
+    <path
+        fill-rule="evenodd"
+        d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
+        clip-rule="evenodd"
+    />
+    </svg>
+    <svg class="h-5 w-5 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
+    <path
+        fill-rule="evenodd"
+        d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
+        clip-rule="evenodd"
+    />
+    </svg>
+</div>

+ 48 - 0
packages/cli/tests/test.html

@@ -0,0 +1,48 @@
+<section class="text-gray-600 body-font">
+  <div class="container px-5 py-24 mx-auto">
+    <div class="flex flex-wrap -mx-4 -mb-10 text-center">
+      <div class="sm:w-1/2 mb-10 px-4">
+        <div class="rounded-lg h-64 overflow-hidden">
+          <img
+            alt="content"
+            class="object-cover object-center h-full w-full"
+            src="https://dummyimage.com/1201x501"
+          />
+        </div>
+        <h2 class="title-font text-2xl font-medium text-gray-900 mt-6 mb-3">
+          Buy YouTube Videos
+        </h2>
+        <p class="leading-relaxed text-base">
+          Williamsburg occupy sustainable snackwave gochujang. Pinterest
+          cornhole brunch, slow-carb neutra irony.
+        </p>
+        <button
+          class="flex mx-auto mt-6 text-white bg-indigo-500 border-0 py-2 px-5 focus:outline-none hover:bg-indigo-600 rounded"
+        >
+          Button
+        </button>
+      </div>
+      <div class="sm:w-1/2 mb-10 px-4">
+        <div class="rounded-lg h-64 overflow-hidden">
+          <img
+            alt="content"
+            class="object-cover object-center h-full w-full"
+            src="https://dummyimage.com/1202x502"
+          />
+        </div>
+        <h2 class="title-font text-2xl font-medium text-gray-900 mt-6 mb-3">
+          The Catalyzer
+        </h2>
+        <p class="leading-relaxed text-base">
+          Williamsburg occupy sustainable snackwave gochujang. Pinterest
+          cornhole brunch, slow-carb neutra irony.
+        </p>
+        <button
+          class="flex mx-auto mt-6 text-white bg-indigo-500 border-0 py-2 px-5 focus:outline-none hover:bg-indigo-600 rounded"
+        >
+          Button
+        </button>
+      </div>
+    </div>
+  </div>
+</section>