diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 8e94654d5fce93c74043e0ec06624595bb0675a7..0000000000000000000000000000000000000000
--- a/.editorconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-root = true
-
-[*]
-charset = utf-8
-end_of_line = lf
-indent_size = 2
-insert_final_newline = true
-
-[*.rs]
-charset = utf-8
-end_of_line = lf
-indent_size = 4
-insert_final_newline = true
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 6749373378f83373b6a8d5c689e25caa5956a8d1..0000000000000000000000000000000000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: "[BUG]"
-labels: bug
-assignees: ''
-
----
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-Steps to reproduce the behavior:
-1. Go to '...'
-2. Click on '....'
-3. Scroll down to '....'
-4. See error
-
-**Expected behavior**
-A clear and concise description of what you expected to happen.
-
-**Screenshots**
-If applicable, add screenshots to help explain your problem.
-
-**Information**
- - OS: [e.g. macOS]
- - Clash Verge Version: [e.g. 1.3.4]
- - Clash Core: [e.g. Clash or Clash Meta]
-
-**Additional context**
-Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 6269982f98c9abd9bbae660efd6cc74398eb7b51..0000000000000000000000000000000000000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: "[Feature]"
-labels: enhancement
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml
deleted file mode 100644
index 91eeb6c472f2405af23f087fa1a1f4e22ad1f899..0000000000000000000000000000000000000000
--- a/.github/workflows/alpha.yml
+++ /dev/null
@@ -1,93 +0,0 @@
-name: Alpha CI
-
-on:
-  workflow_dispatch:
-    inputs:
-      debug:
-        type: boolean
-        default: false
-
-env:
-  CARGO_INCREMENTAL: 0
-  RUST_BACKTRACE: short
-
-jobs:
-  release:
-    strategy:
-      fail-fast: false
-      matrix:
-        os: [windows-latest, ubuntu-20.04, macos-latest]
-    runs-on: ${{ matrix.os }}
-    if: startsWith(github.repository, 'zzzgydi')
-    steps:
-      - name: Checkout repository
-        uses: actions/checkout@v4
-
-      - name: install Rust stable
-        uses: dtolnay/rust-toolchain@stable
-
-      - name: Rust Cache
-        uses: Swatinem/rust-cache@v2
-        with:
-          workspaces: src-tauri
-
-      - name: Install Node
-        uses: actions/setup-node@v4
-        with:
-          node-version: "16"
-          cache: "yarn"
-
-      - name: Delete current release assets
-        if: startsWith(matrix.os, 'ubuntu-')
-        uses: mknejp/delete-release-assets@v1
-        with:
-          token: ${{ secrets.GITHUB_TOKEN }}
-          tag: alpha
-          fail-if-no-assets: false
-          fail-if-no-release: false
-          assets: |
-            *.zip
-            *.gz
-            *.AppImage
-            *.deb
-            *.dmg
-            *.msi
-            *.sig
-            *.exe
-
-      - name: Install Dependencies (ubuntu only)
-        if: startsWith(matrix.os, 'ubuntu-')
-        run: |
-          sudo apt-get update
-          sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf openssl
-
-      - name: Yarn install and check
-        run: |
-          yarn install --network-timeout 1000000 --frozen-lockfile
-          yarn run check
-
-      - name: Tauri build
-        uses: tauri-apps/tauri-action@v0
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
-          TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
-        with:
-          tagName: alpha
-          releaseName: "Clash Verge Alpha"
-          releaseBody: "Alpha Version (include debug)"
-          releaseDraft: false
-          prerelease: true
-          includeDebug: ${{ github.event.inputs.debug }}
-
-      - name: Portable Bundle
-        if: startsWith(matrix.os, 'windows-')
-        run: |
-          yarn build
-          yarn run portable
-        env:
-          TAG_NAME: alpha
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
-          TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
-          VITE_WIN_PORTABLE: 1
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
deleted file mode 100644
index 1fce34ffb0d3e5b35683cb3b2ea7fb56c67476ac..0000000000000000000000000000000000000000
--- a/.github/workflows/ci.yml
+++ /dev/null
@@ -1,98 +0,0 @@
-name: Release CI
-
-on:
-  workflow_dispatch:
-  push:
-    tags:
-      - v**
-
-env:
-  CARGO_INCREMENTAL: 0
-  RUST_BACKTRACE: short
-
-jobs:
-  release:
-    strategy:
-      matrix:
-        os: [windows-latest, ubuntu-latest, macos-latest]
-    runs-on: ${{ matrix.os }}
-    if: startsWith(github.repository, 'zzzgydi')
-    steps:
-      - name: Checkout repository
-        uses: actions/checkout@v4
-
-      - name: install Rust stable
-        uses: dtolnay/rust-toolchain@stable
-
-      - name: Rust Cache
-        uses: Swatinem/rust-cache@v2
-        with:
-          workspaces: src-tauri
-
-      - name: Install Node
-        uses: actions/setup-node@v4
-        with:
-          node-version: "16"
-          cache: "yarn"
-
-      - name: Install Dependencies (ubuntu only)
-        if: startsWith(matrix.os, 'ubuntu-')
-        run: |
-          sudo apt-get update
-          sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf openssl
-
-      - name: Yarn install and check
-        run: |
-          yarn install --network-timeout 1000000 --frozen-lockfile
-          yarn run check
-
-      - name: Tauri build
-        uses: tauri-apps/tauri-action@v0
-        # enable cache even though failed
-        # continue-on-error: true
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
-          TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
-        with:
-          tagName: v__VERSION__
-          releaseName: "Clash Verge v__VERSION__"
-          releaseBody: "More new features are now supported."
-          releaseDraft: false
-          prerelease: true
-
-      - name: Portable Bundle
-        if: startsWith(matrix.os, 'windows-')
-        # rebuild with env settings
-        run: |
-          yarn build
-          yarn run portable
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
-          TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
-          VITE_WIN_PORTABLE: 1
-
-  release-update:
-    needs: release
-    runs-on: ubuntu-latest
-    if: |
-      startsWith(github.repository, 'zzzgydi') &&
-      startsWith(github.ref, 'refs/tags/v')
-    steps:
-      - name: Checkout repository
-        uses: actions/checkout@v4
-
-      - name: Install Node
-        uses: actions/setup-node@v4
-        with:
-          node-version: "16"
-          cache: "yarn"
-
-      - name: Yarn install
-        run: yarn install --network-timeout 1000000 --frozen-lockfile
-
-      - name: Release updater file
-        run: yarn run updater
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/compatible.yml b/.github/workflows/compatible.yml
deleted file mode 100644
index abbbbb6787a03f57bcdf4008eb7754f7128a17a3..0000000000000000000000000000000000000000
--- a/.github/workflows/compatible.yml
+++ /dev/null
@@ -1,102 +0,0 @@
-name: Compatible CI
-
-on:
-  workflow_dispatch:
-  # push:
-  #   tags:
-  #     - v**
-
-env:
-  CARGO_INCREMENTAL: 0
-  RUST_BACKTRACE: short
-
-jobs:
-  build:
-    strategy:
-      fail-fast: false
-      matrix:
-        targets:
-          - tag: macOS-10.15
-            os: macos-10.15
-          - tag: Ubuntu18
-            os: ubuntu-18.04
-          - tag: Ubuntu22
-            os: ubuntu-22.04
-
-    runs-on: ${{ matrix.targets.os }}
-    if: startsWith(github.repository, 'zzzgydi')
-    steps:
-      - name: Checkout repository
-        uses: actions/checkout@v2
-
-      - name: Install Rust
-        uses: actions-rs/toolchain@v1
-        with:
-          toolchain: stable
-          profile: minimal
-          override: true
-
-      - name: Rust Cache
-        uses: Swatinem/rust-cache@v2
-        with:
-          workspaces: src-tauri
-
-      - name: Install Node
-        uses: actions/setup-node@v1
-        with:
-          node-version: 16
-
-      # - name: Install Dependencies (ubuntu18 only)
-      #   if: matrix.targets.os == 'ubuntu-18.04'
-      #   run: |
-      #     sudo apt-get update
-      #     sudo apt-get install -y libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libappindicator3-dev librsvg2-dev libayatana-appindicator3-dev
-
-      - name: Install Dependencies (ubuntu22 only)
-        if: startsWith(matrix.targets.os, 'ubuntu-')
-        run: |
-          sudo apt-get update
-          sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf
-
-      - name: Get yarn cache dir path
-        id: yarn-cache-dir-path
-        run: echo "::set-output name=dir::$(yarn cache dir)"
-
-      - name: Yarn Cache
-        uses: actions/cache@v2
-        id: yarn-cache
-        with:
-          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
-          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
-          restore-keys: |
-            ${{ runner.os }}-yarn-
-
-      - name: Yarn install and check
-        run: |
-          yarn install --network-timeout 1000000
-          yarn run check
-
-      - name: Tauri build
-        uses: tauri-apps/tauri-action@v0
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
-          TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
-        with:
-          tagName: ${{ matrix.targets.tag }}
-          releaseName: "Compatible For ${{ matrix.targets.tag }}"
-          releaseBody: "More new features are now supported."
-          releaseDraft: false
-          prerelease: false
-
-      # - name: Portable Bundle
-      #   if: matrix.os == 'windows-latest'
-      #   # rebuild with env settings
-      #   run: |
-      #     yarn build
-      #     yarn run portable
-      #   env:
-      #     GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-      #     TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
-      #     TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
-      #     VITE_WIN_PORTABLE: 1
diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml
deleted file mode 100644
index a26d9f0c88bcd07b0ddab89119a4f99ea9ebb68a..0000000000000000000000000000000000000000
--- a/.github/workflows/meta.yml
+++ /dev/null
@@ -1,107 +0,0 @@
-name: Meta CI
-
-on:
-  workflow_dispatch:
-  push:
-    tags:
-      - v**
-
-env:
-  CARGO_INCREMENTAL: 0
-  RUST_BACKTRACE: short
-
-jobs:
-  release:
-    strategy:
-      fail-fast: false
-      matrix:
-        os: [windows-latest, ubuntu-latest, macos-latest]
-    runs-on: ${{ matrix.os }}
-    if: startsWith(github.repository, 'zzzgydi')
-    steps:
-      - name: Checkout repository
-        uses: actions/checkout@v2
-
-      - name: Install Rust
-        uses: actions-rs/toolchain@v1
-        with:
-          toolchain: stable
-          profile: minimal
-          override: true
-
-      - name: Rust Cache
-        uses: Swatinem/rust-cache@v2
-        with:
-          workspaces: src-tauri
-
-      - name: Install Node
-        uses: actions/setup-node@v1
-        with:
-          node-version: 16
-
-      - name: Delete current release assets
-        if: matrix.os == 'ubuntu-latest'
-        uses: mknejp/delete-release-assets@v1
-        with:
-          token: ${{ secrets.GITHUB_TOKEN }}
-          tag: meta
-          fail-if-no-assets: false
-          fail-if-no-release: false
-          assets: |
-            *.zip
-            *.gz
-            *.AppImage
-            *.deb
-            *.dmg
-            *.msi
-            *.sig
-
-      - name: Install Dependencies (ubuntu only)
-        if: startsWith(matrix.os, 'ubuntu-')
-        run: |
-          sudo apt-get update
-          sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf openssl
-
-      - name: Get yarn cache dir path
-        id: yarn-cache-dir-path
-        run: echo "::set-output name=dir::$(yarn cache dir)"
-
-      - name: Yarn Cache
-        uses: actions/cache@v2
-        id: yarn-cache
-        with:
-          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
-          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
-          restore-keys: |
-            ${{ runner.os }}-yarn-
-
-      - name: Yarn install and check
-        run: |
-          yarn install --network-timeout 1000000
-          yarn run check
-
-      - name: Tauri build
-        uses: tauri-apps/tauri-action@v0
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
-          TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
-        with:
-          tagName: meta
-          releaseName: "Clash Verge Meta"
-          releaseBody: ""
-          releaseDraft: false
-          prerelease: true
-          args: -f default-meta
-
-      - name: Portable Bundle
-        if: matrix.os == 'windows-latest'
-        run: |
-          yarn build -f default-meta
-          yarn run portable
-        env:
-          TAG_NAME: meta
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
-          TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
-          VITE_WIN_PORTABLE: 1
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
deleted file mode 100644
index 3576f5c84137c964a07e144554f2baf1f7868016..0000000000000000000000000000000000000000
--- a/.github/workflows/test.yml
+++ /dev/null
@@ -1,76 +0,0 @@
-name: Test CI
-
-on:
-  workflow_dispatch:
-    inputs:
-      os:
-        description: "Runs on OS"
-        required: true
-        default: windows-latest
-        type: choice
-        options:
-          - windows-latest
-          - ubuntu-latest
-          - macos-latest
-          - ubuntu-18.04
-          - ubuntu-20.04
-          - ubuntu-22.04
-          - macos-10.15
-          - macos-11
-          - macos-12
-          - windows-2019
-          - windows-2022
-
-env:
-  CARGO_INCREMENTAL: 0
-  RUST_BACKTRACE: short
-
-jobs:
-  release:
-    runs-on: ${{ github.event.inputs.os }}
-    if: startsWith(github.repository, 'zzzgydi')
-    steps:
-      - name: System Version
-        run: |
-          echo ${{ github.event.inputs.os }}
-
-      - name: Checkout repository
-        uses: actions/checkout@v4
-
-      - name: install Rust stable
-        uses: dtolnay/rust-toolchain@stable
-
-      - name: Rust Cache
-        uses: Swatinem/rust-cache@v2
-        with:
-          workspaces: src-tauri
-
-      - name: Install Node
-        uses: actions/setup-node@v4
-        with:
-          node-version: "16"
-          cache: "yarn"
-
-      - name: Install Dependencies (ubuntu only)
-        if: startsWith(github.event.inputs.os, 'ubuntu-')
-        run: |
-          sudo apt-get update
-          sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
-
-      - name: Yarn install and check
-        run: |
-          yarn install --network-timeout 1000000 --frozen-lockfile
-          yarn run check
-
-      - name: Tauri build
-        uses: tauri-apps/tauri-action@v0
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
-          TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
-        with:
-          tagName: alpha
-          releaseName: "Clash Verge Alpha"
-          releaseBody: "Alpha Version (include debug)"
-          releaseDraft: false
-          includeUpdaterJson: false
diff --git a/.github/workflows/updater.yml b/.github/workflows/updater.yml
deleted file mode 100644
index 7c2107860b2c4216f826d6360319ba3c4c90b2eb..0000000000000000000000000000000000000000
--- a/.github/workflows/updater.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-name: Updater CI
-
-on: workflow_dispatch
-
-jobs:
-  release-update:
-    runs-on: ubuntu-latest
-    if: startsWith(github.repository, 'zzzgydi')
-    steps:
-      - name: Checkout repository
-        uses: actions/checkout@v4
-
-      - name: Install Node
-        uses: actions/setup-node@v4
-        with:
-          node-version: "16"
-          cache: "yarn"
-
-      - name: Yarn install
-        run: yarn install --network-timeout 1000000 --frozen-lockfile
-
-      - name: Release updater file
-        run: yarn run updater
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index c9e2fb916ed5395d3fc10ad8a7fadac8966f2451..0000000000000000000000000000000000000000
--- a/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-node_modules
-.DS_Store
-dist
-dist-ssr
-*.local
-update.json
-scripts/_env.sh
-.vscode
diff --git a/.husky/pre-commit b/.husky/pre-commit
deleted file mode 100755
index f3a67960480c76074cdbe39a79ff13b0471ce074..0000000000000000000000000000000000000000
--- a/.husky/pre-commit
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-. "$(dirname "$0")/_/husky.sh"
-
-yarn pretty-quick --staged
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index f288702d2fa16d3cdf0035b15a9fcbc552cd88e7..0000000000000000000000000000000000000000
--- a/LICENSE
+++ /dev/null
@@ -1,674 +0,0 @@
-                    GNU GENERAL PUBLIC LICENSE
-                       Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                            Preamble
-
-  The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
-  The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works.  By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.  We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors.  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
-  To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights.  Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received.  You must make sure that they, too, receive
-or can get the source code.  And you must show them these terms so they
-know their rights.
-
-  Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
-  For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software.  For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
-  Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so.  This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software.  The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable.  Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products.  If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
-  Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary.  To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                       TERMS AND CONDITIONS
-
-  0. Definitions.
-
-  "This License" refers to version 3 of the GNU General Public License.
-
-  "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
-  "The Program" refers to any copyrightable work licensed under this
-License.  Each licensee is addressed as "you".  "Licensees" and
-"recipients" may be individuals or organizations.
-
-  To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy.  The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
-  A "covered work" means either the unmodified Program or a work based
-on the Program.
-
-  To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy.  Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
-  To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies.  Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
-  An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License.  If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
-  1. Source Code.
-
-  The "source code" for a work means the preferred form of the work
-for making modifications to it.  "Object code" means any non-source
-form of a work.
-
-  A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
-  The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form.  A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
-  The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities.  However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work.  For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
-  The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
-  The Corresponding Source for a work in source code form is that
-same work.
-
-  2. Basic Permissions.
-
-  All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met.  This License explicitly affirms your unlimited
-permission to run the unmodified Program.  The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work.  This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
-  You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force.  You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright.  Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
-  Conveying under any other circumstances is permitted solely under
-the conditions stated below.  Sublicensing is not allowed; section 10
-makes it unnecessary.
-
-  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-  No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
-  When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
-  4. Conveying Verbatim Copies.
-
-  You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
-  You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
-  5. Conveying Modified Source Versions.
-
-  You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
-    a) The work must carry prominent notices stating that you modified
-    it, and giving a relevant date.
-
-    b) The work must carry prominent notices stating that it is
-    released under this License and any conditions added under section
-    7.  This requirement modifies the requirement in section 4 to
-    "keep intact all notices".
-
-    c) You must license the entire work, as a whole, under this
-    License to anyone who comes into possession of a copy.  This
-    License will therefore apply, along with any applicable section 7
-    additional terms, to the whole of the work, and all its parts,
-    regardless of how they are packaged.  This License gives no
-    permission to license the work in any other way, but it does not
-    invalidate such permission if you have separately received it.
-
-    d) If the work has interactive user interfaces, each must display
-    Appropriate Legal Notices; however, if the Program has interactive
-    interfaces that do not display Appropriate Legal Notices, your
-    work need not make them do so.
-
-  A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit.  Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
-  6. Conveying Non-Source Forms.
-
-  You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
-    a) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by the
-    Corresponding Source fixed on a durable physical medium
-    customarily used for software interchange.
-
-    b) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by a
-    written offer, valid for at least three years and valid for as
-    long as you offer spare parts or customer support for that product
-    model, to give anyone who possesses the object code either (1) a
-    copy of the Corresponding Source for all the software in the
-    product that is covered by this License, on a durable physical
-    medium customarily used for software interchange, for a price no
-    more than your reasonable cost of physically performing this
-    conveying of source, or (2) access to copy the
-    Corresponding Source from a network server at no charge.
-
-    c) Convey individual copies of the object code with a copy of the
-    written offer to provide the Corresponding Source.  This
-    alternative is allowed only occasionally and noncommercially, and
-    only if you received the object code with such an offer, in accord
-    with subsection 6b.
-
-    d) Convey the object code by offering access from a designated
-    place (gratis or for a charge), and offer equivalent access to the
-    Corresponding Source in the same way through the same place at no
-    further charge.  You need not require recipients to copy the
-    Corresponding Source along with the object code.  If the place to
-    copy the object code is a network server, the Corresponding Source
-    may be on a different server (operated by you or a third party)
-    that supports equivalent copying facilities, provided you maintain
-    clear directions next to the object code saying where to find the
-    Corresponding Source.  Regardless of what server hosts the
-    Corresponding Source, you remain obligated to ensure that it is
-    available for as long as needed to satisfy these requirements.
-
-    e) Convey the object code using peer-to-peer transmission, provided
-    you inform other peers where the object code and Corresponding
-    Source of the work are being offered to the general public at no
-    charge under subsection 6d.
-
-  A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
-  A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling.  In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage.  For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product.  A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
-  "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source.  The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
-  If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information.  But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
-  The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed.  Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
-  Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
-  7. Additional Terms.
-
-  "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law.  If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
-  When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it.  (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.)  You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
-  Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
-    a) Disclaiming warranty or limiting liability differently from the
-    terms of sections 15 and 16 of this License; or
-
-    b) Requiring preservation of specified reasonable legal notices or
-    author attributions in that material or in the Appropriate Legal
-    Notices displayed by works containing it; or
-
-    c) Prohibiting misrepresentation of the origin of that material, or
-    requiring that modified versions of such material be marked in
-    reasonable ways as different from the original version; or
-
-    d) Limiting the use for publicity purposes of names of licensors or
-    authors of the material; or
-
-    e) Declining to grant rights under trademark law for use of some
-    trade names, trademarks, or service marks; or
-
-    f) Requiring indemnification of licensors and authors of that
-    material by anyone who conveys the material (or modified versions of
-    it) with contractual assumptions of liability to the recipient, for
-    any liability that these contractual assumptions directly impose on
-    those licensors and authors.
-
-  All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10.  If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term.  If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
-  If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
-  Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
-  8. Termination.
-
-  You may not propagate or modify a covered work except as expressly
-provided under this License.  Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
-  However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
-  Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
-  Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License.  If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
-  9. Acceptance Not Required for Having Copies.
-
-  You are not required to accept this License in order to receive or
-run a copy of the Program.  Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance.  However,
-nothing other than this License grants you permission to propagate or
-modify any covered work.  These actions infringe copyright if you do
-not accept this License.  Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
-  10. Automatic Licensing of Downstream Recipients.
-
-  Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License.  You are not responsible
-for enforcing compliance by third parties with this License.
-
-  An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations.  If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
-  You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License.  For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
-  11. Patents.
-
-  A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based.  The
-work thus licensed is called the contributor's "contributor version".
-
-  A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version.  For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
-  Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
-  In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement).  To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
-  If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients.  "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
-  If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
-  A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License.  You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
-  Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
-  12. No Surrender of Others' Freedom.
-
-  If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all.  For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
-  13. Use with the GNU Affero General Public License.
-
-  Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work.  The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
-  14. Revised Versions of this License.
-
-  The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-  Each version is given a distinguishing version number.  If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation.  If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
-  If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
-  Later license versions may give you additional or different
-permissions.  However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
-  15. Disclaimer of Warranty.
-
-  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. Limitation of Liability.
-
-  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
-  17. Interpretation of Sections 15 and 16.
-
-  If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
-                     END OF TERMS AND CONDITIONS
-
-            How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
-  If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
-    <program>  Copyright (C) <year>  <name of author>
-    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
-  You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<https://www.gnu.org/licenses/>.
-
-  The GNU General Public License does not permit incorporating your program
-into proprietary programs.  If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.  But first, please read
-<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/README.md b/README.md
index d78bc471c5313e2258ef7c3bc1ad65b955aab245..4c3e5e5ef3bfb8a65c5c7508f7bd13c78b5278f3 100644
--- a/README.md
+++ b/README.md
@@ -1,158 +1 @@
-<h1 align="center">
-  <img src="./src/assets/image/logo.png" alt="Clash" width="128" />
-  <br>
-  Clash Verge
-  <br>
-</h1>
-
-<h3 align="center">
-A <a href="https://github.com/Dreamacro/clash">Clash</a> GUI based on <a href="https://github.com/tauri-apps/tauri">tauri</a>.
-</h3>
-
-## Features
-
-- Full `clash` config supported, Partial `clash premium` config supported.
-- Profiles management and enhancement (by yaml and Javascript). [Doc](https://github.com/zzzgydi/clash-verge/wiki/%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97)
-- Simple UI and supports custom theme color.
-- Built-in support [Clash.Meta](https://github.com/MetaCubeX/Clash.Meta) core.
-- System proxy setting and guard.
-
-## Promotion
-
-[狗狗加速 —— 技术流机场 Doggygo VPN](https://dg1.top)
-
-- High-performance overseas VPN, free trial, discounted packages, unlock streaming media, the world's first to support Hysteria protocol.
-- 高性能海外机场,免费试用,优惠套餐,解锁流媒体,全球首家支持 Hysteria 协议。
-- 使用 Clash Verge 专属邀请链接注册送 15 天,每天 1G 流量免费试用:https://panel.dg1.top/#/register?code=sFCDayZf
-
-<details>
-<summary>Promotion Detail</summary>
-
-- Clash Verge 专属 8 折优惠码: verge20 (仅有 500 份)
-- 优惠套餐每月仅需 15.8 元,160G 流量,年付 8 折
-- 海外团队,无跑路风险,高达 50% 返佣
-- 集群负载均衡设计,高速专线(兼容老客户端),极低延迟,无视晚高峰,4K 秒开
-- 全球首家 Hysteria 协议机场,将在今年 10 月上线更快的 `tuic` 协议(Clash Verge 客户端最佳搭配)
-- 解锁流媒体及 ChatGPT
-- 官网:https://dg1.top
-
-</details>
-
-<br />
-
-[EEVPN —— 海外运营机场 ※ 支持 ChatGPT](https://www.eejsq.net/#/register?code=yRr6qBO3)
-
-- 年付低至 9.99 元,价格低,速度不减
-
-<details>
-<summary>Promotion Detail</summary>
-
-- 中国大陆 BGP 网络接入
-- IEPL 专线网络
-- 最高 2500Mbps 速率可用
-- 不限制在线客户端
-- 解锁流媒体及 ChatGPT
-- 海外运营 数据安全
-
-</details>
-
-## Install
-
-Download from [release](https://github.com/zzzgydi/clash-verge/releases). Supports Windows x64, Linux x86_64 and macOS 11+
-
-- [Windows x64](https://github.com/zzzgydi/clash-verge/releases/download/v1.3.8/Clash.Verge_1.3.8_x64_en-US.msi)
-- [macOS intel](https://github.com/zzzgydi/clash-verge/releases/download/v1.3.8/Clash.Verge_1.3.8_x64.dmg)
-- [macOS arm](https://github.com/zzzgydi/clash-verge/releases/download/v1.3.8/Clash.Verge_1.3.8_aarch64.dmg)
-- [Linux AppImage](https://github.com/zzzgydi/clash-verge/releases/download/v1.3.8/clash-verge_1.3.8_amd64.AppImage)
-- [Linux deb](https://github.com/zzzgydi/clash-verge/releases/download/v1.3.8/clash-verge_1.3.8_amd64.deb)
-- [Fedora Linux](https://github.com/zzzgydi/clash-verge/issues/352)
-
-Or you can build it yourself. Supports Windows, Linux and macOS 10.15+
-
-Notes: If you could not start the app on Windows, please check that you have [Webview2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section) installed.
-
-### FAQ
-
-#### 1. **macOS** "Clash Verge" is damaged and can't be opened
-
-open the terminal and run `sudo xattr -r -d com.apple.quarantine /Applications/Clash\ Verge.app`
-
-## Development
-
-You should install Rust and Nodejs, see [here](https://tauri.app/v1/guides/getting-started/prerequisites) for more details. Then install Nodejs packages.
-
-```shell
-yarn install
-```
-
-Then download the clash binary... Or you can download it from [clash premium release](https://github.com/Dreamacro/clash/releases/tag/premium) and rename it according to [tauri config](https://tauri.studio/docs/api/config/#tauri.bundle.externalBin).
-
-```shell
-# force update to latest version
-# yarn run check --force
-
-yarn run check
-```
-
-Then run
-
-```shell
-yarn dev
-
-# run it in another way if app instance exists
-yarn dev:diff
-```
-
-Or you can build it
-
-```shell
-yarn build
-```
-
-## Todos
-
-> This keng is a little big...
-
-## Screenshots
-
-<div align="center">
-  <img src="./docs/demo1.png" alt="demo1" width="32%" />
-  <img src="./docs/demo2.png" alt="demo2" width="32%" />
-  <img src="./docs/demo3.png" alt="demo3" width="32%" />
-  <img src="./docs/demo4.png" alt="demo4" width="32%" />
-  <img src="./docs/demo5.png" alt="demo5" width="32%" />
-  <img src="./docs/demo6.png" alt="demo6" width="32%" />
-</div>
-
-### Custom Theme
-
-<div align="center">
-  <img src="./docs/color1.png" alt="demo1" width="16%" />
-  <img src="./docs/color2.png" alt="demo2" width="16%" />
-  <img src="./docs/color3.png" alt="demo3" width="16%" />
-  <img src="./docs/color4.png" alt="demo4" width="16%" />
-  <img src="./docs/color5.png" alt="demo5" width="16%" />
-  <img src="./docs/color6.png" alt="demo6" width="16%" />
-</div>
-
-## Disclaimer
-
-This is a learning project for Rust practice.
-
-## Contributions
-
-Issue and PR welcome!
-
-## Acknowledgement
-
-Clash Verge was based on or inspired by these projects and so on:
-
-- [tauri-apps/tauri](https://github.com/tauri-apps/tauri): Build smaller, faster, and more secure desktop applications with a web frontend.
-- [Dreamacro/clash](https://github.com/Dreamacro/clash): A rule-based tunnel in Go.
-- [MetaCubeX/Clash.Meta](https://github.com/MetaCubeX/Clash.Meta): A rule-based tunnel in Go.
-- [Fndroid/clash_for_windows_pkg](https://github.com/Fndroid/clash_for_windows_pkg): A Windows/macOS GUI based on Clash.
-- [vitejs/vite](https://github.com/vitejs/vite): Next generation frontend tooling. It's fast!
-
-## License
-
-GPL-3.0 License. See [License here](./LICENSE) for details.
+Removed
diff --git a/UPDATELOG.md b/UPDATELOG.md
deleted file mode 100644
index a08a86e2547c5f0f889c9c584ce699aa2096798f..0000000000000000000000000000000000000000
--- a/UPDATELOG.md
+++ /dev/null
@@ -1,472 +0,0 @@
-## v1.3.8
-
-### Features
-
-- update clash meta core
-- add default valid keys
-- adjust the delay display interval and color
-
-### Bug Fixes
-
-- fix connections page undefined exception
-
----
-
-## v1.3.7
-
-### Features
-
-- update clash and clash meta core
-- profiles page add paste button
-- subscriptions url textfield use multi lines
-- set min window size
-- add check for updates buttons
-- add open dashboard to the hotkey list
-
-### Bug Fixes
-
-- fix profiles page undefined exception
-
----
-
-## v1.3.6
-
-### Features
-
-- add russian translation
-- support to show connection detail
-- support clash meta memory usage display
-- support proxy provider update ui
-- update geo data file from meta repo
-- adjust setting page
-
-### Bug Fixes
-
-- center the window when it is out of screen
-- use `sudo` when `pkexec` not found (Linux)
-- reconnect websocket when window focus
-
-### Notes
-
-- The current version of the Linux installation package is built by Ubuntu 20.04 (Github Action).
-
----
-
-## v1.3.5
-
-### Features
-
-- update clash core
-
-### Bug Fixes
-
-- fix blurry system tray icon (Windows)
-- fix v1.3.4 wintun.dll not found (Windows)
-- fix v1.3.4 clash core not found (macOS, Linux)
-
----
-
-## v1.3.4
-
-### Features
-
-- update clash and clash meta core
-- optimize traffic graph high CPU usage when window hidden
-- use polkit to elevate permission (Linux)
-- support app log level setting
-- support copy environment variable
-- overwrite resource file according to file modified
-- save window size and position
-
-### Bug Fixes
-
-- remove fallback group select status
-- enable context menu on editable element (Windows)
-
----
-
-## v1.3.3
-
-### Features
-
-- update clash and clash meta core
-- show tray icon variants in different system proxy status (Windows)
-- close all connections when mode changed
-
-### Bug Fixes
-
-- encode controller secret into uri
-- error boundary for each page
-
----
-
-## v1.3.2
-
-### Features
-
-- update clash and clash meta core
-
-### Bug Fixes
-
-- fix import url issue
-- fix profile undefined issue
-
----
-
-## v1.3.1
-
-### Features
-
-- update clash and clash meta core
-
-### Bug Fixes
-
-- fix open url issue
-- fix appimage path panic
-- fix grant root permission in macOS
-- fix linux system proxy default bypass
-
----
-
-## v1.3.0
-
-### Features
-
-- update clash and clash meta
-- support opening dir on tray
-- support updating all profiles with one click
-- support granting root permission to clash core(Linux, macOS)
-- support enable/disable clash fields filter, feel free to experience the latest features of Clash Meta
-
-### Bug Fixes
-
-- deb add openssl depend(Linux)
-- fix the AppImage auto launch path(Linux)
-- fix get the default network service(macOS)
-- remove the esc key listener in macOS, cmd+w instead(macOS)
-- fix infinite retry when websocket error
-
----
-
-## v1.2.3
-
-### Features
-
-- update clash
-- adjust macOS window style
-- profile supports UTF8 with BOM
-
-### Bug Fixes
-
-- fix selected proxy
-- fix error log
-
----
-
-## v1.2.2
-
-### Features
-
-- update clash meta
-- recover clash core after panic
-- use system window decorations(Linux)
-
-### Bug Fixes
-
-- flush system proxy settings(Windows)
-- fix parse log panic
-- fix ui bug
-
----
-
-## v1.2.1
-
-### Features
-
-- update clash version
-- proxy groups support multi columns
-- optimize ui
-
-### Bug Fixes
-
-- fix ui websocket connection
-- adjust delay check concurrency
-- avoid setting login item repeatedly(macOS)
-
----
-
-## v1.2.0
-
-### Features
-
-- update clash meta version
-- support to change external-controller
-- support to change default latency test URL
-- close all connections when proxy changed or profile changed
-- check the config by using the core
-- increase the robustness of the program
-- optimize windows service mode (need to reinstall)
-- optimize ui
-
-### Bug Fixes
-
-- invalid hotkey cause panic
-- invalid theme setting cause panic
-- fix some other glitches
-
----
-
-## v1.1.2
-
-### Features
-
-- the system tray follows i18n
-- change the proxy group ui of global mode
-- support to update profile with the system proxy/clash proxy
-- check the remote profile more strictly
-
-### Bug Fixes
-
-- use app version as default user agent
-- the clash not exit in service mode
-- reset the system proxy when quit the app
-- fix some other glitches
-
----
-
-## v1.1.1
-
-### Features
-
-- optimize clash config feedback
-- hide macOS dock icon
-- use clash meta compatible version (Linux)
-
-### Bug Fixes
-
-- fix some other glitches
-
----
-
-## v1.1.0
-
-### Features
-
-- add rule page
-- supports proxy providers delay check
-- add proxy delay check loading status
-- supports hotkey/shortcut management
-- supports displaying connections data in table layout(refer to yacd)
-
-### Bug Fixes
-
-- supports yaml merge key in clash config
-- detect the network interface and set the system proxy(macOS)
-- fix some other glitches
-
----
-
-## v1.0.6
-
-### Features
-
-- update clash and clash.meta
-
-### Bug Fixes
-
-- only script profile display console
-- automatic configuration update on demand at launch
-
----
-
-## v1.0.5
-
-### Features
-
-- reimplement profile enhanced mode with quick-js
-- optimize the runtime config generation process
-- support web ui management
-- support clash field management
-- support viewing the runtime config
-- adjust some pages style
-
-### Bug Fixes
-
-- fix silent start
-- fix incorrectly reset system proxy on exit
-
----
-
-## v1.0.4
-
-### Features
-
-- update clash core and clash meta version
-- support switch clash mode on system tray
-- theme mode support follows system
-
-### Bug Fixes
-
-- config load error on first use
-
----
-
-## v1.0.3
-
-### Features
-
-- save some states such as URL test, filter, etc
-- update clash core and clash-meta core
-- new icon for macOS
-
----
-
-## v1.0.2
-
-### Features
-
-- supports for switching clash core
-- supports release UI processes
-- supports script mode setting
-
-### Bug Fixes
-
-- fix service mode bug (Windows)
-
----
-
-## v1.0.1
-
-### Features
-
-- adjust default theme settings
-- reduce gpu usage of traffic graph when hidden
-- supports more remote profile response header setting
-- check remote profile data format when imported
-
-### Bug Fixes
-
-- service mode install and start issue (Windows)
-- fix launch panic (Some Windows)
-
----
-
-## v1.0.0
-
-### Features
-
-- update clash core
-- optimize traffic graph animation
-- supports interval update profiles
-- supports service mode (Windows)
-
-### Bug Fixes
-
-- reset system proxy when exit from dock (macOS)
-- adjust clash dns config process strategy
-
----
-
-## v0.0.29
-
-### Features
-
-- sort proxy node
-- custom proxy test url
-- logs page filter
-- connections page filter
-- default user agent for subscription
-- system tray add tun mode toggle
-- enable to change the config dir (Windows only)
-
----
-
-## v0.0.28
-
-### Features
-
-- enable to use clash config fields (UI)
-
-### Bug Fixes
-
-- remove the character
-- fix some icon color
-
----
-
-## v0.0.27
-
-### Features
-
-- supports custom theme color
-- tun mode setting control the final config
-
-### Bug Fixes
-
-- fix transition flickers (macOS)
-- reduce proxy page render
-
----
-
-## v0.0.26
-
-### Features
-
-- silent start
-- profile editor
-- profile enhance mode supports more fields
-- optimize profile enhance mode strategy
-
-### Bug Fixes
-
-- fix csp restriction on macOS
-- window controllers on Linux
-
----
-
-## v0.0.25
-
-### Features
-
-- update clash core version
-
-### Bug Fixes
-
-- app updater error
-- display window controllers on Linux
-
-### Notes
-
-If you can't update the app properly, please consider downloading the latest version from github release.
-
----
-
-## v0.0.24
-
-### Features
-
-- Connections page
-- add wintun.dll (Windows)
-- supports create local profile with selected file (Windows)
-- system tray enable set system proxy
-
-### Bug Fixes
-
-- open dir error
-- auto launch path (Windows)
-- fix some clash config error
-- reduce the impact of the enhanced mode
-
----
-
-## v0.0.23
-
-### Features
-
-- i18n supports
-- Remote profile User Agent supports
-
-### Bug Fixes
-
-- clash config file case ignore
-- clash `external-controller` only port
diff --git a/docs/color1.png b/docs/color1.png
deleted file mode 100644
index 9c24fb8d89517ed522b384b0eb0497a680ab960e..0000000000000000000000000000000000000000
Binary files a/docs/color1.png and /dev/null differ
diff --git a/docs/color2.png b/docs/color2.png
deleted file mode 100644
index 8d6d935dac15ea4d8bacf7e9ade6d09ac7247511..0000000000000000000000000000000000000000
Binary files a/docs/color2.png and /dev/null differ
diff --git a/docs/color3.png b/docs/color3.png
deleted file mode 100644
index 247b84104f802b9f9242fca244515606a0c1ab2f..0000000000000000000000000000000000000000
Binary files a/docs/color3.png and /dev/null differ
diff --git a/docs/color4.png b/docs/color4.png
deleted file mode 100644
index 3ecb7506fededc06ce38c09b4dedbe3227a3a513..0000000000000000000000000000000000000000
Binary files a/docs/color4.png and /dev/null differ
diff --git a/docs/color5.png b/docs/color5.png
deleted file mode 100644
index 65e916a04d0fbe6a4292b9f2bc29cbe0b245d591..0000000000000000000000000000000000000000
Binary files a/docs/color5.png and /dev/null differ
diff --git a/docs/color6.png b/docs/color6.png
deleted file mode 100644
index 5067320993579242b61fa4fe3bb774fa8685acb2..0000000000000000000000000000000000000000
Binary files a/docs/color6.png and /dev/null differ
diff --git a/docs/demo1.png b/docs/demo1.png
deleted file mode 100644
index b18450f0a136b2342976907e9c0d0e331ba759c0..0000000000000000000000000000000000000000
Binary files a/docs/demo1.png and /dev/null differ
diff --git a/docs/demo2.png b/docs/demo2.png
deleted file mode 100644
index a2919b6dcd357a3f83e0276c8642de1a73f8f4e1..0000000000000000000000000000000000000000
Binary files a/docs/demo2.png and /dev/null differ
diff --git a/docs/demo3.png b/docs/demo3.png
deleted file mode 100644
index 55267b5f7472bc286880ebf7a4c5fa38b1c9029a..0000000000000000000000000000000000000000
Binary files a/docs/demo3.png and /dev/null differ
diff --git a/docs/demo4.png b/docs/demo4.png
deleted file mode 100644
index ef9b90a6bd4e9d3cf73d9db0986e64110c58c558..0000000000000000000000000000000000000000
Binary files a/docs/demo4.png and /dev/null differ
diff --git a/docs/demo5.png b/docs/demo5.png
deleted file mode 100644
index a7eac5437c3cae2a00bf3eed362ac3c012eb5b93..0000000000000000000000000000000000000000
Binary files a/docs/demo5.png and /dev/null differ
diff --git a/docs/demo6.png b/docs/demo6.png
deleted file mode 100644
index fe53e2b04e891bc3c46bbb1592a6b003cdc7aeb7..0000000000000000000000000000000000000000
Binary files a/docs/demo6.png and /dev/null differ
diff --git a/package.json b/package.json
deleted file mode 100644
index 8249427ebdaf4e3736f5b128e747326382fa44b6..0000000000000000000000000000000000000000
--- a/package.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
-  "name": "clash-verge",
-  "version": "1.3.8",
-  "license": "GPL-3.0",
-  "scripts": {
-    "dev": "tauri dev",
-    "dev:diff": "tauri dev -f verge-dev",
-    "build": "tauri build",
-    "tauri": "tauri",
-    "web:dev": "vite",
-    "web:build": "tsc && vite build",
-    "web:serve": "vite preview",
-    "aarch": "node scripts/aarch.mjs",
-    "check": "node scripts/check.mjs",
-    "updater": "node scripts/updater.mjs",
-    "publish": "node scripts/publish.mjs",
-    "portable": "node scripts/portable.mjs",
-    "prepare": "husky install"
-  },
-  "dependencies": {
-    "@emotion/react": "^11.10.5",
-    "@emotion/styled": "^11.10.5",
-    "@juggle/resize-observer": "^3.4.0",
-    "@mui/icons-material": "^5.10.9",
-    "@mui/material": "^5.10.13",
-    "@mui/x-data-grid": "^5.17.11",
-    "@tauri-apps/api": "^1.3.0",
-    "ahooks": "^3.7.2",
-    "axios": "^1.1.3",
-    "dayjs": "1.11.5",
-    "i18next": "^22.0.4",
-    "lodash-es": "^4.17.21",
-    "monaco-editor": "^0.34.1",
-    "react": "^18.2.0",
-    "react-dom": "^18.2.0",
-    "react-error-boundary": "^3.1.4",
-    "react-hook-form": "^7.39.5",
-    "react-i18next": "^12.0.0",
-    "react-router-dom": "^6.4.3",
-    "react-virtuoso": "^3.1.3",
-    "recoil": "^0.7.6",
-    "snarkdown": "^2.0.0",
-    "swr": "^1.3.0"
-  },
-  "devDependencies": {
-    "@actions/github": "^5.0.3",
-    "@tauri-apps/cli": "^1.3.1",
-    "@types/fs-extra": "^9.0.13",
-    "@types/js-cookie": "^3.0.2",
-    "@types/lodash": "^4.14.180",
-    "@types/lodash-es": "^4.17.7",
-    "@types/react-dom": "^18.0.11",
-    "@vitejs/plugin-react": "^2.0.1",
-    "adm-zip": "^0.5.9",
-    "cross-env": "^7.0.3",
-    "fs-extra": "^10.0.0",
-    "https-proxy-agent": "^5.0.1",
-    "husky": "^7.0.0",
-    "node-fetch": "^3.2.6",
-    "prettier": "^2.7.1",
-    "pretty-quick": "^3.1.3",
-    "sass": "^1.54.0",
-    "typescript": "^4.7.4",
-    "vite": "^3.2.5",
-    "vite-plugin-monaco-editor": "^1.1.0",
-    "vite-plugin-svgr": "^2.2.1"
-  },
-  "prettier": {
-    "tabWidth": 2,
-    "semi": true,
-    "singleQuote": false,
-    "endOfLine": "lf"
-  }
-}
diff --git a/scripts/aarch.mjs b/scripts/aarch.mjs
deleted file mode 100644
index 989e77463a1610f4c5de13d087399ccd2be48025..0000000000000000000000000000000000000000
--- a/scripts/aarch.mjs
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * Build and upload assets
- * for macOS(aarch)
- */
-import fs from "fs-extra";
-import path from "path";
-import { exit } from "process";
-import { execSync } from "child_process";
-import { createRequire } from "module";
-import { getOctokit, context } from "@actions/github";
-
-// to `meta` tag
-const META = process.argv.includes("--meta");
-// to `alpha` tag
-const ALPHA = process.argv.includes("--alpha");
-
-const require = createRequire(import.meta.url);
-
-async function resolve() {
-  if (!process.env.GITHUB_TOKEN) {
-    throw new Error("GITHUB_TOKEN is required");
-  }
-  if (!process.env.GITHUB_REPOSITORY) {
-    throw new Error("GITHUB_REPOSITORY is required");
-  }
-  if (!process.env.TAURI_PRIVATE_KEY) {
-    throw new Error("TAURI_PRIVATE_KEY is required");
-  }
-  if (!process.env.TAURI_KEY_PASSWORD) {
-    throw new Error("TAURI_KEY_PASSWORD is required");
-  }
-
-  const { version } = require("../package.json");
-
-  const tag = META ? "meta" : ALPHA ? "alpha" : `v${version}`;
-  const buildCmd = META ? `yarn build -f default-meta` : `yarn build`;
-
-  console.log(`[INFO]: Upload to tag "${tag}"`);
-  console.log(`[INFO]: Building app. "${buildCmd}"`);
-
-  execSync(buildCmd);
-
-  const cwd = process.cwd();
-  const bundlePath = path.join(cwd, "src-tauri/target/release/bundle");
-  const join = (p) => path.join(bundlePath, p);
-
-  const appPathList = [
-    join("macos/Clash Verge.aarch64.app.tar.gz"),
-    join("macos/Clash Verge.aarch64.app.tar.gz.sig"),
-  ];
-
-  for (const appPath of appPathList) {
-    if (fs.pathExistsSync(appPath)) {
-      fs.removeSync(appPath);
-    }
-  }
-
-  fs.copyFileSync(join("macos/Clash Verge.app.tar.gz"), appPathList[0]);
-  fs.copyFileSync(join("macos/Clash Verge.app.tar.gz.sig"), appPathList[1]);
-
-  const options = { owner: context.repo.owner, repo: context.repo.repo };
-  const github = getOctokit(process.env.GITHUB_TOKEN);
-
-  const { data: release } = await github.rest.repos.getReleaseByTag({
-    ...options,
-    tag,
-  });
-
-  if (!release.id) throw new Error("failed to find the release");
-
-  await uploadAssets(release.id, [
-    join(`dmg/Clash Verge_${version}_aarch64.dmg`),
-    ...appPathList,
-  ]);
-}
-
-// From tauri-apps/tauri-action
-// https://github.com/tauri-apps/tauri-action/blob/dev/packages/action/src/upload-release-assets.ts
-async function uploadAssets(releaseId, assets) {
-  const github = getOctokit(process.env.GITHUB_TOKEN);
-
-  // Determine content-length for header to upload asset
-  const contentLength = (filePath) => fs.statSync(filePath).size;
-
-  for (const assetPath of assets) {
-    const headers = {
-      "content-type": "application/zip",
-      "content-length": contentLength(assetPath),
-    };
-
-    const ext = path.extname(assetPath);
-    const filename = path.basename(assetPath).replace(ext, "");
-    const assetName = path.dirname(assetPath).includes(`target${path.sep}debug`)
-      ? `${filename}-debug${ext}`
-      : `${filename}${ext}`;
-
-    console.log(`[INFO]: Uploading ${assetName}...`);
-
-    try {
-      await github.rest.repos.uploadReleaseAsset({
-        headers,
-        name: assetName,
-        data: fs.readFileSync(assetPath),
-        owner: context.repo.owner,
-        repo: context.repo.repo,
-        release_id: releaseId,
-      });
-    } catch (error) {
-      console.log(error.message);
-    }
-  }
-}
-
-if (process.platform === "darwin" && process.arch === "arm64") {
-  resolve();
-} else {
-  console.error("invalid");
-  exit(1);
-}
diff --git a/scripts/check.mjs b/scripts/check.mjs
deleted file mode 100644
index 5b7aceb9af0d3045fa849f5de5f06af2a465e656..0000000000000000000000000000000000000000
--- a/scripts/check.mjs
+++ /dev/null
@@ -1,332 +0,0 @@
-import fs from "fs-extra";
-import zlib from "zlib";
-import path from "path";
-import AdmZip from "adm-zip";
-import fetch from "node-fetch";
-import proxyAgent from "https-proxy-agent";
-import { execSync } from "child_process";
-
-const cwd = process.cwd();
-const TEMP_DIR = path.join(cwd, "node_modules/.verge");
-const FORCE = process.argv.includes("--force");
-
-const SIDECAR_HOST = execSync("rustc -vV")
-  .toString()
-  .match(/(?<=host: ).+(?=\s*)/g)[0];
-
-/* ======= clash ======= */
-const CLASH_STORAGE_PREFIX = "https://release.dreamacro.workers.dev/";
-const CLASH_URL_PREFIX =
-  "https://github.com/Dreamacro/clash/releases/download/premium/";
-const CLASH_LATEST_DATE = "2023.08.17";
-
-const CLASH_MAP = {
-  "win32-x64": "clash-windows-amd64",
-  "darwin-x64": "clash-darwin-amd64",
-  "darwin-arm64": "clash-darwin-arm64",
-  "linux-x64": "clash-linux-amd64",
-  "linux-arm64": "clash-linux-arm64",
-};
-
-/* ======= clash meta ======= */
-const META_URL_PREFIX = `https://github.com/MetaCubeX/Clash.Meta/releases/download/`;
-const META_VERSION = "v1.16.0";
-
-const META_MAP = {
-  "win32-x64": "clash.meta-windows-amd64-compatible",
-  "darwin-x64": "clash.meta-darwin-amd64",
-  "darwin-arm64": "clash.meta-darwin-arm64",
-  "linux-x64": "clash.meta-linux-amd64-compatible",
-  "linux-arm64": "clash.meta-linux-arm64",
-};
-
-/**
- * check available
- */
-
-const { platform, arch } = process;
-if (!CLASH_MAP[`${platform}-${arch}`]) {
-  throw new Error(`clash unsupported platform "${platform}-${arch}"`);
-}
-if (!META_MAP[`${platform}-${arch}`]) {
-  throw new Error(`clash meta unsupported platform "${platform}-${arch}"`);
-}
-
-function clash() {
-  const name = CLASH_MAP[`${platform}-${arch}`];
-
-  const isWin = platform === "win32";
-  const urlExt = isWin ? "zip" : "gz";
-  const downloadURL = `${CLASH_URL_PREFIX}${name}-${CLASH_LATEST_DATE}.${urlExt}`;
-  const exeFile = `${name}${isWin ? ".exe" : ""}`;
-  const zipFile = `${name}.${urlExt}`;
-
-  return {
-    name: "clash",
-    targetFile: `clash-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
-    exeFile,
-    zipFile,
-    downloadURL,
-  };
-}
-
-function clashS3() {
-  const name = CLASH_MAP[`${platform}-${arch}`];
-
-  const isWin = platform === "win32";
-  const urlExt = isWin ? "zip" : "gz";
-  const downloadURL = `${CLASH_STORAGE_PREFIX}${CLASH_LATEST_DATE}/${name}-${CLASH_LATEST_DATE}.${urlExt}`;
-  const exeFile = `${name}${isWin ? ".exe" : ""}`;
-  const zipFile = `${name}.${urlExt}`;
-
-  return {
-    name: "clash",
-    targetFile: `clash-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
-    exeFile,
-    zipFile,
-    downloadURL,
-  };
-}
-
-function clashMeta() {
-  const name = META_MAP[`${platform}-${arch}`];
-  const isWin = platform === "win32";
-  const urlExt = isWin ? "zip" : "gz";
-  const downloadURL = `${META_URL_PREFIX}${META_VERSION}/${name}-${META_VERSION}.${urlExt}`;
-  const exeFile = `${name}${isWin ? ".exe" : ""}`;
-  const zipFile = `${name}-${META_VERSION}.${urlExt}`;
-
-  return {
-    name: "clash-meta",
-    targetFile: `clash-meta-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
-    exeFile,
-    zipFile,
-    downloadURL,
-  };
-}
-
-/**
- * download sidecar and rename
- */
-async function resolveSidecar(binInfo) {
-  const { name, targetFile, zipFile, exeFile, downloadURL } = binInfo;
-
-  const sidecarDir = path.join(cwd, "src-tauri", "sidecar");
-  const sidecarPath = path.join(sidecarDir, targetFile);
-
-  await fs.mkdirp(sidecarDir);
-  if (!FORCE && (await fs.pathExists(sidecarPath))) return;
-
-  const tempDir = path.join(TEMP_DIR, name);
-  const tempZip = path.join(tempDir, zipFile);
-  const tempExe = path.join(tempDir, exeFile);
-
-  await fs.mkdirp(tempDir);
-  try {
-    if (!(await fs.pathExists(tempZip))) {
-      await downloadFile(downloadURL, tempZip);
-    }
-
-    if (zipFile.endsWith(".zip")) {
-      const zip = new AdmZip(tempZip);
-      zip.getEntries().forEach((entry) => {
-        console.log(`[DEBUG]: "${name}" entry name`, entry.entryName);
-      });
-      zip.extractAllTo(tempDir, true);
-      await fs.rename(tempExe, sidecarPath);
-      console.log(`[INFO]: "${name}" unzip finished`);
-    } else {
-      // gz
-      const readStream = fs.createReadStream(tempZip);
-      const writeStream = fs.createWriteStream(sidecarPath);
-      await new Promise((resolve, reject) => {
-        const onError = (error) => {
-          console.error(`[ERROR]: "${name}" gz failed:`, error.message);
-          reject(error);
-        };
-        readStream
-          .pipe(zlib.createGunzip().on("error", onError))
-          .pipe(writeStream)
-          .on("finish", () => {
-            console.log(`[INFO]: "${name}" gunzip finished`);
-            execSync(`chmod 755 ${sidecarPath}`);
-            console.log(`[INFO]: "${name}" chmod binary finished`);
-            resolve();
-          })
-          .on("error", onError);
-      });
-    }
-  } catch (err) {
-    // 需要删除文件
-    await fs.remove(sidecarPath);
-    throw err;
-  } finally {
-    // delete temp dir
-    await fs.remove(tempDir);
-  }
-}
-
-/**
- * prepare clash core
- * if the core version is not updated in time, use S3 storage as a backup.
- */
-async function resolveClash() {
-  try {
-    return await resolveSidecar(clash());
-  } catch {
-    console.log(`[WARN]: clash core needs to be updated`);
-    return await resolveSidecar(clashS3());
-  }
-}
-
-/**
- * only Windows
- * get the wintun.dll (not required)
- */
-async function resolveWintun() {
-  const { platform } = process;
-
-  if (platform !== "win32") return;
-
-  const url = "https://www.wintun.net/builds/wintun-0.14.1.zip";
-
-  const tempDir = path.join(TEMP_DIR, "wintun");
-  const tempZip = path.join(tempDir, "wintun.zip");
-
-  const wintunPath = path.join(tempDir, "wintun/bin/amd64/wintun.dll");
-  const targetPath = path.join(cwd, "src-tauri/resources", "wintun.dll");
-
-  if (!FORCE && (await fs.pathExists(targetPath))) return;
-
-  await fs.mkdirp(tempDir);
-
-  if (!(await fs.pathExists(tempZip))) {
-    await downloadFile(url, tempZip);
-  }
-
-  // unzip
-  const zip = new AdmZip(tempZip);
-  zip.extractAllTo(tempDir, true);
-
-  if (!(await fs.pathExists(wintunPath))) {
-    throw new Error(`path not found "${wintunPath}"`);
-  }
-
-  await fs.rename(wintunPath, targetPath);
-  await fs.remove(tempDir);
-
-  console.log(`[INFO]: resolve wintun.dll finished`);
-}
-
-/**
- * download the file to the resources dir
- */
-async function resolveResource(binInfo) {
-  const { file, downloadURL } = binInfo;
-
-  const resDir = path.join(cwd, "src-tauri/resources");
-  const targetPath = path.join(resDir, file);
-
-  if (!FORCE && (await fs.pathExists(targetPath))) return;
-
-  await fs.mkdirp(resDir);
-  await downloadFile(downloadURL, targetPath);
-
-  console.log(`[INFO]: ${file} finished`);
-}
-
-/**
- * download file and save to `path`
- */
-async function downloadFile(url, path) {
-  const options = {};
-
-  const httpProxy =
-    process.env.HTTP_PROXY ||
-    process.env.http_proxy ||
-    process.env.HTTPS_PROXY ||
-    process.env.https_proxy;
-
-  if (httpProxy) {
-    options.agent = proxyAgent(httpProxy);
-  }
-
-  const response = await fetch(url, {
-    ...options,
-    method: "GET",
-    headers: { "Content-Type": "application/octet-stream" },
-  });
-  const buffer = await response.arrayBuffer();
-  await fs.writeFile(path, new Uint8Array(buffer));
-
-  console.log(`[INFO]: download finished "${url}"`);
-}
-
-/**
- * main
- */
-const SERVICE_URL =
-  "https://github.com/zzzgydi/clash-verge-service/releases/download/latest";
-
-const resolveService = () =>
-  resolveResource({
-    file: "clash-verge-service.exe",
-    downloadURL: `${SERVICE_URL}/clash-verge-service.exe`,
-  });
-const resolveInstall = () =>
-  resolveResource({
-    file: "install-service.exe",
-    downloadURL: `${SERVICE_URL}/install-service.exe`,
-  });
-const resolveUninstall = () =>
-  resolveResource({
-    file: "uninstall-service.exe",
-    downloadURL: `${SERVICE_URL}/uninstall-service.exe`,
-  });
-const resolveMmdb = () =>
-  resolveResource({
-    file: "Country.mmdb",
-    downloadURL: `https://github.com/Dreamacro/maxmind-geoip/releases/download/20230812/Country.mmdb`,
-  });
-const resolveGeosite = () =>
-  resolveResource({
-    file: "geosite.dat",
-    downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat`,
-  });
-const resolveGeoIP = () =>
-  resolveResource({
-    file: "geoip.dat",
-    downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat`,
-  });
-
-const tasks = [
-  { name: "clash", func: resolveClash, retry: 5 },
-  { name: "clash-meta", func: () => resolveSidecar(clashMeta()), retry: 5 },
-  { name: "wintun", func: resolveWintun, retry: 5, winOnly: true },
-  { name: "service", func: resolveService, retry: 5, winOnly: true },
-  { name: "install", func: resolveInstall, retry: 5, winOnly: true },
-  { name: "uninstall", func: resolveUninstall, retry: 5, winOnly: true },
-  { name: "mmdb", func: resolveMmdb, retry: 5 },
-  { name: "geosite", func: resolveGeosite, retry: 5 },
-  { name: "geoip", func: resolveGeoIP, retry: 5 },
-];
-
-async function runTask() {
-  const task = tasks.shift();
-  if (!task) return;
-  if (task.winOnly && process.platform !== "win32") return runTask();
-
-  for (let i = 0; i < task.retry; i++) {
-    try {
-      await task.func();
-      break;
-    } catch (err) {
-      console.error(`[ERROR]: task::${task.name} try ${i} ==`, err.message);
-      if (i === task.retry - 1) throw err;
-    }
-  }
-  return runTask();
-}
-
-runTask();
-runTask();
diff --git a/scripts/portable.mjs b/scripts/portable.mjs
deleted file mode 100644
index b523a50dc445d5caeb657807cca4deae93b9357e..0000000000000000000000000000000000000000
--- a/scripts/portable.mjs
+++ /dev/null
@@ -1,59 +0,0 @@
-import fs from "fs-extra";
-import path from "path";
-import AdmZip from "adm-zip";
-import { createRequire } from "module";
-import { getOctokit, context } from "@actions/github";
-
-/// Script for ci
-/// 打包绿色版/便携版 (only Windows)
-async function resolvePortable() {
-  if (process.platform !== "win32") return;
-
-  const releaseDir = "./src-tauri/target/release";
-
-  if (!(await fs.pathExists(releaseDir))) {
-    throw new Error("could not found the release dir");
-  }
-
-  const zip = new AdmZip();
-
-  zip.addLocalFile(path.join(releaseDir, "Clash Verge.exe"));
-  zip.addLocalFile(path.join(releaseDir, "clash.exe"));
-  zip.addLocalFile(path.join(releaseDir, "clash-meta.exe"));
-  zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
-
-  const require = createRequire(import.meta.url);
-  const packageJson = require("../package.json");
-  const { version } = packageJson;
-
-  const zipFile = `Clash.Verge_${version}_x64_portable.zip`;
-  zip.writeZip(zipFile);
-
-  console.log("[INFO]: create portable zip successfully");
-
-  // push release assets
-  if (process.env.GITHUB_TOKEN === undefined) {
-    throw new Error("GITHUB_TOKEN is required");
-  }
-
-  const options = { owner: context.repo.owner, repo: context.repo.repo };
-  const github = getOctokit(process.env.GITHUB_TOKEN);
-
-  console.log("[INFO]: upload to ", process.env.TAG_NAME || `v${version}`);
-
-  const { data: release } = await github.rest.repos.getReleaseByTag({
-    ...options,
-    tag: process.env.TAG_NAME || `v${version}`,
-  });
-
-  console.log(release.name);
-
-  await github.rest.repos.uploadReleaseAsset({
-    ...options,
-    release_id: release.id,
-    name: zipFile,
-    data: zip.toBuffer(),
-  });
-}
-
-resolvePortable().catch(console.error);
diff --git a/scripts/publish.mjs b/scripts/publish.mjs
deleted file mode 100644
index 523ad18c3e25454919bc0e9987c40a1e59842fda..0000000000000000000000000000000000000000
--- a/scripts/publish.mjs
+++ /dev/null
@@ -1,53 +0,0 @@
-import fs from "fs-extra";
-import { createRequire } from "module";
-import { execSync } from "child_process";
-import { resolveUpdateLog } from "./updatelog.mjs";
-
-const require = createRequire(import.meta.url);
-
-// publish
-async function resolvePublish() {
-  const flag = process.argv[2] ?? "patch";
-  const packageJson = require("../package.json");
-  const tauriJson = require("../src-tauri/tauri.conf.json");
-
-  let [a, b, c] = packageJson.version.split(".").map(Number);
-
-  if (flag === "major") {
-    a += 1;
-    b = 0;
-    c = 0;
-  } else if (flag === "minor") {
-    b += 1;
-    c = 0;
-  } else if (flag === "patch") {
-    c += 1;
-  } else throw new Error(`invalid flag "${flag}"`);
-
-  const nextVersion = `${a}.${b}.${c}`;
-  packageJson.version = nextVersion;
-  tauriJson.package.version = nextVersion;
-
-  // 发布更新前先写更新日志
-  const nextTag = `v${nextVersion}`;
-  await resolveUpdateLog(nextTag);
-
-  await fs.writeFile(
-    "./package.json",
-    JSON.stringify(packageJson, undefined, 2)
-  );
-  await fs.writeFile(
-    "./src-tauri/tauri.conf.json",
-    JSON.stringify(tauriJson, undefined, 2)
-  );
-
-  execSync("git add ./package.json");
-  execSync("git add ./src-tauri/tauri.conf.json");
-  execSync(`git commit -m "v${nextVersion}"`);
-  execSync(`git tag -a v${nextVersion} -m "v${nextVersion}"`);
-  execSync(`git push`);
-  execSync(`git push origin v${nextVersion}`);
-  console.log(`Publish Successfully...`);
-}
-
-resolvePublish();
diff --git a/scripts/updatelog.mjs b/scripts/updatelog.mjs
deleted file mode 100644
index fae7f628f42e13512b9bfdff921b58c936a9ae2b..0000000000000000000000000000000000000000
--- a/scripts/updatelog.mjs
+++ /dev/null
@@ -1,44 +0,0 @@
-import fs from "fs-extra";
-import path from "path";
-
-const UPDATE_LOG = "UPDATELOG.md";
-
-// parse the UPDATELOG.md
-export async function resolveUpdateLog(tag) {
-  const cwd = process.cwd();
-
-  const reTitle = /^## v[\d\.]+/;
-  const reEnd = /^---/;
-
-  const file = path.join(cwd, UPDATE_LOG);
-
-  if (!(await fs.pathExists(file))) {
-    throw new Error("could not found UPDATELOG.md");
-  }
-
-  const data = await fs.readFile(file).then((d) => d.toString("utf8"));
-
-  const map = {};
-  let p = "";
-
-  data.split("\n").forEach((line) => {
-    if (reTitle.test(line)) {
-      p = line.slice(3).trim();
-      if (!map[p]) {
-        map[p] = [];
-      } else {
-        throw new Error(`Tag ${p} dup`);
-      }
-    } else if (reEnd.test(line)) {
-      p = "";
-    } else if (p) {
-      map[p].push(line);
-    }
-  });
-
-  if (!map[tag]) {
-    throw new Error(`could not found "${tag}" in UPDATELOG.md`);
-  }
-
-  return map[tag].join("\n").trim();
-}
diff --git a/scripts/updater.mjs b/scripts/updater.mjs
deleted file mode 100644
index 2a3a8eea64419340f0849f5d86926bfa7d51d39f..0000000000000000000000000000000000000000
--- a/scripts/updater.mjs
+++ /dev/null
@@ -1,177 +0,0 @@
-import fetch from "node-fetch";
-import { getOctokit, context } from "@actions/github";
-import { resolveUpdateLog } from "./updatelog.mjs";
-
-const UPDATE_TAG_NAME = "updater";
-const UPDATE_JSON_FILE = "update.json";
-const UPDATE_JSON_PROXY = "update-proxy.json";
-
-/// generate update.json
-/// upload to update tag's release asset
-async function resolveUpdater() {
-  if (process.env.GITHUB_TOKEN === undefined) {
-    throw new Error("GITHUB_TOKEN is required");
-  }
-
-  const options = { owner: context.repo.owner, repo: context.repo.repo };
-  const github = getOctokit(process.env.GITHUB_TOKEN);
-
-  const { data: tags } = await github.rest.repos.listTags({
-    ...options,
-    per_page: 10,
-    page: 1,
-  });
-
-  // get the latest publish tag
-  const tag = tags.find((t) => t.name.startsWith("v"));
-
-  console.log(tag);
-  console.log();
-
-  const { data: latestRelease } = await github.rest.repos.getReleaseByTag({
-    ...options,
-    tag: tag.name,
-  });
-
-  const updateData = {
-    name: tag.name,
-    notes: await resolveUpdateLog(tag.name), // use updatelog.md
-    pub_date: new Date().toISOString(),
-    platforms: {
-      win64: { signature: "", url: "" }, // compatible with older formats
-      linux: { signature: "", url: "" }, // compatible with older formats
-      darwin: { signature: "", url: "" }, // compatible with older formats
-      "darwin-aarch64": { signature: "", url: "" },
-      "darwin-intel": { signature: "", url: "" },
-      "darwin-x86_64": { signature: "", url: "" },
-      "linux-x86_64": { signature: "", url: "" },
-      "windows-x86_64": { signature: "", url: "" },
-      "windows-i686": { signature: "", url: "" }, // no supported
-    },
-  };
-
-  const promises = latestRelease.assets.map(async (asset) => {
-    const { name, browser_download_url } = asset;
-
-    // win64 url
-    if (name.endsWith(".msi.zip") && name.includes("en-US")) {
-      updateData.platforms.win64.url = browser_download_url;
-      updateData.platforms["windows-x86_64"].url = browser_download_url;
-    }
-    // win64 signature
-    if (name.endsWith(".msi.zip.sig") && name.includes("en-US")) {
-      const sig = await getSignature(browser_download_url);
-      updateData.platforms.win64.signature = sig;
-      updateData.platforms["windows-x86_64"].signature = sig;
-    }
-
-    // darwin url (intel)
-    if (name.endsWith(".app.tar.gz") && !name.includes("aarch")) {
-      updateData.platforms.darwin.url = browser_download_url;
-      updateData.platforms["darwin-intel"].url = browser_download_url;
-      updateData.platforms["darwin-x86_64"].url = browser_download_url;
-    }
-    // darwin signature (intel)
-    if (name.endsWith(".app.tar.gz.sig") && !name.includes("aarch")) {
-      const sig = await getSignature(browser_download_url);
-      updateData.platforms.darwin.signature = sig;
-      updateData.platforms["darwin-intel"].signature = sig;
-      updateData.platforms["darwin-x86_64"].signature = sig;
-    }
-
-    // darwin url (aarch)
-    if (name.endsWith("aarch64.app.tar.gz")) {
-      updateData.platforms["darwin-aarch64"].url = browser_download_url;
-    }
-    // darwin signature (aarch)
-    if (name.endsWith("aarch64.app.tar.gz.sig")) {
-      const sig = await getSignature(browser_download_url);
-      updateData.platforms["darwin-aarch64"].signature = sig;
-    }
-
-    // linux url
-    if (name.endsWith(".AppImage.tar.gz")) {
-      updateData.platforms.linux.url = browser_download_url;
-      updateData.platforms["linux-x86_64"].url = browser_download_url;
-    }
-    // linux signature
-    if (name.endsWith(".AppImage.tar.gz.sig")) {
-      const sig = await getSignature(browser_download_url);
-      updateData.platforms.linux.signature = sig;
-      updateData.platforms["linux-x86_64"].signature = sig;
-    }
-  });
-
-  await Promise.allSettled(promises);
-  console.log(updateData);
-
-  // maybe should test the signature as well
-  // delete the null field
-  Object.entries(updateData.platforms).forEach(([key, value]) => {
-    if (!value.url) {
-      console.log(`[Error]: failed to parse release for "${key}"`);
-      delete updateData.platforms[key];
-    }
-  });
-
-  // 生成一个代理github的更新文件
-  // 使用 https://hub.fastgit.xyz/ 做github资源的加速
-  const updateDataNew = JSON.parse(JSON.stringify(updateData));
-
-  Object.entries(updateDataNew.platforms).forEach(([key, value]) => {
-    if (value.url) {
-      updateDataNew.platforms[key].url = "https://ghproxy.com/" + value.url;
-    } else {
-      console.log(`[Error]: updateDataNew.platforms.${key} is null`);
-    }
-  });
-
-  // update the update.json
-  const { data: updateRelease } = await github.rest.repos.getReleaseByTag({
-    ...options,
-    tag: UPDATE_TAG_NAME,
-  });
-
-  // delete the old assets
-  for (let asset of updateRelease.assets) {
-    if (asset.name === UPDATE_JSON_FILE) {
-      await github.rest.repos.deleteReleaseAsset({
-        ...options,
-        asset_id: asset.id,
-      });
-    }
-
-    if (asset.name === UPDATE_JSON_PROXY) {
-      await github.rest.repos
-        .deleteReleaseAsset({ ...options, asset_id: asset.id })
-        .catch(console.error); // do not break the pipeline
-    }
-  }
-
-  // upload new assets
-  await github.rest.repos.uploadReleaseAsset({
-    ...options,
-    release_id: updateRelease.id,
-    name: UPDATE_JSON_FILE,
-    data: JSON.stringify(updateData, null, 2),
-  });
-
-  await github.rest.repos.uploadReleaseAsset({
-    ...options,
-    release_id: updateRelease.id,
-    name: UPDATE_JSON_PROXY,
-    data: JSON.stringify(updateDataNew, null, 2),
-  });
-}
-
-// get the signature file content
-async function getSignature(url) {
-  const response = await fetch(url, {
-    method: "GET",
-    headers: { "Content-Type": "application/octet-stream" },
-  });
-
-  return response.text();
-}
-
-resolveUpdater().catch(console.error);
diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore
deleted file mode 100644
index 7b128ffce57dfbbc5dca361dd1cc78b3f93b25d7..0000000000000000000000000000000000000000
--- a/src-tauri/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# Generated by Cargo
-# will have compiled files and executables
-/target/
-WixTools
-resources
-sidecar
diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
deleted file mode 100644
index 9b1c0ec5ffe5b3e2440036df3799eef73a00434c..0000000000000000000000000000000000000000
--- a/src-tauri/Cargo.lock
+++ /dev/null
@@ -1,5658 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "adler"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
-
-[[package]]
-name = "ahash"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
-dependencies = [
- "getrandom 0.2.9",
- "once_cell",
- "version_check",
-]
-
-[[package]]
-name = "aho-corasick"
-version = "0.6.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
-dependencies = [
- "memchr",
-]
-
-[[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.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04"
-dependencies = [
- "memchr",
-]
-
-[[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_system_properties"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "anyhow"
-version = "1.0.71"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
-
-[[package]]
-name = "arc-swap"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
-
-[[package]]
-name = "async-channel"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
-dependencies = [
- "concurrent-queue",
- "event-listener",
- "futures-core",
-]
-
-[[package]]
-name = "async-executor"
-version = "1.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb"
-dependencies = [
- "async-lock",
- "async-task",
- "concurrent-queue",
- "fastrand",
- "futures-lite",
- "slab",
-]
-
-[[package]]
-name = "async-fs"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06"
-dependencies = [
- "async-lock",
- "autocfg",
- "blocking",
- "futures-lite",
-]
-
-[[package]]
-name = "async-io"
-version = "1.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
-dependencies = [
- "async-lock",
- "autocfg",
- "cfg-if",
- "concurrent-queue",
- "futures-lite",
- "log 0.4.17",
- "parking",
- "polling",
- "rustix",
- "slab",
- "socket2",
- "waker-fn",
-]
-
-[[package]]
-name = "async-lock"
-version = "2.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7"
-dependencies = [
- "event-listener",
-]
-
-[[package]]
-name = "async-net"
-version = "1.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4051e67316bc7eff608fe723df5d32ed639946adcd69e07df41fd42a7b411f1f"
-dependencies = [
- "async-io",
- "autocfg",
- "blocking",
- "futures-lite",
-]
-
-[[package]]
-name = "async-process"
-version = "1.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9"
-dependencies = [
- "async-io",
- "async-lock",
- "autocfg",
- "blocking",
- "cfg-if",
- "event-listener",
- "futures-lite",
- "rustix",
- "signal-hook 0.3.15",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "async-task"
-version = "4.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae"
-
-[[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.18",
-]
-
-[[package]]
-name = "atk"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd"
-dependencies = [
- "atk-sys",
- "bitflags",
- "glib",
- "libc",
-]
-
-[[package]]
-name = "atk-sys"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6"
-dependencies = [
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "atomic-waker"
-version = "1.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3"
-
-[[package]]
-name = "attohttpc"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7"
-dependencies = [
- "flate2",
- "http",
- "log 0.4.17",
- "native-tls",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "url",
-]
-
-[[package]]
-name = "auto-launch"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f012b8cc0c850f34117ec8252a44418f2e34a2cf501de89e29b241ae5f79471"
-dependencies = [
- "dirs 4.0.0",
- "thiserror",
- "winreg 0.10.1",
-]
-
-[[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
-[[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 = "bitflags"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "block"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
-
-[[package]]
-name = "block-buffer"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
-dependencies = [
- "generic-array",
-]
-
-[[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 = "blocking"
-version = "1.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65"
-dependencies = [
- "async-channel",
- "async-lock",
- "async-task",
- "atomic-waker",
- "fastrand",
- "futures-lite",
- "log 0.4.17",
-]
-
-[[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 = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5"
-dependencies = [
- "memchr",
- "serde",
-]
-
-[[package]]
-name = "bumpalo"
-version = "3.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
-
-[[package]]
-name = "bytemuck"
-version = "1.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea"
-
-[[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"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "cairo-rs"
-version = "0.15.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc"
-dependencies = [
- "bitflags",
- "cairo-sys-rs",
- "glib",
- "libc",
- "thiserror",
-]
-
-[[package]]
-name = "cairo-sys-rs"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8"
-dependencies = [
- "glib-sys",
- "libc",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "cargo_toml"
-version = "0.13.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "497049e9477329f8f6a559972ee42e117487d01d1e8c2cc9f836ea6fa23a9e1a"
-dependencies = [
- "serde",
- "toml 0.5.11",
-]
-
-[[package]]
-name = "cc"
-version = "1.0.79"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
-
-[[package]]
-name = "cesu8"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
-
-[[package]]
-name = "cfb"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f"
-dependencies = [
- "byteorder",
- "fnv",
- "uuid",
-]
-
-[[package]]
-name = "cfg-expr"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7"
-dependencies = [
- "smallvec",
-]
-
-[[package]]
-name = "cfg-expr"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8790cf1286da485c72cf5fc7aeba308438800036ec67d89425924c4807268c9"
-dependencies = [
- "smallvec",
- "target-lexicon",
-]
-
-[[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.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b"
-dependencies = [
- "iana-time-zone",
- "js-sys",
- "num-integer",
- "num-traits",
- "serde",
- "time 0.1.45",
- "wasm-bindgen",
- "winapi",
-]
-
-[[package]]
-name = "clash-verge"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "auto-launch",
- "chrono",
- "ctrlc",
- "deelevate",
- "delay_timer",
- "dirs 5.0.1",
- "dunce",
- "log 0.4.17",
- "log4rs",
- "nanoid",
- "once_cell",
- "open 4.1.0",
- "parking_lot",
- "port_scanner",
- "reqwest",
- "rquickjs",
- "runas",
- "serde",
- "serde_json",
- "serde_yaml 0.9.21",
- "sysinfo",
- "sysproxy",
- "tauri",
- "tauri-build",
- "tokio",
- "warp",
- "which",
- "window-shadows",
- "window-vibrancy",
- "windows-sys 0.48.0",
- "winreg 0.50.0",
- "wry",
-]
-
-[[package]]
-name = "cocoa"
-version = "0.24.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a"
-dependencies = [
- "bitflags",
- "block",
- "cocoa-foundation",
- "core-foundation",
- "core-graphics",
- "foreign-types",
- "libc",
- "objc",
-]
-
-[[package]]
-name = "cocoa-foundation"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6"
-dependencies = [
- "bitflags",
- "block",
- "core-foundation",
- "core-graphics-types",
- "foreign-types",
- "libc",
- "objc",
-]
-
-[[package]]
-name = "color_quant"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
-
-[[package]]
-name = "combine"
-version = "4.6.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"
-dependencies = [
- "bytes",
- "memchr",
-]
-
-[[package]]
-name = "concat-idents"
-version = "1.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fe0e1d9f7de897d18e590a7496b5facbe87813f746cf4b8db596ba77e07e832"
-dependencies = [
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "concurrent-queue"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c"
-dependencies = [
- "crossbeam-utils",
-]
-
-[[package]]
-name = "convert_case"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
-
-[[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 = "core-graphics"
-version = "0.22.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
-dependencies = [
- "bitflags",
- "core-foundation",
- "core-graphics-types",
- "foreign-types",
- "libc",
-]
-
-[[package]]
-name = "core-graphics-types"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
-dependencies = [
- "bitflags",
- "core-foundation",
- "foreign-types",
- "libc",
-]
-
-[[package]]
-name = "cpufeatures"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58"
-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 = "cron_clock"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a8699d8ed16e3db689f8ae04d8dc3c6666a4ba7e724e5a157884b7cc385d16b"
-dependencies = [
- "chrono",
- "nom 7.1.3",
- "once_cell",
-]
-
-[[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-deque"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
-dependencies = [
- "cfg-if",
- "crossbeam-epoch",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-epoch"
-version = "0.9.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
-dependencies = [
- "autocfg",
- "cfg-if",
- "crossbeam-utils",
- "memoffset 0.8.0",
- "scopeguard",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
-dependencies = [
- "cfg-if",
-]
-
-[[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 = "cssparser"
-version = "0.27.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a"
-dependencies = [
- "cssparser-macros",
- "dtoa-short",
- "itoa 0.4.8",
- "matches",
- "phf 0.8.0",
- "proc-macro2",
- "quote",
- "smallvec",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "cssparser-macros"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e"
-dependencies = [
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "ctor"
-version = "0.1.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
-dependencies = [
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "ctrlc"
-version = "3.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7394a21d012ce5c850497fb774b167d81b99f060025fbf06ee92b9848bd97eb2"
-dependencies = [
- "nix 0.26.2",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "cty"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
-
-[[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",
- "strsim",
- "syn 2.0.18",
-]
-
-[[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.18",
-]
-
-[[package]]
-name = "dashmap"
-version = "4.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c"
-dependencies = [
- "cfg-if",
- "num_cpus",
-]
-
-[[package]]
-name = "deelevate"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c7397f8c48906dd9b5afc75001368c979418e5dff5575998a831eb2319b424e"
-dependencies = [
- "lazy_static 1.4.0",
- "pathsearch",
- "rand 0.8.5",
- "shared_library",
- "termwiz",
- "winapi",
-]
-
-[[package]]
-name = "delay_timer"
-version = "0.11.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46e3040b73d9397711697558109c983a2dc6fc63e98785ffbefd3ece57b46b67"
-dependencies = [
- "anyhow",
- "async-trait",
- "autocfg",
- "concat-idents",
- "cron_clock",
- "dashmap",
- "event-listener",
- "futures",
- "log 0.4.17",
- "lru",
- "once_cell",
- "rs-snowflake",
- "rustc_version 0.2.3",
- "smol",
- "thiserror",
- "tokio",
- "tracing",
-]
-
-[[package]]
-name = "derivative"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "derive_more"
-version = "0.99.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
-dependencies = [
- "convert_case",
- "proc-macro2",
- "quote",
- "rustc_version 0.4.0",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "destructure_traitobject"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7"
-
-[[package]]
-name = "digest"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "digest"
-version = "0.10.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
-dependencies = [
- "block-buffer 0.10.4",
- "crypto-common",
-]
-
-[[package]]
-name = "dirs"
-version = "4.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
-dependencies = [
- "dirs-sys 0.3.7",
-]
-
-[[package]]
-name = "dirs"
-version = "5.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
-dependencies = [
- "dirs-sys 0.4.1",
-]
-
-[[package]]
-name = "dirs-next"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
-dependencies = [
- "cfg-if",
- "dirs-sys-next",
-]
-
-[[package]]
-name = "dirs-sys"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
-dependencies = [
- "libc",
- "redox_users",
- "winapi",
-]
-
-[[package]]
-name = "dirs-sys"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
-dependencies = [
- "libc",
- "option-ext",
- "redox_users",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "dirs-sys-next"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
-dependencies = [
- "libc",
- "redox_users",
- "winapi",
-]
-
-[[package]]
-name = "dispatch"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
-
-[[package]]
-name = "dtoa"
-version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
-
-[[package]]
-name = "dtoa-short"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bde03329ae10e79ede66c9ce4dc930aa8599043b0743008548680f25b91502d6"
-dependencies = [
- "dtoa",
-]
-
-[[package]]
-name = "dunce"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
-
-[[package]]
-name = "either"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
-
-[[package]]
-name = "embed_plist"
-version = "1.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
-
-[[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 = "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 = "event-listener"
-version = "2.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
-
-[[package]]
-name = "fastrand"
-version = "1.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
-dependencies = [
- "instant",
-]
-
-[[package]]
-name = "fdeflate"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10"
-dependencies = [
- "simd-adler32",
-]
-
-[[package]]
-name = "field-offset"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535"
-dependencies = [
- "memoffset 0.8.0",
- "rustc_version 0.4.0",
-]
-
-[[package]]
-name = "filedescriptor"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7199d965852c3bac31f779ef99cbb4537f80e952e2d6aa0ffeb30cce00f4f46e"
-dependencies = [
- "libc",
- "thiserror",
- "winapi",
-]
-
-[[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 = "flate2"
-version = "1.0.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
-dependencies = [
- "crc32fast",
- "miniz_oxide",
-]
-
-[[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.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
-dependencies = [
- "percent-encoding",
-]
-
-[[package]]
-name = "futf"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
-dependencies = [
- "mac",
- "new_debug_unreachable",
-]
-
-[[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-lite"
-version = "1.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
-dependencies = [
- "fastrand",
- "futures-core",
- "futures-io",
- "memchr",
- "parking",
- "pin-project-lite",
- "waker-fn",
-]
-
-[[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.18",
-]
-
-[[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 = "fxhash"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
-dependencies = [
- "byteorder",
-]
-
-[[package]]
-name = "gdk"
-version = "0.15.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8"
-dependencies = [
- "bitflags",
- "cairo-rs",
- "gdk-pixbuf",
- "gdk-sys",
- "gio",
- "glib",
- "libc",
- "pango",
-]
-
-[[package]]
-name = "gdk-pixbuf"
-version = "0.15.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a"
-dependencies = [
- "bitflags",
- "gdk-pixbuf-sys",
- "gio",
- "glib",
- "libc",
-]
-
-[[package]]
-name = "gdk-pixbuf-sys"
-version = "0.15.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7"
-dependencies = [
- "gio-sys",
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "gdk-sys"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88"
-dependencies = [
- "cairo-sys-rs",
- "gdk-pixbuf-sys",
- "gio-sys",
- "glib-sys",
- "gobject-sys",
- "libc",
- "pango-sys",
- "pkg-config",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "gdkwayland-sys"
-version = "0.15.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cca49a59ad8cfdf36ef7330fe7bdfbe1d34323220cc16a0de2679ee773aee2c2"
-dependencies = [
- "gdk-sys",
- "glib-sys",
- "gobject-sys",
- "libc",
- "pkg-config",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "gdkx11-sys"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4b7f8c7a84b407aa9b143877e267e848ff34106578b64d1e0a24bf550716178"
-dependencies = [
- "gdk-sys",
- "glib-sys",
- "libc",
- "system-deps 6.1.0",
- "x11",
-]
-
-[[package]]
-name = "generator"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3e123d9ae7c02966b4d892e550bdc32164f05853cd40ab570650ad600596a8a"
-dependencies = [
- "cc",
- "libc",
- "log 0.4.17",
- "rustversion",
- "windows 0.48.0",
-]
-
-[[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.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
-]
-
-[[package]]
-name = "gio"
-version = "0.15.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b"
-dependencies = [
- "bitflags",
- "futures-channel",
- "futures-core",
- "futures-io",
- "gio-sys",
- "glib",
- "libc",
- "once_cell",
- "thiserror",
-]
-
-[[package]]
-name = "gio-sys"
-version = "0.15.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d"
-dependencies = [
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps 6.1.0",
- "winapi",
-]
-
-[[package]]
-name = "glib"
-version = "0.15.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d"
-dependencies = [
- "bitflags",
- "futures-channel",
- "futures-core",
- "futures-executor",
- "futures-task",
- "glib-macros",
- "glib-sys",
- "gobject-sys",
- "libc",
- "once_cell",
- "smallvec",
- "thiserror",
-]
-
-[[package]]
-name = "glib-macros"
-version = "0.15.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10c6ae9f6fa26f4fb2ac16b528d138d971ead56141de489f8111e259b9df3c4a"
-dependencies = [
- "anyhow",
- "heck 0.4.1",
- "proc-macro-crate",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "glib-sys"
-version = "0.15.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4"
-dependencies = [
- "libc",
- "system-deps 6.1.0",
-]
-
-[[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",
- "fnv",
- "log 0.4.17",
- "regex 1.8.3",
-]
-
-[[package]]
-name = "gobject-sys"
-version = "0.15.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a"
-dependencies = [
- "glib-sys",
- "libc",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "gtk"
-version = "0.15.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0"
-dependencies = [
- "atk",
- "bitflags",
- "cairo-rs",
- "field-offset",
- "futures-channel",
- "gdk",
- "gdk-pixbuf",
- "gio",
- "glib",
- "gtk-sys",
- "gtk3-macros",
- "libc",
- "once_cell",
- "pango",
- "pkg-config",
-]
-
-[[package]]
-name = "gtk-sys"
-version = "0.15.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84"
-dependencies = [
- "atk-sys",
- "cairo-sys-rs",
- "gdk-pixbuf-sys",
- "gdk-sys",
- "gio-sys",
- "glib-sys",
- "gobject-sys",
- "libc",
- "pango-sys",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "gtk3-macros"
-version = "0.15.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "684c0456c086e8e7e9af73ec5b84e35938df394712054550e81558d21c44ab0d"
-dependencies = [
- "anyhow",
- "proc-macro-crate",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "h2"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782"
-dependencies = [
- "bytes",
- "fnv",
- "futures-core",
- "futures-sink",
- "futures-util",
- "http",
- "indexmap",
- "slab",
- "tokio",
- "tokio-util",
- "tracing",
-]
-
-[[package]]
-name = "handlebars"
-version = "0.29.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb04af2006ea09d985fef82b81e0eb25337e51b691c76403332378a53d521edc"
-dependencies = [
- "lazy_static 0.2.11",
- "log 0.3.9",
- "pest 0.3.3",
- "quick-error",
- "regex 0.2.11",
- "serde",
- "serde_json",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
-dependencies = [
- "ahash",
-]
-
-[[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.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.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
-[[package]]
-name = "html5ever"
-version = "0.25.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5c13fb08e5d4dfc151ee5e88bae63f7773d61852f3bdc73c9f4b9e1bde03148"
-dependencies = [
- "log 0.4.17",
- "mac",
- "markup5ever",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "http"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
-dependencies = [
- "bytes",
- "fnv",
- "itoa 1.0.6",
-]
-
-[[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"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
-
-[[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.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "httparse",
- "httpdate",
- "itoa 1.0.6",
- "pin-project-lite",
- "socket2",
- "tokio",
- "tower-service",
- "tracing",
- "want",
-]
-
-[[package]]
-name = "hyper-rustls"
-version = "0.24.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7"
-dependencies = [
- "http",
- "hyper",
- "rustls",
- "tokio",
- "tokio-rustls",
-]
-
-[[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.56"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
-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 = "ico"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3804960be0bb5e4edb1e1ad67afd321a9ecfd875c3e65c099468fd2717d7cae"
-dependencies = [
- "byteorder",
- "png",
-]
-
-[[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.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
-dependencies = [
- "unicode-bidi",
- "unicode-normalization",
-]
-
-[[package]]
-name = "ignore"
-version = "0.4.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d"
-dependencies = [
- "crossbeam-utils",
- "globset",
- "lazy_static 1.4.0",
- "log 0.4.17",
- "memchr",
- "regex 1.8.3",
- "same-file",
- "thread_local 1.1.7",
- "walkdir",
- "winapi-util",
-]
-
-[[package]]
-name = "image"
-version = "0.24.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a"
-dependencies = [
- "bytemuck",
- "byteorder",
- "color_quant",
- "num-rational",
- "num-traits",
-]
-
-[[package]]
-name = "indexmap"
-version = "1.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
-dependencies = [
- "autocfg",
- "hashbrown",
- "serde",
-]
-
-[[package]]
-name = "infer"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f178e61cdbfe084aa75a2f4f7a25a5bb09701a47ae1753608f194b15783c937a"
-dependencies = [
- "cfb",
-]
-
-[[package]]
-name = "infer"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a898e4b7951673fce96614ce5751d13c40fc5674bc2d759288e46c3ab62598b3"
-dependencies = [
- "cfb",
-]
-
-[[package]]
-name = "instant"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "interfaces"
-version = "0.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ec8f50a973916cac3da5057c986db05cd3346f38c78e9bc24f64cc9f6a3978f"
-dependencies = [
- "bitflags",
- "cc",
- "handlebars",
- "lazy_static 1.4.0",
- "libc",
- "nix 0.23.2",
- "serde",
- "serde_derive",
-]
-
-[[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 = "ipnet"
-version = "2.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
-
-[[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-wsl"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
-dependencies = [
- "is-docker",
- "once_cell",
-]
-
-[[package]]
-name = "itoa"
-version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
-
-[[package]]
-name = "itoa"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
-
-[[package]]
-name = "javascriptcore-rs"
-version = "0.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf053e7843f2812ff03ef5afe34bb9c06ffee120385caad4f6b9967fcd37d41c"
-dependencies = [
- "bitflags",
- "glib",
- "javascriptcore-rs-sys",
-]
-
-[[package]]
-name = "javascriptcore-rs-sys"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "905fbb87419c5cde6e3269537e4ea7d46431f3008c5d057e915ef3f115e7793c"
-dependencies = [
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps 5.0.0",
-]
-
-[[package]]
-name = "jni"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c"
-dependencies = [
- "cesu8",
- "combine",
- "jni-sys",
- "log 0.4.17",
- "thiserror",
- "walkdir",
-]
-
-[[package]]
-name = "jni-sys"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
-
-[[package]]
-name = "js-sys"
-version = "0.3.63"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790"
-dependencies = [
- "wasm-bindgen",
-]
-
-[[package]]
-name = "json-patch"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb3fa5a61630976fc4c353c70297f2e93f1930e3ccee574d59d618ccbd5154ce"
-dependencies = [
- "serde",
- "serde_json",
- "treediff 3.0.2",
-]
-
-[[package]]
-name = "json-patch"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f54898088ccb91df1b492cc80029a6fdf1c48ca0db7c6822a8babad69c94658"
-dependencies = [
- "serde",
- "serde_json",
- "thiserror",
- "treediff 4.0.2",
-]
-
-[[package]]
-name = "kuchiki"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ea8e9c6e031377cff82ee3001dc8026cdf431ed4e2e6b51f98ab8c73484a358"
-dependencies = [
- "cssparser",
- "html5ever",
- "matches",
- "selectors",
-]
-
-[[package]]
-name = "lazy_static"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
-
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
-[[package]]
-name = "libappindicator"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db2d3cb96d092b4824cb306c9e544c856a4cb6210c1081945187f7f1924b47e8"
-dependencies = [
- "glib",
- "gtk",
- "gtk-sys",
- "libappindicator-sys",
- "log 0.4.17",
-]
-
-[[package]]
-name = "libappindicator-sys"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1b3b6681973cea8cc3bce7391e6d7d5502720b80a581c9a95c9cbaf592826aa"
-dependencies = [
- "gtk-sys",
- "libloading",
- "once_cell",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.144"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
-
-[[package]]
-name = "libloading"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
-dependencies = [
- "cfg-if",
- "winapi",
-]
-
-[[package]]
-name = "line-wrap"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
-dependencies = [
- "safemem",
-]
-
-[[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 = "lock_api"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
-dependencies = [
- "autocfg",
- "scopeguard",
-]
-
-[[package]]
-name = "log"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
-dependencies = [
- "log 0.4.17",
-]
-
-[[package]]
-name = "log"
-version = "0.4.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
-dependencies = [
- "cfg-if",
- "serde",
-]
-
-[[package]]
-name = "log-mdc"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7"
-
-[[package]]
-name = "log4rs"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d36ca1786d9e79b8193a68d480a0907b612f109537115c6ff655a3a1967533fd"
-dependencies = [
- "anyhow",
- "arc-swap",
- "chrono",
- "derivative",
- "fnv",
- "humantime",
- "libc",
- "log 0.4.17",
- "log-mdc",
- "parking_lot",
- "serde",
- "serde-value",
- "serde_json",
- "serde_yaml 0.8.26",
- "thiserror",
- "thread-id",
- "typemap-ors",
- "winapi",
-]
-
-[[package]]
-name = "loom"
-version = "0.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5"
-dependencies = [
- "cfg-if",
- "generator",
- "scoped-tls",
- "serde",
- "serde_json",
- "tracing",
- "tracing-subscriber",
-]
-
-[[package]]
-name = "lru"
-version = "0.7.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a"
-dependencies = [
- "hashbrown",
-]
-
-[[package]]
-name = "mac"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
-
-[[package]]
-name = "malloc_buf"
-version = "0.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "markup5ever"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd"
-dependencies = [
- "log 0.4.17",
- "phf 0.8.0",
- "phf_codegen 0.8.0",
- "string_cache",
- "string_cache_codegen",
- "tendril",
-]
-
-[[package]]
-name = "matchers"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
-dependencies = [
- "regex-automata",
-]
-
-[[package]]
-name = "matches"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
-
-[[package]]
-name = "memchr"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
-
-[[package]]
-name = "memmem"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15"
-
-[[package]]
-name = "memoffset"
-version = "0.6.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "memoffset"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
-dependencies = [
- "autocfg",
-]
-
-[[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 = "minisign-verify"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "933dca44d65cdd53b355d0b73d380a2ff5da71f87f036053188bf1eab6a19881"
-
-[[package]]
-name = "miniz_oxide"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
-dependencies = [
- "adler",
- "simd-adler32",
-]
-
-[[package]]
-name = "mio"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
-dependencies = [
- "libc",
- "log 0.4.17",
- "wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys 0.45.0",
-]
-
-[[package]]
-name = "multer"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2"
-dependencies = [
- "bytes",
- "encoding_rs",
- "futures-util",
- "http",
- "httparse",
- "log 0.4.17",
- "memchr",
- "mime",
- "spin 0.9.8",
- "version_check",
-]
-
-[[package]]
-name = "nanoid"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8"
-dependencies = [
- "rand 0.8.5",
-]
-
-[[package]]
-name = "native-tls"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
-dependencies = [
- "lazy_static 1.4.0",
- "libc",
- "log 0.4.17",
- "openssl",
- "openssl-probe",
- "openssl-sys",
- "schannel",
- "security-framework",
- "security-framework-sys",
- "tempfile",
-]
-
-[[package]]
-name = "ndk"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4"
-dependencies = [
- "bitflags",
- "jni-sys",
- "ndk-sys",
- "num_enum",
- "thiserror",
-]
-
-[[package]]
-name = "ndk-context"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
-
-[[package]]
-name = "ndk-sys"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97"
-dependencies = [
- "jni-sys",
-]
-
-[[package]]
-name = "new_debug_unreachable"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
-
-[[package]]
-name = "nix"
-version = "0.23.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
-dependencies = [
- "bitflags",
- "cc",
- "cfg-if",
- "libc",
- "memoffset 0.6.5",
-]
-
-[[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 = "nodrop"
-version = "0.1.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
-
-[[package]]
-name = "nom"
-version = "5.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b"
-dependencies = [
- "memchr",
- "version_check",
-]
-
-[[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 = "ntapi"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "nu-ansi-term"
-version = "0.46.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
-dependencies = [
- "overload",
- "winapi",
-]
-
-[[package]]
-name = "num-derive"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "num-integer"
-version = "0.1.45"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
-dependencies = [
- "autocfg",
- "num-traits",
-]
-
-[[package]]
-name = "num-rational"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
-dependencies = [
- "autocfg",
- "num-integer",
- "num-traits",
-]
-
-[[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_enum"
-version = "0.5.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
-dependencies = [
- "num_enum_derive",
-]
-
-[[package]]
-name = "num_enum_derive"
-version = "0.5.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
-dependencies = [
- "proc-macro-crate",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "num_threads"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "objc"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
-dependencies = [
- "malloc_buf",
- "objc_exception",
-]
-
-[[package]]
-name = "objc-foundation"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
-dependencies = [
- "block",
- "objc",
- "objc_id",
-]
-
-[[package]]
-name = "objc_exception"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
-dependencies = [
- "cc",
-]
-
-[[package]]
-name = "objc_id"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
-dependencies = [
- "objc",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.17.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
-
-[[package]]
-name = "opaque-debug"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
-
-[[package]]
-name = "open"
-version = "3.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2078c0039e6a54a0c42c28faa984e115fb4c2d5bf2208f77d1961002df8576f8"
-dependencies = [
- "pathdiff",
- "windows-sys 0.42.0",
-]
-
-[[package]]
-name = "open"
-version = "4.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d16814a067484415fda653868c9be0ac5f2abd2ef5d951082a5f2fe1b3662944"
-dependencies = [
- "is-wsl",
- "pathdiff",
-]
-
-[[package]]
-name = "openssl"
-version = "0.10.52"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56"
-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.18",
-]
-
-[[package]]
-name = "openssl-probe"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
-
-[[package]]
-name = "openssl-src"
-version = "111.25.3+1.1.1t"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "924757a6a226bf60da5f7dd0311a34d2b52283dd82ddeb103208ddc66362f80c"
-dependencies = [
- "cc",
-]
-
-[[package]]
-name = "openssl-sys"
-version = "0.9.87"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e"
-dependencies = [
- "cc",
- "libc",
- "openssl-src",
- "pkg-config",
- "vcpkg",
-]
-
-[[package]]
-name = "option-ext"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
-
-[[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 = "os_pipe"
-version = "1.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ae859aa07428ca9a929b936690f8b12dc5f11dd8c6992a18ca93919f28bc177"
-dependencies = [
- "libc",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "overload"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
-
-[[package]]
-name = "pango"
-version = "0.15.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f"
-dependencies = [
- "bitflags",
- "glib",
- "libc",
- "once_cell",
- "pango-sys",
-]
-
-[[package]]
-name = "pango-sys"
-version = "0.15.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa"
-dependencies = [
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "parking"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e"
-
-[[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.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
-dependencies = [
- "cfg-if",
- "libc",
- "redox_syscall 0.2.16",
- "smallvec",
- "windows-sys 0.45.0",
-]
-
-[[package]]
-name = "pathdiff"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
-
-[[package]]
-name = "pathsearch"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da983bc5e582ab17179c190b4b66c7d76c5943a69c6d34df2a2b6bf8a2977b05"
-dependencies = [
- "anyhow",
- "libc",
-]
-
-[[package]]
-name = "percent-encoding"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
-
-[[package]]
-name = "pest"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8"
-
-[[package]]
-name = "pest"
-version = "2.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e68e84bfb01f0507134eac1e9b410a12ba379d064eab48c50ba4ce329a527b70"
-dependencies = [
- "thiserror",
- "ucd-trie",
-]
-
-[[package]]
-name = "phf"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
-dependencies = [
- "phf_macros 0.8.0",
- "phf_shared 0.8.0",
- "proc-macro-hack",
-]
-
-[[package]]
-name = "phf"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
-dependencies = [
- "phf_macros 0.10.0",
- "phf_shared 0.10.0",
- "proc-macro-hack",
-]
-
-[[package]]
-name = "phf"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c"
-dependencies = [
- "phf_shared 0.11.1",
-]
-
-[[package]]
-name = "phf_codegen"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815"
-dependencies = [
- "phf_generator 0.8.0",
- "phf_shared 0.8.0",
-]
-
-[[package]]
-name = "phf_codegen"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770"
-dependencies = [
- "phf_generator 0.11.1",
- "phf_shared 0.11.1",
-]
-
-[[package]]
-name = "phf_generator"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
-dependencies = [
- "phf_shared 0.8.0",
- "rand 0.7.3",
-]
-
-[[package]]
-name = "phf_generator"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
-dependencies = [
- "phf_shared 0.10.0",
- "rand 0.8.5",
-]
-
-[[package]]
-name = "phf_generator"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf"
-dependencies = [
- "phf_shared 0.11.1",
- "rand 0.8.5",
-]
-
-[[package]]
-name = "phf_macros"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c"
-dependencies = [
- "phf_generator 0.8.0",
- "phf_shared 0.8.0",
- "proc-macro-hack",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "phf_macros"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0"
-dependencies = [
- "phf_generator 0.10.0",
- "phf_shared 0.10.0",
- "proc-macro-hack",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "phf_shared"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
-dependencies = [
- "siphasher",
-]
-
-[[package]]
-name = "phf_shared"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
-dependencies = [
- "siphasher",
-]
-
-[[package]]
-name = "phf_shared"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676"
-dependencies = [
- "siphasher",
-]
-
-[[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.18",
-]
-
-[[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 = "plist"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590"
-dependencies = [
- "base64 0.21.2",
- "indexmap",
- "line-wrap",
- "quick-xml",
- "serde",
- "time 0.3.15",
-]
-
-[[package]]
-name = "png"
-version = "0.17.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa"
-dependencies = [
- "bitflags",
- "crc32fast",
- "fdeflate",
- "flate2",
- "miniz_oxide",
-]
-
-[[package]]
-name = "polling"
-version = "2.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
-dependencies = [
- "autocfg",
- "bitflags",
- "cfg-if",
- "concurrent-queue",
- "libc",
- "log 0.4.17",
- "pin-project-lite",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "port_scanner"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "325a6d2ac5dee293c3b2612d4993b98aec1dff096b0a2dae70ed7d95784a05da"
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
-
-[[package]]
-name = "precomputed-hash"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
-
-[[package]]
-name = "proc-macro-crate"
-version = "1.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
-dependencies = [
- "once_cell",
- "toml_edit",
-]
-
-[[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.59"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
-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 = "quick-xml"
-version = "0.28.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1"
-dependencies = [
- "memchr",
-]
-
-[[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.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
-dependencies = [
- "getrandom 0.1.16",
- "libc",
- "rand_chacha 0.2.2",
- "rand_core 0.5.1",
- "rand_hc",
- "rand_pcg",
-]
-
-[[package]]
-name = "rand"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-dependencies = [
- "libc",
- "rand_chacha 0.3.1",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.5.1",
-]
-
-[[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 0.6.4",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-dependencies = [
- "getrandom 0.1.16",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-dependencies = [
- "getrandom 0.2.9",
-]
-
-[[package]]
-name = "rand_hc"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
-dependencies = [
- "rand_core 0.5.1",
-]
-
-[[package]]
-name = "rand_pcg"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
-dependencies = [
- "rand_core 0.5.1",
-]
-
-[[package]]
-name = "raw-window-handle"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a"
-dependencies = [
- "cty",
-]
-
-[[package]]
-name = "rayon"
-version = "1.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
-dependencies = [
- "either",
- "rayon-core",
-]
-
-[[package]]
-name = "rayon-core"
-version = "1.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
-dependencies = [
- "crossbeam-channel",
- "crossbeam-deque",
- "crossbeam-utils",
- "num_cpus",
-]
-
-[[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.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
-dependencies = [
- "getrandom 0.2.9",
- "redox_syscall 0.2.16",
- "thiserror",
-]
-
-[[package]]
-name = "regex"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
-dependencies = [
- "aho-corasick 0.6.10",
- "memchr",
- "regex-syntax 0.5.6",
- "thread_local 0.3.6",
- "utf8-ranges",
-]
-
-[[package]]
-name = "regex"
-version = "1.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390"
-dependencies = [
- "aho-corasick 1.0.1",
- "memchr",
- "regex-syntax 0.7.2",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
-dependencies = [
- "regex-syntax 0.6.29",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
-dependencies = [
- "ucd-util",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.6.29"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
-
-[[package]]
-name = "regex-syntax"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
-
-[[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",
- "hyper-tls",
- "ipnet",
- "js-sys",
- "log 0.4.17",
- "mime",
- "native-tls",
- "once_cell",
- "percent-encoding",
- "pin-project-lite",
- "rustls",
- "rustls-pemfile",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "tokio",
- "tokio-native-tls",
- "tokio-rustls",
- "tokio-util",
- "tower-service",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "wasm-streams",
- "web-sys",
- "webpki-roots",
- "winreg 0.10.1",
-]
-
-[[package]]
-name = "rfd"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea"
-dependencies = [
- "block",
- "dispatch",
- "glib-sys",
- "gobject-sys",
- "gtk-sys",
- "js-sys",
- "lazy_static 1.4.0",
- "log 0.4.17",
- "objc",
- "objc-foundation",
- "objc_id",
- "raw-window-handle",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "windows 0.37.0",
-]
-
-[[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 0.5.2",
- "untrusted",
- "web-sys",
- "winapi",
-]
-
-[[package]]
-name = "rquickjs"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc022cc82b5de6f38b2f4ddb8ed9c49cdbd7ce112e650b181598e102157257de"
-dependencies = [
- "rquickjs-core",
-]
-
-[[package]]
-name = "rquickjs-core"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74fa1ecc1c84b31da87e5b26ce2b5218d36ffeb5c322141c78b79fa86a6ee3b9"
-dependencies = [
- "rquickjs-sys",
-]
-
-[[package]]
-name = "rquickjs-sys"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24311952af42d8252e399cf48e7d470cb413b1a11a1a5b7fab648cd2edec76c5"
-dependencies = [
- "cc",
-]
-
-[[package]]
-name = "rs-snowflake"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e60ef3b82994702bbe4e134d98aadca4b49ed04440148985678d415c68127666"
-
-[[package]]
-name = "runas"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49535b7c73aec5596ae2c44a6d8a7a8f8592e5744564c327fd4846750413d921"
-dependencies = [
- "libc",
- "security-framework-sys",
- "which",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "rustc_version"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-dependencies = [
- "semver 0.9.0",
-]
-
-[[package]]
-name = "rustc_version"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
-dependencies = [
- "semver 1.0.17",
-]
-
-[[package]]
-name = "rustix"
-version = "0.37.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
-dependencies = [
- "bitflags",
- "errno",
- "io-lifetimes",
- "libc",
- "linux-raw-sys",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "rustls"
-version = "0.21.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e"
-dependencies = [
- "log 0.4.17",
- "ring",
- "rustls-webpki",
- "sct",
-]
-
-[[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 = "rustversion"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
-
-[[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 = "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 = "scoped-tls"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
-
-[[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 = "selectors"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe"
-dependencies = [
- "bitflags",
- "cssparser",
- "derive_more",
- "fxhash",
- "log 0.4.17",
- "matches",
- "phf 0.8.0",
- "phf_codegen 0.8.0",
- "precomputed-hash",
- "servo_arc",
- "smallvec",
- "thin-slice",
-]
-
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-dependencies = [
- "semver-parser 0.7.0",
-]
-
-[[package]]
-name = "semver"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
-dependencies = [
- "semver-parser 0.10.2",
-]
-
-[[package]]
-name = "semver"
-version = "1.0.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-
-[[package]]
-name = "semver-parser"
-version = "0.10.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
-dependencies = [
- "pest 2.6.0",
-]
-
-[[package]]
-name = "serde"
-version = "1.0.163"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
-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.163"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.96"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
-dependencies = [
- "itoa 1.0.6",
- "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.18",
-]
-
-[[package]]
-name = "serde_spanned"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d"
-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 1.0.6",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "serde_with"
-version = "2.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe"
-dependencies = [
- "base64 0.13.1",
- "chrono",
- "hex",
- "indexmap",
- "serde",
- "serde_json",
- "serde_with_macros",
- "time 0.3.15",
-]
-
-[[package]]
-name = "serde_with_macros"
-version = "2.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f"
-dependencies = [
- "darling",
- "proc-macro2",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "serde_yaml"
-version = "0.8.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"
-dependencies = [
- "indexmap",
- "ryu",
- "serde",
- "yaml-rust",
-]
-
-[[package]]
-name = "serde_yaml"
-version = "0.9.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c"
-dependencies = [
- "indexmap",
- "itoa 1.0.6",
- "ryu",
- "serde",
- "unsafe-libyaml",
-]
-
-[[package]]
-name = "serialize-to-javascript"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb"
-dependencies = [
- "serde",
- "serde_json",
- "serialize-to-javascript-impl",
-]
-
-[[package]]
-name = "serialize-to-javascript-impl"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "servo_arc"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432"
-dependencies = [
- "nodrop",
- "stable_deref_trait",
-]
-
-[[package]]
-name = "sha1"
-version = "0.10.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
-dependencies = [
- "cfg-if",
- "cpufeatures",
- "digest 0.10.7",
-]
-
-[[package]]
-name = "sha2"
-version = "0.9.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
-dependencies = [
- "block-buffer 0.9.0",
- "cfg-if",
- "cpufeatures",
- "digest 0.9.0",
- "opaque-debug",
-]
-
-[[package]]
-name = "sha2"
-version = "0.10.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
-dependencies = [
- "cfg-if",
- "cpufeatures",
- "digest 0.10.7",
-]
-
-[[package]]
-name = "sharded-slab"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
-dependencies = [
- "lazy_static 1.4.0",
-]
-
-[[package]]
-name = "shared_child"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef"
-dependencies = [
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "shared_library"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11"
-dependencies = [
- "lazy_static 1.4.0",
- "libc",
-]
-
-[[package]]
-name = "signal-hook"
-version = "0.1.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729"
-dependencies = [
- "libc",
- "signal-hook-registry",
-]
-
-[[package]]
-name = "signal-hook"
-version = "0.3.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
-dependencies = [
- "libc",
- "signal-hook-registry",
-]
-
-[[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 = "simd-adler32"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f"
-
-[[package]]
-name = "siphasher"
-version = "0.3.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
-
-[[package]]
-name = "slab"
-version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "smallvec"
-version = "1.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
-
-[[package]]
-name = "smol"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1"
-dependencies = [
- "async-channel",
- "async-executor",
- "async-fs",
- "async-io",
- "async-lock",
- "async-net",
- "async-process",
- "blocking",
- "futures-lite",
-]
-
-[[package]]
-name = "socket2"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
-dependencies = [
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "soup2"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2b4d76501d8ba387cf0fefbe055c3e0a59891d09f0f995ae4e4b16f6b60f3c0"
-dependencies = [
- "bitflags",
- "gio",
- "glib",
- "libc",
- "once_cell",
- "soup2-sys",
-]
-
-[[package]]
-name = "soup2-sys"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf"
-dependencies = [
- "bitflags",
- "gio-sys",
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps 5.0.0",
-]
-
-[[package]]
-name = "spin"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
-
-[[package]]
-name = "spin"
-version = "0.9.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
-
-[[package]]
-name = "stable_deref_trait"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
-
-[[package]]
-name = "state"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b"
-dependencies = [
- "loom",
-]
-
-[[package]]
-name = "static_assertions"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
-
-[[package]]
-name = "string_cache"
-version = "0.8.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
-dependencies = [
- "new_debug_unreachable",
- "once_cell",
- "parking_lot",
- "phf_shared 0.10.0",
- "precomputed-hash",
- "serde",
-]
-
-[[package]]
-name = "string_cache_codegen"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988"
-dependencies = [
- "phf_generator 0.10.0",
- "phf_shared 0.10.0",
- "proc-macro2",
- "quote",
-]
-
-[[package]]
-name = "strsim"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
-[[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.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "sysinfo"
-version = "0.29.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02f1dc6930a439cc5d154221b5387d153f8183529b07c19aca24ea31e0a167e1"
-dependencies = [
- "cfg-if",
- "core-foundation-sys",
- "libc",
- "ntapi",
- "once_cell",
- "rayon",
- "winapi",
-]
-
-[[package]]
-name = "sysproxy"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9707a79d3b95683aa5a9521e698ffd878b8fb289727c25a69157fb85d529ffff"
-dependencies = [
- "interfaces",
- "thiserror",
- "winapi",
- "winreg 0.10.1",
-]
-
-[[package]]
-name = "system-deps"
-version = "5.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18db855554db7bd0e73e06cf7ba3df39f97812cb11d3f75e71c39bf45171797e"
-dependencies = [
- "cfg-expr 0.9.1",
- "heck 0.3.3",
- "pkg-config",
- "toml 0.5.11",
- "version-compare 0.0.11",
-]
-
-[[package]]
-name = "system-deps"
-version = "6.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5fa6fb9ee296c0dc2df41a656ca7948546d061958115ddb0bcaae43ad0d17d2"
-dependencies = [
- "cfg-expr 0.15.1",
- "heck 0.4.1",
- "pkg-config",
- "toml 0.7.4",
- "version-compare 0.1.1",
-]
-
-[[package]]
-name = "tao"
-version = "0.16.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6d198e01085564cea63e976ad1566c1ba2c2e4cc79578e35d9f05521505e31"
-dependencies = [
- "bitflags",
- "cairo-rs",
- "cc",
- "cocoa",
- "core-foundation",
- "core-graphics",
- "crossbeam-channel",
- "dirs-next",
- "dispatch",
- "gdk",
- "gdk-pixbuf",
- "gdk-sys",
- "gdkwayland-sys",
- "gdkx11-sys",
- "gio",
- "glib",
- "glib-sys",
- "gtk",
- "image",
- "instant",
- "jni",
- "lazy_static 1.4.0",
- "libappindicator",
- "libc",
- "log 0.4.17",
- "ndk",
- "ndk-context",
- "ndk-sys",
- "objc",
- "once_cell",
- "parking_lot",
- "png",
- "raw-window-handle",
- "scopeguard",
- "serde",
- "tao-macros",
- "unicode-segmentation",
- "uuid",
- "windows 0.39.0",
- "windows-implement",
- "x11-dl",
-]
-
-[[package]]
-name = "tao-macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b27a4bcc5eb524658234589bdffc7e7bfb996dbae6ce9393bfd39cb4159b445"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[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 = "target-lexicon"
-version = "0.12.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5"
-
-[[package]]
-name = "tauri"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d42ba3a2e8556722f31336a0750c10dbb6a81396a1c452977f515da83f69f842"
-dependencies = [
- "anyhow",
- "attohttpc",
- "base64 0.21.2",
- "bytes",
- "cocoa",
- "dirs-next",
- "embed_plist",
- "encoding_rs",
- "flate2",
- "futures-util",
- "glib",
- "glob",
- "gtk",
- "heck 0.4.1",
- "http",
- "ignore",
- "infer 0.9.0",
- "minisign-verify",
- "objc",
- "once_cell",
- "open 3.2.0",
- "os_pipe",
- "percent-encoding",
- "png",
- "rand 0.8.5",
- "raw-window-handle",
- "regex 1.8.3",
- "reqwest",
- "rfd",
- "semver 1.0.17",
- "serde",
- "serde_json",
- "serde_repr",
- "serialize-to-javascript",
- "shared_child",
- "state",
- "tar",
- "tauri-macros",
- "tauri-runtime",
- "tauri-runtime-wry",
- "tauri-utils",
- "tempfile",
- "thiserror",
- "time 0.3.15",
- "tokio",
- "url",
- "uuid",
- "webkit2gtk",
- "webview2-com",
- "windows 0.39.0",
- "zip",
-]
-
-[[package]]
-name = "tauri-build"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8807c85d656b2b93927c19fe5a5f1f1f348f96c2de8b90763b3c2d561511f9b4"
-dependencies = [
- "anyhow",
- "cargo_toml",
- "heck 0.4.1",
- "json-patch 0.2.7",
- "semver 1.0.17",
- "serde_json",
- "tauri-utils",
- "winres",
-]
-
-[[package]]
-name = "tauri-codegen"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5a2105f807c6f50b2fa2ce5abd62ef207bc6f14c9fcc6b8caec437f6fb13bde"
-dependencies = [
- "base64 0.21.2",
- "brotli",
- "ico",
- "json-patch 1.0.0",
- "plist",
- "png",
- "proc-macro2",
- "quote",
- "regex 1.8.3",
- "semver 1.0.17",
- "serde",
- "serde_json",
- "sha2 0.10.6",
- "tauri-utils",
- "thiserror",
- "time 0.3.15",
- "uuid",
- "walkdir",
-]
-
-[[package]]
-name = "tauri-macros"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8784cfe6f5444097e93c69107d1ac5e8f13d02850efa8d8f2a40fe79674cef46"
-dependencies = [
- "heck 0.4.1",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
- "tauri-codegen",
- "tauri-utils",
-]
-
-[[package]]
-name = "tauri-runtime"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3b80ea3fcd5fefb60739a3b577b277e8fc30434538a2f5bba82ad7d4368c422"
-dependencies = [
- "gtk",
- "http",
- "http-range",
- "rand 0.8.5",
- "raw-window-handle",
- "serde",
- "serde_json",
- "tauri-utils",
- "thiserror",
- "url",
- "uuid",
- "webview2-com",
- "windows 0.39.0",
-]
-
-[[package]]
-name = "tauri-runtime-wry"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1c396950b1ba06aee1b4ffe6c7cd305ff433ca0e30acbc5fa1a2f92a4ce70f1"
-dependencies = [
- "cocoa",
- "gtk",
- "percent-encoding",
- "rand 0.8.5",
- "raw-window-handle",
- "tauri-runtime",
- "tauri-utils",
- "uuid",
- "webkit2gtk",
- "webview2-com",
- "windows 0.39.0",
- "wry",
-]
-
-[[package]]
-name = "tauri-utils"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a6f9c2dafef5cbcf52926af57ce9561bd33bb41d7394f8bb849c0330260d864"
-dependencies = [
- "brotli",
- "ctor",
- "glob",
- "heck 0.4.1",
- "html5ever",
- "infer 0.12.0",
- "json-patch 1.0.0",
- "kuchiki",
- "memchr",
- "phf 0.10.1",
- "proc-macro2",
- "quote",
- "semver 1.0.17",
- "serde",
- "serde_json",
- "serde_with",
- "thiserror",
- "url",
- "walkdir",
- "windows 0.39.0",
-]
-
-[[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 = "tendril"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
-dependencies = [
- "futf",
- "mac",
- "utf-8",
-]
-
-[[package]]
-name = "terminfo"
-version = "0.7.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da31aef70da0f6352dbcb462683eb4dd2bfad01cf3fc96cf204547b9a839a585"
-dependencies = [
- "dirs 4.0.0",
- "fnv",
- "nom 5.1.3",
- "phf 0.11.1",
- "phf_codegen 0.11.1",
-]
-
-[[package]]
-name = "termios"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "termwiz"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31ef6892cc0348a9b3b8c377addba91e0f6365863d92354bf27559dca81ee8c5"
-dependencies = [
- "anyhow",
- "base64 0.13.1",
- "bitflags",
- "cfg-if",
- "filedescriptor",
- "hex",
- "lazy_static 1.4.0",
- "libc",
- "log 0.4.17",
- "memmem",
- "num-derive",
- "num-traits",
- "ordered-float",
- "regex 1.8.3",
- "semver 0.11.0",
- "sha2 0.9.9",
- "signal-hook 0.1.17",
- "terminfo",
- "termios",
- "thiserror",
- "ucd-trie",
- "unicode-segmentation",
- "vtparse",
- "winapi",
-]
-
-[[package]]
-name = "thin-slice"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
-
-[[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.18",
-]
-
-[[package]]
-name = "thread-id"
-version = "4.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ee93aa2b8331c0fec9091548843f2c90019571814057da3b783f9de09349d73"
-dependencies = [
- "libc",
- "redox_syscall 0.2.16",
- "winapi",
-]
-
-[[package]]
-name = "thread_local"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
-dependencies = [
- "lazy_static 1.4.0",
-]
-
-[[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.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c"
-dependencies = [
- "itoa 1.0.6",
- "libc",
- "num_threads",
- "serde",
-]
-
-[[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",
- "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.18",
-]
-
-[[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.24.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5"
-dependencies = [
- "rustls",
- "tokio",
-]
-
-[[package]]
-name = "tokio-stream"
-version = "0.1.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
-dependencies = [
- "futures-core",
- "pin-project-lite",
- "tokio",
-]
-
-[[package]]
-name = "tokio-tungstenite"
-version = "0.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd"
-dependencies = [
- "futures-util",
- "log 0.4.17",
- "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.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec"
-dependencies = [
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_edit",
-]
-
-[[package]]
-name = "toml_datetime"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "toml_edit"
-version = "0.19.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739"
-dependencies = [
- "indexmap",
- "serde",
- "serde_spanned",
- "toml_datetime",
- "winnow",
-]
-
-[[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 0.4.17",
- "pin-project-lite",
- "tracing-attributes",
- "tracing-core",
-]
-
-[[package]]
-name = "tracing-attributes"
-version = "0.1.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "tracing-core"
-version = "0.1.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
-dependencies = [
- "once_cell",
- "valuable",
-]
-
-[[package]]
-name = "tracing-log"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
-dependencies = [
- "lazy_static 1.4.0",
- "log 0.4.17",
- "tracing-core",
-]
-
-[[package]]
-name = "tracing-subscriber"
-version = "0.3.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
-dependencies = [
- "matchers",
- "nu-ansi-term",
- "once_cell",
- "regex 1.8.3",
- "sharded-slab",
- "smallvec",
- "thread_local 1.1.7",
- "tracing",
- "tracing-core",
- "tracing-log",
-]
-
-[[package]]
-name = "treediff"
-version = "3.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "761e8d5ad7ce14bb82b7e61ccc0ca961005a275a060b9644a2431aa11553c2ff"
-dependencies = [
- "serde_json",
-]
-
-[[package]]
-name = "treediff"
-version = "4.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52984d277bdf2a751072b5df30ec0377febdb02f7696d64c2d7d54630bac4303"
-dependencies = [
- "serde_json",
-]
-
-[[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.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788"
-dependencies = [
- "base64 0.13.1",
- "byteorder",
- "bytes",
- "http",
- "httparse",
- "log 0.4.17",
- "rand 0.8.5",
- "sha1",
- "thiserror",
- "url",
- "utf-8",
-]
-
-[[package]]
-name = "typemap-ors"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867"
-dependencies = [
- "unsafe-any-ors",
-]
-
-[[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 = "ucd-util"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abd2fc5d32b590614af8b0a20d837f32eca055edd0bbead59a9cfe80858be003"
-
-[[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-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 = "unsafe-any-ors"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad"
-dependencies = [
- "destructure_traitobject",
-]
-
-[[package]]
-name = "unsafe-libyaml"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6"
-
-[[package]]
-name = "untrusted"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
-
-[[package]]
-name = "url"
-version = "2.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
-dependencies = [
- "form_urlencoded",
- "idna",
- "percent-encoding",
- "serde",
-]
-
-[[package]]
-name = "utf-8"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
-
-[[package]]
-name = "utf8-ranges"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba"
-
-[[package]]
-name = "utf8parse"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
-
-[[package]]
-name = "uuid"
-version = "1.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2"
-dependencies = [
- "getrandom 0.2.9",
-]
-
-[[package]]
-name = "valuable"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
-
-[[package]]
-name = "vcpkg"
-version = "0.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
-
-[[package]]
-name = "version-compare"
-version = "0.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b"
-
-[[package]]
-name = "version-compare"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
-
-[[package]]
-name = "version_check"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-
-[[package]]
-name = "vtparse"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d9b2acfb050df409c972a37d3b8e08cdea3bddb0c09db9d53137e504cfabed0"
-dependencies = [
- "utf8parse",
-]
-
-[[package]]
-name = "waker-fn"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
-
-[[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 = "want"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
-dependencies = [
- "log 0.4.17",
- "try-lock",
-]
-
-[[package]]
-name = "warp"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba431ef570df1287f7f8b07e376491ad54f84d26ac473489427231e1718e1f69"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-util",
- "headers",
- "http",
- "hyper",
- "log 0.4.17",
- "mime",
- "mime_guess",
- "multer",
- "percent-encoding",
- "pin-project",
- "rustls-pemfile",
- "scoped-tls",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "tokio",
- "tokio-stream",
- "tokio-tungstenite",
- "tokio-util",
- "tower-service",
- "tracing",
-]
-
-[[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.86"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73"
-dependencies = [
- "cfg-if",
- "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.86"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb"
-dependencies = [
- "bumpalo",
- "log 0.4.17",
- "once_cell",
- "proc-macro2",
- "quote",
- "syn 2.0.18",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-futures"
-version = "0.4.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e"
-dependencies = [
- "cfg-if",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.86"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
-dependencies = [
- "quote",
- "wasm-bindgen-macro-support",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.86"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.18",
- "wasm-bindgen-backend",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.86"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
-
-[[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 = "web-sys"
-version = "0.3.63"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "webkit2gtk"
-version = "0.18.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8f859735e4a452aeb28c6c56a852967a8a76c8eb1cc32dbf931ad28a13d6370"
-dependencies = [
- "bitflags",
- "cairo-rs",
- "gdk",
- "gdk-sys",
- "gio",
- "gio-sys",
- "glib",
- "glib-sys",
- "gobject-sys",
- "gtk",
- "gtk-sys",
- "javascriptcore-rs",
- "libc",
- "once_cell",
- "soup2",
- "webkit2gtk-sys",
-]
-
-[[package]]
-name = "webkit2gtk-sys"
-version = "0.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d76ca6ecc47aeba01ec61e480139dda143796abcae6f83bcddf50d6b5b1dcf3"
-dependencies = [
- "atk-sys",
- "bitflags",
- "cairo-sys-rs",
- "gdk-pixbuf-sys",
- "gdk-sys",
- "gio-sys",
- "glib-sys",
- "gobject-sys",
- "gtk-sys",
- "javascriptcore-rs-sys",
- "libc",
- "pango-sys",
- "pkg-config",
- "soup2-sys",
- "system-deps 6.1.0",
-]
-
-[[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 = "webview2-com"
-version = "0.19.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4a769c9f1a64a8734bde70caafac2b96cada12cd4aefa49196b3a386b8b4178"
-dependencies = [
- "webview2-com-macros",
- "webview2-com-sys",
- "windows 0.39.0",
- "windows-implement",
-]
-
-[[package]]
-name = "webview2-com-macros"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaebe196c01691db62e9e4ca52c5ef1e4fd837dcae27dae3ada599b5a8fd05ac"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "webview2-com-sys"
-version = "0.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aac48ef20ddf657755fdcda8dfed2a7b4fc7e4581acce6fe9b88c3d64f29dee7"
-dependencies = [
- "regex 1.8.3",
- "serde",
- "serde_json",
- "thiserror",
- "windows 0.39.0",
- "windows-bindgen",
- "windows-metadata",
-]
-
-[[package]]
-name = "which"
-version = "4.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
-dependencies = [
- "either",
- "libc",
- "once_cell",
-]
-
-[[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 = "window-shadows"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29d30320647cfc3dc45554c8ad825b84831def81f967a2f7589931328ff9b16d"
-dependencies = [
- "cocoa",
- "objc",
- "raw-window-handle",
- "windows-sys 0.42.0",
-]
-
-[[package]]
-name = "window-vibrancy"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f762d9cc392fb85e6b1b5eed1ef13d73fed5149a5cbb017a7137497d14ef612"
-dependencies = [
- "cocoa",
- "objc",
- "raw-window-handle",
- "windows-sys 0.42.0",
-]
-
-[[package]]
-name = "windows"
-version = "0.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647"
-dependencies = [
- "windows_aarch64_msvc 0.37.0",
- "windows_i686_gnu 0.37.0",
- "windows_i686_msvc 0.37.0",
- "windows_x86_64_gnu 0.37.0",
- "windows_x86_64_msvc 0.37.0",
-]
-
-[[package]]
-name = "windows"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a"
-dependencies = [
- "windows-implement",
- "windows_aarch64_msvc 0.39.0",
- "windows_i686_gnu 0.39.0",
- "windows_i686_msvc 0.39.0",
- "windows_x86_64_gnu 0.39.0",
- "windows_x86_64_msvc 0.39.0",
-]
-
-[[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-bindgen"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68003dbd0e38abc0fb85b939240f4bce37c43a5981d3df37ccbaaa981b47cb41"
-dependencies = [
- "windows-metadata",
- "windows-tokens",
-]
-
-[[package]]
-name = "windows-implement"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba01f98f509cb5dc05f4e5fc95e535f78260f15fea8fe1a8abdd08f774f1cee7"
-dependencies = [
- "syn 1.0.109",
- "windows-tokens",
-]
-
-[[package]]
-name = "windows-metadata"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ee5e275231f07c6e240d14f34e1b635bf1faa1c76c57cfd59a5cdb9848e4278"
-
-[[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-tokens"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f838de2fe15fe6bac988e74b798f26499a8b21a9d97edec321e79b28d1d7f597"
-
-[[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.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2"
-
-[[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.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b"
-
-[[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.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106"
-
-[[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.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65"
-
-[[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.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809"
-
-[[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.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
-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 = "winres"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c"
-dependencies = [
- "toml 0.5.11",
-]
-
-[[package]]
-name = "wry"
-version = "0.24.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33748f35413c8a98d45f7a08832d848c0c5915501803d1faade5a4ebcd258cea"
-dependencies = [
- "base64 0.13.1",
- "block",
- "cocoa",
- "core-graphics",
- "crossbeam-channel",
- "dunce",
- "gdk",
- "gio",
- "glib",
- "gtk",
- "html5ever",
- "http",
- "kuchiki",
- "libc",
- "log 0.4.17",
- "objc",
- "objc_id",
- "once_cell",
- "serde",
- "serde_json",
- "sha2 0.10.6",
- "soup2",
- "tao",
- "thiserror",
- "url",
- "webkit2gtk",
- "webkit2gtk-sys",
- "webview2-com",
- "windows 0.39.0",
- "windows-implement",
-]
-
-[[package]]
-name = "x11"
-version = "2.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e"
-dependencies = [
- "libc",
- "pkg-config",
-]
-
-[[package]]
-name = "x11-dl"
-version = "2.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f"
-dependencies = [
- "libc",
- "once_cell",
- "pkg-config",
-]
-
-[[package]]
-name = "xattr"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "yaml-rust"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
-dependencies = [
- "linked-hash-map",
-]
-
-[[package]]
-name = "zip"
-version = "0.6.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
-dependencies = [
- "byteorder",
- "crc32fast",
- "crossbeam-utils",
-]
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
deleted file mode 100644
index 440a39859c25475bd0f007abfdba613304a5e4b7..0000000000000000000000000000000000000000
--- a/src-tauri/Cargo.toml
+++ /dev/null
@@ -1,69 +0,0 @@
-[package]
-name = "clash-verge"
-version = "0.1.0"
-description = "clash verge"
-authors = ["zzzgydi"]
-license = "GPL-3.0"
-repository = "https://github.com/zzzgydi/clash-verge.git"
-default-run = "clash-verge"
-edition = "2021"
-build = "build.rs"
-
-[build-dependencies]
-tauri-build = { version = "1", features = [] }
-
-[dependencies]
-warp = "0.3"
-which = "4.2.2"
-anyhow = "1.0"
-dirs = "5.0.0"
-open = "4.0.1"
-log = "0.4.14"
-ctrlc = "3.2.3"
-dunce = "1.0.2"
-log4rs = "1.0.0"
-nanoid = "0.4.0"
-chrono = "0.4.19"
-sysinfo = "0.29"
-sysproxy = "0.3"
-rquickjs = "0.1.7"
-serde_json = "1.0"
-serde_yaml = "0.9"
-auto-launch = "0.5"
-once_cell = "1.14.0"
-port_scanner = "0.1.5"
-delay_timer = "0.11.1"
-parking_lot = "0.12.0"
-tokio = { version = "1", features = ["full"] }
-serde = { version = "1.0", features = ["derive"] }
-reqwest = { version = "0.11", features = ["json","rustls-tls"] }
-tauri = { version = "1.2.4", features = ["global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all"] }
-window-vibrancy = { version = "0.3.0" }
-window-shadows = { version = "0.2.0" }
-wry = { version = "0.24.3" }
-
-
-[target.'cfg(windows)'.dependencies]
-runas = "1.1.0"
-deelevate = "0.2.0"
-winreg = { version = "0.50", features = ["transactions"] }
-windows-sys = { version = "0.48", features = ["Win32_System_LibraryLoader", "Win32_System_SystemInformation"] }
-
-[target.'cfg(windows)'.dependencies.tauri]
-features = ["global-shortcut-all", "icon-png", "process-all", "shell-all", "system-tray", "updater", "window-all"]
-
-[target.'cfg(linux)'.dependencies.tauri]
-features = ["global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all", "native-tls-vendored", "reqwest-native-tls-vendored"]
-
-
-[features]
-default = ["custom-protocol"]
-custom-protocol = ["tauri/custom-protocol"]
-verge-dev = []
-default-meta = []
-
-[profile.release]
-panic = "abort"
-codegen-units = 1
-lto = true
-opt-level = "s"
diff --git a/src-tauri/build.rs b/src-tauri/build.rs
deleted file mode 100644
index d860e1e6a7cac333c3cc0bc9cb67faf286b07d69..0000000000000000000000000000000000000000
--- a/src-tauri/build.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    tauri_build::build()
-}
diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png
deleted file mode 100644
index be2533a7ffd32a09b800d27e302a0f41afa74bea..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/128x128.png and /dev/null differ
diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png
deleted file mode 100644
index 324589136cb5d8b0045dbee67b71c9b3c36ea88e..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/128x128@2x.png and /dev/null differ
diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png
deleted file mode 100644
index 1a93685f9b5500e0b9ec69befceccc8481dbde32..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/32x32.png and /dev/null differ
diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png
deleted file mode 100644
index 4240ea56915d30519dc114e5c26e548fab2164ee..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/Square107x107Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png
deleted file mode 100644
index 822b49ba544624dd4dc3fb7a700a14d224421abc..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/Square142x142Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png
deleted file mode 100644
index bb7e494823681499fceb3229c9390066d7764a4b..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/Square150x150Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png
deleted file mode 100644
index 9b0ec9fa8ebc4f2452bfa50681c08bdfe5e16ec9..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/Square284x284Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png
deleted file mode 100644
index 496a662f31a32b52885b755aa0c5a891e4b7e199..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/Square30x30Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png
deleted file mode 100644
index c02df10facea2e9563ff7a7ec1462ccadf130acf..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/Square310x310Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png
deleted file mode 100644
index 8ff531dba16b1fdd9d94baebca8a0bd8122b1a65..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/Square44x44Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png
deleted file mode 100644
index 7829892e41dd0be2c20dd172013e4fa298c4688c..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/Square71x71Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square89x89Logo.png b/src-tauri/icons/Square89x89Logo.png
deleted file mode 100644
index 6b6499003b9ee10c7be467e7d7a20cd1be5e831d..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/Square89x89Logo.png and /dev/null differ
diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png
deleted file mode 100644
index 15344c6c470008d1178e9779a00812fdcb1d2658..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/StoreLogo.png and /dev/null differ
diff --git a/src-tauri/icons/icon-new.icns b/src-tauri/icons/icon-new.icns
deleted file mode 100644
index b66e74eb862032eb40c7566238480070fe9e3fe1..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/icon-new.icns and /dev/null differ
diff --git a/src-tauri/icons/icon-shrink.png b/src-tauri/icons/icon-shrink.png
deleted file mode 100644
index 5ebfa3834a36a2c36fa05ec0ba5d45a870837e19..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/icon-shrink.png and /dev/null differ
diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns
deleted file mode 100644
index 88df4a03c6afea45a20be7f8a78999a97a0cef80..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/icon.icns and /dev/null differ
diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico
deleted file mode 100644
index e406a78f26db8439871a6536024a5116e3254951..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/icon.ico and /dev/null differ
diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png
deleted file mode 100644
index cf91cf6ca09775d4c316493955646e15943d7bae..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/icon.png and /dev/null differ
diff --git a/src-tauri/icons/tray-icon.ico b/src-tauri/icons/tray-icon.ico
deleted file mode 100644
index 611c958247b71383cd10709f646a220e0c9fb919..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/tray-icon.ico and /dev/null differ
diff --git a/src-tauri/icons/tray-icon.png b/src-tauri/icons/tray-icon.png
deleted file mode 100644
index be2533a7ffd32a09b800d27e302a0f41afa74bea..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/tray-icon.png and /dev/null differ
diff --git a/src-tauri/icons/win-tray-icon-activated.png b/src-tauri/icons/win-tray-icon-activated.png
deleted file mode 100644
index 441ff02bacda059ac8df2a690746179d3e0b309b..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/win-tray-icon-activated.png and /dev/null differ
diff --git a/src-tauri/icons/win-tray-icon.png b/src-tauri/icons/win-tray-icon.png
deleted file mode 100644
index 29616c85b5cf343451974488a753d4b8addd746f..0000000000000000000000000000000000000000
Binary files a/src-tauri/icons/win-tray-icon.png and /dev/null differ
diff --git a/src-tauri/rustfmt.toml b/src-tauri/rustfmt.toml
deleted file mode 100644
index 11eda8825f2c9d0290de2ad518684dbc9c95177b..0000000000000000000000000000000000000000
--- a/src-tauri/rustfmt.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-max_width = 100
-hard_tabs = false
-tab_spaces = 4
-newline_style = "Auto"
-use_small_heuristics = "Default"
-reorder_imports = true
-reorder_modules = true
-remove_nested_parens = true
-edition = "2021"
-merge_derives = true
-use_try_shorthand = false
-use_field_init_shorthand = false
-force_explicit_abi = true
-imports_granularity = "Crate"
diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs
deleted file mode 100644
index 4b42ebe4d07460327c1ce26230c97733f9107eb2..0000000000000000000000000000000000000000
--- a/src-tauri/src/cmds.rs
+++ /dev/null
@@ -1,280 +0,0 @@
-use crate::{
-    config::*,
-    core::*,
-    feat,
-    utils::{dirs, help},
-};
-use crate::{ret_err, wrap_err};
-use anyhow::{Context, Result};
-use serde_yaml::Mapping;
-use std::collections::{HashMap, VecDeque};
-use sysproxy::Sysproxy;
-
-type CmdResult<T = ()> = Result<T, String>;
-
-#[tauri::command]
-pub fn get_profiles() -> CmdResult<IProfiles> {
-    Ok(Config::profiles().data().clone())
-}
-
-#[tauri::command]
-pub async fn enhance_profiles() -> CmdResult {
-    wrap_err!(CoreManager::global().update_config().await)?;
-    handle::Handle::refresh_clash();
-    Ok(())
-}
-
-#[tauri::command]
-pub async fn import_profile(url: String, option: Option<PrfOption>) -> CmdResult {
-    let item = wrap_err!(PrfItem::from_url(&url, None, None, option).await)?;
-    wrap_err!(Config::profiles().data().append_item(item))
-}
-
-#[tauri::command]
-pub async fn create_profile(item: PrfItem, file_data: Option<String>) -> CmdResult {
-    let item = wrap_err!(PrfItem::from(item, file_data).await)?;
-    wrap_err!(Config::profiles().data().append_item(item))
-}
-
-#[tauri::command]
-pub async fn update_profile(index: String, option: Option<PrfOption>) -> CmdResult {
-    wrap_err!(feat::update_profile(index, option).await)
-}
-
-#[tauri::command]
-pub async fn delete_profile(index: String) -> CmdResult {
-    let should_update = wrap_err!({ Config::profiles().data().delete_item(index) })?;
-    if should_update {
-        wrap_err!(CoreManager::global().update_config().await)?;
-        handle::Handle::refresh_clash();
-    }
-
-    Ok(())
-}
-
-/// 修改profiles的
-#[tauri::command]
-pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult {
-    wrap_err!({ Config::profiles().draft().patch_config(profiles) })?;
-
-    match CoreManager::global().update_config().await {
-        Ok(_) => {
-            handle::Handle::refresh_clash();
-            Config::profiles().apply();
-            wrap_err!(Config::profiles().data().save_file())?;
-            Ok(())
-        }
-        Err(err) => {
-            Config::profiles().discard();
-            log::error!(target: "app", "{err}");
-            Err(format!("{err}"))
-        }
-    }
-}
-
-/// 修改某个profile item的
-#[tauri::command]
-pub fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
-    wrap_err!(Config::profiles().data().patch_item(index, profile))?;
-    wrap_err!(timer::Timer::global().refresh())
-}
-
-#[tauri::command]
-pub fn view_profile(index: String) -> CmdResult {
-    let file = {
-        wrap_err!(Config::profiles().latest().get_item(&index))?
-            .file
-            .clone()
-            .ok_or("the file field is null")
-    }?;
-
-    let path = wrap_err!(dirs::app_profiles_dir())?.join(file);
-    if !path.exists() {
-        ret_err!("the file not found");
-    }
-
-    wrap_err!(help::open_file(path))
-}
-
-#[tauri::command]
-pub fn read_profile_file(index: String) -> CmdResult<String> {
-    let profiles = Config::profiles();
-    let profiles = profiles.latest();
-    let item = wrap_err!(profiles.get_item(&index))?;
-    let data = wrap_err!(item.read_file())?;
-    Ok(data)
-}
-
-#[tauri::command]
-pub fn save_profile_file(index: String, file_data: Option<String>) -> CmdResult {
-    if file_data.is_none() {
-        return Ok(());
-    }
-
-    let profiles = Config::profiles();
-    let profiles = profiles.latest();
-    let item = wrap_err!(profiles.get_item(&index))?;
-    wrap_err!(item.save_file(file_data.unwrap()))
-}
-
-#[tauri::command]
-pub fn get_clash_info() -> CmdResult<ClashInfo> {
-    Ok(Config::clash().latest().get_client_info())
-}
-
-#[tauri::command]
-pub fn get_runtime_config() -> CmdResult<Option<Mapping>> {
-    Ok(Config::runtime().latest().config.clone())
-}
-
-#[tauri::command]
-pub fn get_runtime_yaml() -> CmdResult<String> {
-    let runtime = Config::runtime();
-    let runtime = runtime.latest();
-    let config = runtime.config.as_ref();
-    wrap_err!(config
-        .ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
-        .and_then(
-            |config| serde_yaml::to_string(config).context("failed to convert config to yaml")
-        ))
-}
-
-#[tauri::command]
-pub fn get_runtime_exists() -> CmdResult<Vec<String>> {
-    Ok(Config::runtime().latest().exists_keys.clone())
-}
-
-#[tauri::command]
-pub fn get_runtime_logs() -> CmdResult<HashMap<String, Vec<(String, String)>>> {
-    Ok(Config::runtime().latest().chain_logs.clone())
-}
-
-#[tauri::command]
-pub async fn patch_clash_config(payload: Mapping) -> CmdResult {
-    wrap_err!(feat::patch_clash(payload).await)
-}
-
-#[tauri::command]
-pub fn get_verge_config() -> CmdResult<IVerge> {
-    Ok(Config::verge().data().clone())
-}
-
-#[tauri::command]
-pub async fn patch_verge_config(payload: IVerge) -> CmdResult {
-    wrap_err!(feat::patch_verge(payload).await)
-}
-
-#[tauri::command]
-pub async fn change_clash_core(clash_core: Option<String>) -> CmdResult {
-    wrap_err!(CoreManager::global().change_core(clash_core).await)
-}
-
-/// restart the sidecar
-#[tauri::command]
-pub async fn restart_sidecar() -> CmdResult {
-    wrap_err!(CoreManager::global().run_core().await)
-}
-
-#[tauri::command]
-pub fn grant_permission(core: String) -> CmdResult {
-    #[cfg(any(target_os = "macos", target_os = "linux"))]
-    return wrap_err!(manager::grant_permission(core));
-
-    #[cfg(not(any(target_os = "macos", target_os = "linux")))]
-    return Err("Unsupported target".into());
-}
-
-/// get the system proxy
-#[tauri::command]
-pub fn get_sys_proxy() -> CmdResult<Mapping> {
-    let current = wrap_err!(Sysproxy::get_system_proxy())?;
-
-    let mut map = Mapping::new();
-    map.insert("enable".into(), current.enable.into());
-    map.insert(
-        "server".into(),
-        format!("{}:{}", current.host, current.port).into(),
-    );
-    map.insert("bypass".into(), current.bypass.into());
-
-    Ok(map)
-}
-
-#[tauri::command]
-pub fn get_clash_logs() -> CmdResult<VecDeque<String>> {
-    Ok(logger::Logger::global().get_log())
-}
-
-#[tauri::command]
-pub fn open_app_dir() -> CmdResult<()> {
-    let app_dir = wrap_err!(dirs::app_home_dir())?;
-    wrap_err!(open::that(app_dir))
-}
-
-#[tauri::command]
-pub fn open_core_dir() -> CmdResult<()> {
-    let core_dir = wrap_err!(tauri::utils::platform::current_exe())?;
-    let core_dir = core_dir.parent().ok_or(format!("failed to get core dir"))?;
-    wrap_err!(open::that(core_dir))
-}
-
-#[tauri::command]
-pub fn open_logs_dir() -> CmdResult<()> {
-    let log_dir = wrap_err!(dirs::app_logs_dir())?;
-    wrap_err!(open::that(log_dir))
-}
-
-#[tauri::command]
-pub fn open_web_url(url: String) -> CmdResult<()> {
-    wrap_err!(open::that(url))
-}
-
-#[tauri::command]
-pub async fn clash_api_get_proxy_delay(
-    name: String,
-    url: Option<String>,
-) -> CmdResult<clash_api::DelayRes> {
-    match clash_api::get_proxy_delay(name, url).await {
-        Ok(res) => Ok(res),
-        Err(err) => Err(format!("{}", err.to_string())),
-    }
-}
-
-#[cfg(windows)]
-pub mod service {
-    use super::*;
-    use crate::core::win_service;
-
-    #[tauri::command]
-    pub async fn check_service() -> CmdResult<win_service::JsonResponse> {
-        wrap_err!(win_service::check_service().await)
-    }
-
-    #[tauri::command]
-    pub async fn install_service() -> CmdResult {
-        wrap_err!(win_service::install_service().await)
-    }
-
-    #[tauri::command]
-    pub async fn uninstall_service() -> CmdResult {
-        wrap_err!(win_service::uninstall_service().await)
-    }
-}
-
-#[cfg(not(windows))]
-pub mod service {
-    use super::*;
-
-    #[tauri::command]
-    pub async fn check_service() -> CmdResult {
-        Ok(())
-    }
-    #[tauri::command]
-    pub async fn install_service() -> CmdResult {
-        Ok(())
-    }
-    #[tauri::command]
-    pub async fn uninstall_service() -> CmdResult {
-        Ok(())
-    }
-}
diff --git a/src-tauri/src/config/clash.rs b/src-tauri/src/config/clash.rs
deleted file mode 100644
index 6a4cf5ebb0ec6e5bf2c5187558a4e20da13be20b..0000000000000000000000000000000000000000
--- a/src-tauri/src/config/clash.rs
+++ /dev/null
@@ -1,262 +0,0 @@
-use crate::utils::{dirs, help};
-use anyhow::Result;
-use serde::{Deserialize, Serialize};
-use serde_yaml::{Mapping, Value};
-use std::{
-    net::{IpAddr, Ipv4Addr, SocketAddr},
-    str::FromStr,
-};
-
-#[derive(Default, Debug, Clone)]
-pub struct IClashTemp(pub Mapping);
-
-impl IClashTemp {
-    pub fn new() -> Self {
-        match dirs::clash_path().and_then(|path| help::read_merge_mapping(&path)) {
-            Ok(map) => Self(Self::guard(map)),
-            Err(err) => {
-                log::error!(target: "app", "{err}");
-                Self::template()
-            }
-        }
-    }
-
-    pub fn template() -> Self {
-        let mut map = Mapping::new();
-
-        map.insert(
-            "mixed-port".into(),
-            match cfg!(feature = "default-meta") {
-                false => 7890.into(),
-                true => 7898.into(),
-            },
-        );
-        map.insert("log-level".into(), "info".into());
-        map.insert("allow-lan".into(), false.into());
-        map.insert("mode".into(), "rule".into());
-        map.insert(
-            "external-controller".into(),
-            match cfg!(feature = "default-meta") {
-                false => "127.0.0.1:9090".into(),
-                true => "127.0.0.1:9098".into(),
-            },
-        );
-        map.insert("secret".into(), "".into());
-
-        Self(map)
-    }
-
-    fn guard(mut config: Mapping) -> Mapping {
-        let port = Self::guard_mixed_port(&config);
-        let ctrl = Self::guard_server_ctrl(&config);
-
-        config.insert("mixed-port".into(), port.into());
-        config.insert("external-controller".into(), ctrl.into());
-        config
-    }
-
-    pub fn patch_config(&mut self, patch: Mapping) {
-        for (key, value) in patch.into_iter() {
-            self.0.insert(key, value);
-        }
-    }
-
-    pub fn save_config(&self) -> Result<()> {
-        help::save_yaml(
-            &dirs::clash_path()?,
-            &self.0,
-            Some("# Generated by Clash Verge"),
-        )
-    }
-
-    pub fn get_mixed_port(&self) -> u16 {
-        Self::guard_mixed_port(&self.0)
-    }
-
-    pub fn get_client_info(&self) -> ClashInfo {
-        let config = &self.0;
-
-        ClashInfo {
-            port: Self::guard_mixed_port(&config),
-            server: Self::guard_client_ctrl(&config),
-            secret: config.get("secret").and_then(|value| match value {
-                Value::String(val_str) => Some(val_str.clone()),
-                Value::Bool(val_bool) => Some(val_bool.to_string()),
-                Value::Number(val_num) => Some(val_num.to_string()),
-                _ => None,
-            }),
-        }
-    }
-
-    pub fn guard_mixed_port(config: &Mapping) -> u16 {
-        let mut port = config
-            .get("mixed-port")
-            .and_then(|value| match value {
-                Value::String(val_str) => val_str.parse().ok(),
-                Value::Number(val_num) => val_num.as_u64().map(|u| u as u16),
-                _ => None,
-            })
-            .unwrap_or(7890);
-        if port == 0 {
-            port = 7890;
-        }
-        port
-    }
-
-    pub fn guard_server_ctrl(config: &Mapping) -> String {
-        config
-            .get("external-controller")
-            .and_then(|value| match value.as_str() {
-                Some(val_str) => {
-                    let val_str = val_str.trim();
-
-                    let val = match val_str.starts_with(":") {
-                        true => format!("127.0.0.1{val_str}"),
-                        false => val_str.to_owned(),
-                    };
-
-                    SocketAddr::from_str(val.as_str())
-                        .ok()
-                        .map(|s| s.to_string())
-                }
-                None => None,
-            })
-            .unwrap_or("127.0.0.1:9090".into())
-    }
-
-    pub fn guard_client_ctrl(config: &Mapping) -> String {
-        let value = Self::guard_server_ctrl(config);
-        match SocketAddr::from_str(value.as_str()) {
-            Ok(mut socket) => {
-                if socket.ip().is_unspecified() {
-                    socket.set_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
-                }
-                socket.to_string()
-            }
-            Err(_) => "127.0.0.1:9090".into(),
-        }
-    }
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-pub struct ClashInfo {
-    /// clash core port
-    pub port: u16,
-    /// same as `external-controller`
-    pub server: String,
-    /// clash secret
-    pub secret: Option<String>,
-}
-
-#[test]
-fn test_clash_info() {
-    fn get_case<T: Into<Value>, D: Into<Value>>(mp: T, ec: D) -> ClashInfo {
-        let mut map = Mapping::new();
-        map.insert("mixed-port".into(), mp.into());
-        map.insert("external-controller".into(), ec.into());
-
-        IClashTemp(IClashTemp::guard(map)).get_client_info()
-    }
-
-    fn get_result<S: Into<String>>(port: u16, server: S) -> ClashInfo {
-        ClashInfo {
-            port,
-            server: server.into(),
-            secret: None,
-        }
-    }
-
-    assert_eq!(
-        IClashTemp(IClashTemp::guard(Mapping::new())).get_client_info(),
-        get_result(7890, "127.0.0.1:9090")
-    );
-
-    assert_eq!(get_case("", ""), get_result(7890, "127.0.0.1:9090"));
-
-    assert_eq!(get_case(65537, ""), get_result(1, "127.0.0.1:9090"));
-
-    assert_eq!(
-        get_case(8888, "127.0.0.1:8888"),
-        get_result(8888, "127.0.0.1:8888")
-    );
-
-    assert_eq!(
-        get_case(8888, "   :98888 "),
-        get_result(8888, "127.0.0.1:9090")
-    );
-
-    assert_eq!(
-        get_case(8888, "0.0.0.0:8080  "),
-        get_result(8888, "127.0.0.1:8080")
-    );
-
-    assert_eq!(
-        get_case(8888, "0.0.0.0:8080"),
-        get_result(8888, "127.0.0.1:8080")
-    );
-
-    assert_eq!(
-        get_case(8888, "[::]:8080"),
-        get_result(8888, "127.0.0.1:8080")
-    );
-
-    assert_eq!(
-        get_case(8888, "192.168.1.1:8080"),
-        get_result(8888, "192.168.1.1:8080")
-    );
-
-    assert_eq!(
-        get_case(8888, "192.168.1.1:80800"),
-        get_result(8888, "127.0.0.1:9090")
-    );
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct IClash {
-    pub mixed_port: Option<u16>,
-    pub allow_lan: Option<bool>,
-    pub log_level: Option<String>,
-    pub ipv6: Option<bool>,
-    pub mode: Option<String>,
-    pub external_controller: Option<String>,
-    pub secret: Option<String>,
-    pub dns: Option<IClashDNS>,
-    pub tun: Option<IClashTUN>,
-    pub interface_name: Option<String>,
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct IClashTUN {
-    pub enable: Option<bool>,
-    pub stack: Option<String>,
-    pub auto_route: Option<bool>,
-    pub auto_detect_interface: Option<bool>,
-    pub dns_hijack: Option<Vec<String>>,
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct IClashDNS {
-    pub enable: Option<bool>,
-    pub listen: Option<String>,
-    pub default_nameserver: Option<Vec<String>>,
-    pub enhanced_mode: Option<String>,
-    pub fake_ip_range: Option<String>,
-    pub use_hosts: Option<bool>,
-    pub fake_ip_filter: Option<Vec<String>>,
-    pub nameserver: Option<Vec<String>>,
-    pub fallback: Option<Vec<String>>,
-    pub fallback_filter: Option<IClashFallbackFilter>,
-    pub nameserver_policy: Option<Vec<String>>,
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct IClashFallbackFilter {
-    pub geoip: Option<bool>,
-    pub geoip_code: Option<String>,
-    pub ipcidr: Option<Vec<String>>,
-    pub domain: Option<Vec<String>>,
-}
diff --git a/src-tauri/src/config/config.rs b/src-tauri/src/config/config.rs
deleted file mode 100644
index e5af8e591f30c8c3b07c5ebf39b2013308347506..0000000000000000000000000000000000000000
--- a/src-tauri/src/config/config.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-use super::{Draft, IClashTemp, IProfiles, IRuntime, IVerge};
-use crate::{
-    enhance,
-    utils::{dirs, help},
-};
-use anyhow::{anyhow, Result};
-use once_cell::sync::OnceCell;
-use std::{env::temp_dir, path::PathBuf};
-
-pub const RUNTIME_CONFIG: &str = "clash-verge.yaml";
-pub const CHECK_CONFIG: &str = "clash-verge-check.yaml";
-
-pub struct Config {
-    clash_config: Draft<IClashTemp>,
-    verge_config: Draft<IVerge>,
-    profiles_config: Draft<IProfiles>,
-    runtime_config: Draft<IRuntime>,
-}
-
-impl Config {
-    pub fn global() -> &'static Config {
-        static CONFIG: OnceCell<Config> = OnceCell::new();
-
-        CONFIG.get_or_init(|| Config {
-            clash_config: Draft::from(IClashTemp::new()),
-            verge_config: Draft::from(IVerge::new()),
-            profiles_config: Draft::from(IProfiles::new()),
-            runtime_config: Draft::from(IRuntime::new()),
-        })
-    }
-
-    pub fn clash() -> Draft<IClashTemp> {
-        Self::global().clash_config.clone()
-    }
-
-    pub fn verge() -> Draft<IVerge> {
-        Self::global().verge_config.clone()
-    }
-
-    pub fn profiles() -> Draft<IProfiles> {
-        Self::global().profiles_config.clone()
-    }
-
-    pub fn runtime() -> Draft<IRuntime> {
-        Self::global().runtime_config.clone()
-    }
-
-    /// 初始化配置
-    pub fn init_config() -> Result<()> {
-        crate::log_err!(Self::generate());
-        if let Err(err) = Self::generate_file(ConfigType::Run) {
-            log::error!(target: "app", "{err}");
-
-            let runtime_path = dirs::app_home_dir()?.join(RUNTIME_CONFIG);
-            // 如果不存在就将默认的clash文件拿过来
-            if !runtime_path.exists() {
-                help::save_yaml(
-                    &runtime_path,
-                    &Config::clash().latest().0,
-                    Some("# Clash Verge Runtime"),
-                )?;
-            }
-        }
-        Ok(())
-    }
-
-    /// 将配置丢到对应的文件中
-    pub fn generate_file(typ: ConfigType) -> Result<PathBuf> {
-        let path = match typ {
-            ConfigType::Run => dirs::app_home_dir()?.join(RUNTIME_CONFIG),
-            ConfigType::Check => temp_dir().join(CHECK_CONFIG),
-        };
-
-        let runtime = Config::runtime();
-        let runtime = runtime.latest();
-        let config = runtime
-            .config
-            .as_ref()
-            .ok_or(anyhow!("failed to get runtime config"))?;
-
-        help::save_yaml(&path, &config, Some("# Generated by Clash Verge"))?;
-        Ok(path)
-    }
-
-    /// 生成配置存好
-    pub fn generate() -> Result<()> {
-        let (config, exists_keys, logs) = enhance::enhance();
-
-        *Config::runtime().draft() = IRuntime {
-            config: Some(config),
-            exists_keys,
-            chain_logs: logs,
-        };
-
-        Ok(())
-    }
-}
-
-#[derive(Debug)]
-pub enum ConfigType {
-    Run,
-    Check,
-}
diff --git a/src-tauri/src/config/draft.rs b/src-tauri/src/config/draft.rs
deleted file mode 100644
index 5876f1bbbb2a571a9a503766926a087ff732c814..0000000000000000000000000000000000000000
--- a/src-tauri/src/config/draft.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-use super::{IClashTemp, IProfiles, IRuntime, IVerge};
-use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
-use std::sync::Arc;
-
-#[derive(Debug, Clone)]
-pub struct Draft<T: Clone + ToOwned> {
-    inner: Arc<Mutex<(T, Option<T>)>>,
-}
-
-macro_rules! draft_define {
-    ($id: ident) => {
-        impl Draft<$id> {
-            #[allow(unused)]
-            pub fn data(&self) -> MappedMutexGuard<$id> {
-                MutexGuard::map(self.inner.lock(), |guard| &mut guard.0)
-            }
-
-            pub fn latest(&self) -> MappedMutexGuard<$id> {
-                MutexGuard::map(self.inner.lock(), |inner| {
-                    if inner.1.is_none() {
-                        &mut inner.0
-                    } else {
-                        inner.1.as_mut().unwrap()
-                    }
-                })
-            }
-
-            pub fn draft(&self) -> MappedMutexGuard<$id> {
-                MutexGuard::map(self.inner.lock(), |inner| {
-                    if inner.1.is_none() {
-                        inner.1 = Some(inner.0.clone());
-                    }
-
-                    inner.1.as_mut().unwrap()
-                })
-            }
-
-            pub fn apply(&self) -> Option<$id> {
-                let mut inner = self.inner.lock();
-
-                match inner.1.take() {
-                    Some(draft) => {
-                        let old_value = inner.0.to_owned();
-                        inner.0 = draft.to_owned();
-                        Some(old_value)
-                    }
-                    None => None,
-                }
-            }
-
-            pub fn discard(&self) -> Option<$id> {
-                let mut inner = self.inner.lock();
-                inner.1.take()
-            }
-        }
-
-        impl From<$id> for Draft<$id> {
-            fn from(data: $id) -> Self {
-                Draft {
-                    inner: Arc::new(Mutex::new((data, None))),
-                }
-            }
-        }
-    };
-}
-
-// draft_define!(IClash);
-draft_define!(IClashTemp);
-draft_define!(IProfiles);
-draft_define!(IRuntime);
-draft_define!(IVerge);
-
-#[test]
-fn test_draft() {
-    let verge = IVerge {
-        enable_auto_launch: Some(true),
-        enable_tun_mode: Some(false),
-        ..IVerge::default()
-    };
-
-    let draft = Draft::from(verge);
-
-    assert_eq!(draft.data().enable_auto_launch, Some(true));
-    assert_eq!(draft.data().enable_tun_mode, Some(false));
-
-    assert_eq!(draft.draft().enable_auto_launch, Some(true));
-    assert_eq!(draft.draft().enable_tun_mode, Some(false));
-
-    let mut d = draft.draft();
-    d.enable_auto_launch = Some(false);
-    d.enable_tun_mode = Some(true);
-    drop(d);
-
-    assert_eq!(draft.data().enable_auto_launch, Some(true));
-    assert_eq!(draft.data().enable_tun_mode, Some(false));
-
-    assert_eq!(draft.draft().enable_auto_launch, Some(false));
-    assert_eq!(draft.draft().enable_tun_mode, Some(true));
-
-    assert_eq!(draft.latest().enable_auto_launch, Some(false));
-    assert_eq!(draft.latest().enable_tun_mode, Some(true));
-
-    assert!(draft.apply().is_some());
-    assert!(draft.apply().is_none());
-
-    assert_eq!(draft.data().enable_auto_launch, Some(false));
-    assert_eq!(draft.data().enable_tun_mode, Some(true));
-
-    assert_eq!(draft.draft().enable_auto_launch, Some(false));
-    assert_eq!(draft.draft().enable_tun_mode, Some(true));
-
-    let mut d = draft.draft();
-    d.enable_auto_launch = Some(true);
-    drop(d);
-
-    assert_eq!(draft.data().enable_auto_launch, Some(false));
-
-    assert_eq!(draft.draft().enable_auto_launch, Some(true));
-
-    assert!(draft.discard().is_some());
-
-    assert_eq!(draft.data().enable_auto_launch, Some(false));
-
-    assert!(draft.discard().is_none());
-
-    assert_eq!(draft.draft().enable_auto_launch, Some(false));
-}
diff --git a/src-tauri/src/config/mod.rs b/src-tauri/src/config/mod.rs
deleted file mode 100644
index b246a760454507eb9c44ede6f80cac0b7c0adfc9..0000000000000000000000000000000000000000
--- a/src-tauri/src/config/mod.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-mod clash;
-mod config;
-mod draft;
-mod prfitem;
-mod profiles;
-mod runtime;
-mod verge;
-
-pub use self::clash::*;
-pub use self::config::*;
-pub use self::draft::*;
-pub use self::prfitem::*;
-pub use self::profiles::*;
-pub use self::runtime::*;
-pub use self::verge::*;
diff --git a/src-tauri/src/config/prfitem.rs b/src-tauri/src/config/prfitem.rs
deleted file mode 100644
index 1e1d4a8eccadbc8a522301c9ee890bb89b2f0ffe..0000000000000000000000000000000000000000
--- a/src-tauri/src/config/prfitem.rs
+++ /dev/null
@@ -1,374 +0,0 @@
-use crate::utils::{dirs, help, tmpl};
-use anyhow::{bail, Context, Result};
-use reqwest::StatusCode;
-use serde::{Deserialize, Serialize};
-use serde_yaml::Mapping;
-use std::fs;
-use sysproxy::Sysproxy;
-
-use super::Config;
-
-#[derive(Debug, Clone, Deserialize, Serialize)]
-pub struct PrfItem {
-    pub uid: Option<String>,
-
-    /// profile item type
-    /// enum value: remote | local | script | merge
-    #[serde(rename = "type")]
-    pub itype: Option<String>,
-
-    /// profile name
-    pub name: Option<String>,
-
-    /// profile file
-    pub file: Option<String>,
-
-    /// profile description
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub desc: Option<String>,
-
-    /// source url
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub url: Option<String>,
-
-    /// selected information
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub selected: Option<Vec<PrfSelected>>,
-
-    /// subscription user info
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub extra: Option<PrfExtra>,
-
-    /// updated time
-    pub updated: Option<usize>,
-
-    /// some options of the item
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub option: Option<PrfOption>,
-
-    /// the file data
-    #[serde(skip)]
-    pub file_data: Option<String>,
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize)]
-pub struct PrfSelected {
-    pub name: Option<String>,
-    pub now: Option<String>,
-}
-
-#[derive(Default, Debug, Clone, Copy, Deserialize, Serialize)]
-pub struct PrfExtra {
-    pub upload: usize,
-    pub download: usize,
-    pub total: usize,
-    pub expire: usize,
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-pub struct PrfOption {
-    /// for `remote` profile's http request
-    /// see issue #13
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub user_agent: Option<String>,
-
-    /// for `remote` profile
-    /// use system proxy
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub with_proxy: Option<bool>,
-
-    /// for `remote` profile
-    /// use self proxy
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub self_proxy: Option<bool>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub update_interval: Option<u64>,
-}
-
-impl PrfOption {
-    pub fn merge(one: Option<Self>, other: Option<Self>) -> Option<Self> {
-        match (one, other) {
-            (Some(mut a), Some(b)) => {
-                a.user_agent = b.user_agent.or(a.user_agent);
-                a.with_proxy = b.with_proxy.or(a.with_proxy);
-                a.self_proxy = b.self_proxy.or(a.self_proxy);
-                a.update_interval = b.update_interval.or(a.update_interval);
-                Some(a)
-            }
-            t @ _ => t.0.or(t.1),
-        }
-    }
-}
-
-impl Default for PrfItem {
-    fn default() -> Self {
-        PrfItem {
-            uid: None,
-            itype: None,
-            name: None,
-            desc: None,
-            file: None,
-            url: None,
-            selected: None,
-            extra: None,
-            updated: None,
-            option: None,
-            file_data: None,
-        }
-    }
-}
-
-impl PrfItem {
-    /// From partial item
-    /// must contain `itype`
-    pub async fn from(item: PrfItem, file_data: Option<String>) -> Result<PrfItem> {
-        if item.itype.is_none() {
-            bail!("type should not be null");
-        }
-
-        match item.itype.unwrap().as_str() {
-            "remote" => {
-                if item.url.is_none() {
-                    bail!("url should not be null");
-                }
-                let url = item.url.as_ref().unwrap().as_str();
-                let name = item.name;
-                let desc = item.desc;
-                PrfItem::from_url(url, name, desc, item.option).await
-            }
-            "local" => {
-                let name = item.name.unwrap_or("Local File".into());
-                let desc = item.desc.unwrap_or("".into());
-                PrfItem::from_local(name, desc, file_data)
-            }
-            "merge" => {
-                let name = item.name.unwrap_or("Merge".into());
-                let desc = item.desc.unwrap_or("".into());
-                PrfItem::from_merge(name, desc)
-            }
-            "script" => {
-                let name = item.name.unwrap_or("Script".into());
-                let desc = item.desc.unwrap_or("".into());
-                PrfItem::from_script(name, desc)
-            }
-            typ @ _ => bail!("invalid profile item type \"{typ}\""),
-        }
-    }
-
-    /// ## Local type
-    /// create a new item from name/desc
-    pub fn from_local(name: String, desc: String, file_data: Option<String>) -> Result<PrfItem> {
-        let uid = help::get_uid("l");
-        let file = format!("{uid}.yaml");
-
-        Ok(PrfItem {
-            uid: Some(uid),
-            itype: Some("local".into()),
-            name: Some(name),
-            desc: Some(desc),
-            file: Some(file),
-            url: None,
-            selected: None,
-            extra: None,
-            option: None,
-            updated: Some(chrono::Local::now().timestamp() as usize),
-            file_data: Some(file_data.unwrap_or(tmpl::ITEM_LOCAL.into())),
-        })
-    }
-
-    /// ## Remote type
-    /// create a new item from url
-    pub async fn from_url(
-        url: &str,
-        name: Option<String>,
-        desc: Option<String>,
-        option: Option<PrfOption>,
-    ) -> Result<PrfItem> {
-        let opt_ref = option.as_ref();
-        let with_proxy = opt_ref.map_or(false, |o| o.with_proxy.unwrap_or(false));
-        let self_proxy = opt_ref.map_or(false, |o| o.self_proxy.unwrap_or(false));
-        let user_agent = opt_ref.map_or(None, |o| o.user_agent.clone());
-
-        let mut builder = reqwest::ClientBuilder::new().use_rustls_tls().no_proxy();
-
-        // 使用软件自己的代理
-        if self_proxy {
-            let port = Config::clash().data().get_mixed_port();
-
-            let proxy_scheme = format!("http://127.0.0.1:{port}");
-
-            if let Ok(proxy) = reqwest::Proxy::http(&proxy_scheme) {
-                builder = builder.proxy(proxy);
-            }
-            if let Ok(proxy) = reqwest::Proxy::https(&proxy_scheme) {
-                builder = builder.proxy(proxy);
-            }
-            if let Ok(proxy) = reqwest::Proxy::all(&proxy_scheme) {
-                builder = builder.proxy(proxy);
-            }
-        }
-        // 使用系统代理
-        else if with_proxy {
-            match Sysproxy::get_system_proxy() {
-                Ok(p @ Sysproxy { enable: true, .. }) => {
-                    let proxy_scheme = format!("http://{}:{}", p.host, p.port);
-
-                    if let Ok(proxy) = reqwest::Proxy::http(&proxy_scheme) {
-                        builder = builder.proxy(proxy);
-                    }
-                    if let Ok(proxy) = reqwest::Proxy::https(&proxy_scheme) {
-                        builder = builder.proxy(proxy);
-                    }
-                    if let Ok(proxy) = reqwest::Proxy::all(&proxy_scheme) {
-                        builder = builder.proxy(proxy);
-                    }
-                }
-                _ => {}
-            };
-        }
-
-        let version = unsafe { dirs::APP_VERSION };
-        let version = format!("clash-verge/{version}");
-        builder = builder.user_agent(user_agent.unwrap_or(version));
-
-        let resp = builder.build()?.get(url).send().await?;
-
-        let status_code = resp.status();
-        if !StatusCode::is_success(&status_code) {
-            bail!("failed to fetch remote profile with status {status_code}")
-        }
-
-        let header = resp.headers();
-
-        // parse the Subscription UserInfo
-        let extra = match header.get("Subscription-Userinfo") {
-            Some(value) => {
-                let sub_info = value.to_str().unwrap_or("");
-
-                Some(PrfExtra {
-                    upload: help::parse_str(sub_info, "upload=").unwrap_or(0),
-                    download: help::parse_str(sub_info, "download=").unwrap_or(0),
-                    total: help::parse_str(sub_info, "total=").unwrap_or(0),
-                    expire: help::parse_str(sub_info, "expire=").unwrap_or(0),
-                })
-            }
-            None => None,
-        };
-
-        // parse the Content-Disposition
-        let filename = match header.get("Content-Disposition") {
-            Some(value) => {
-                let filename = value.to_str().unwrap_or("");
-                help::parse_str::<String>(filename, "filename=")
-            }
-            None => None,
-        };
-
-        // parse the profile-update-interval
-        let option = match header.get("profile-update-interval") {
-            Some(value) => match value.to_str().unwrap_or("").parse::<u64>() {
-                Ok(val) => Some(PrfOption {
-                    update_interval: Some(val * 60), // hour -> min
-                    ..PrfOption::default()
-                }),
-                Err(_) => None,
-            },
-            None => None,
-        };
-
-        let uid = help::get_uid("r");
-        let file = format!("{uid}.yaml");
-        let name = name.unwrap_or(filename.unwrap_or("Remote File".into()));
-        let data = resp.text_with_charset("utf-8").await?;
-
-        // process the charset "UTF-8 with BOM"
-        let data = data.trim_start_matches('\u{feff}');
-
-        // check the data whether the valid yaml format
-        let yaml = serde_yaml::from_str::<Mapping>(data)
-            .context("the remote profile data is invalid yaml")?;
-
-        if !yaml.contains_key("proxies") && !yaml.contains_key("proxy-providers") {
-            bail!("profile does not contain `proxies` or `proxy-providers`");
-        }
-
-        Ok(PrfItem {
-            uid: Some(uid),
-            itype: Some("remote".into()),
-            name: Some(name),
-            desc,
-            file: Some(file),
-            url: Some(url.into()),
-            selected: None,
-            extra,
-            option,
-            updated: Some(chrono::Local::now().timestamp() as usize),
-            file_data: Some(data.into()),
-        })
-    }
-
-    /// ## Merge type (enhance)
-    /// create the enhanced item by using `merge` rule
-    pub fn from_merge(name: String, desc: String) -> Result<PrfItem> {
-        let uid = help::get_uid("m");
-        let file = format!("{uid}.yaml");
-
-        Ok(PrfItem {
-            uid: Some(uid),
-            itype: Some("merge".into()),
-            name: Some(name),
-            desc: Some(desc),
-            file: Some(file),
-            url: None,
-            selected: None,
-            extra: None,
-            option: None,
-            updated: Some(chrono::Local::now().timestamp() as usize),
-            file_data: Some(tmpl::ITEM_MERGE.into()),
-        })
-    }
-
-    /// ## Script type (enhance)
-    /// create the enhanced item by using javascript quick.js
-    pub fn from_script(name: String, desc: String) -> Result<PrfItem> {
-        let uid = help::get_uid("s");
-        let file = format!("{uid}.js"); // js ext
-
-        Ok(PrfItem {
-            uid: Some(uid),
-            itype: Some("script".into()),
-            name: Some(name),
-            desc: Some(desc),
-            file: Some(file),
-            url: None,
-            selected: None,
-            extra: None,
-            option: None,
-            updated: Some(chrono::Local::now().timestamp() as usize),
-            file_data: Some(tmpl::ITEM_SCRIPT.into()),
-        })
-    }
-
-    /// get the file data
-    pub fn read_file(&self) -> Result<String> {
-        if self.file.is_none() {
-            bail!("could not find the file");
-        }
-
-        let file = self.file.clone().unwrap();
-        let path = dirs::app_profiles_dir()?.join(file);
-        fs::read_to_string(path).context("failed to read the file")
-    }
-
-    /// save the file data
-    pub fn save_file(&self, data: String) -> Result<()> {
-        if self.file.is_none() {
-            bail!("could not find the file");
-        }
-
-        let file = self.file.clone().unwrap();
-        let path = dirs::app_profiles_dir()?.join(file);
-        fs::write(path, data.as_bytes()).context("failed to save the file")
-    }
-}
diff --git a/src-tauri/src/config/profiles.rs b/src-tauri/src/config/profiles.rs
deleted file mode 100644
index 788386ab52526bea78009318f1c95fdd755f8c93..0000000000000000000000000000000000000000
--- a/src-tauri/src/config/profiles.rs
+++ /dev/null
@@ -1,280 +0,0 @@
-use super::prfitem::PrfItem;
-use crate::utils::{dirs, help};
-use anyhow::{bail, Context, Result};
-use serde::{Deserialize, Serialize};
-use serde_yaml::Mapping;
-use std::{fs, io::Write};
-
-/// Define the `profiles.yaml` schema
-#[derive(Default, Debug, Clone, Deserialize, Serialize)]
-pub struct IProfiles {
-    /// same as PrfConfig.current
-    pub current: Option<String>,
-
-    /// same as PrfConfig.chain
-    pub chain: Option<Vec<String>>,
-
-    /// record valid fields for clash
-    pub valid: Option<Vec<String>>,
-
-    /// profile list
-    pub items: Option<Vec<PrfItem>>,
-}
-
-macro_rules! patch {
-    ($lv: expr, $rv: expr, $key: tt) => {
-        if ($rv.$key).is_some() {
-            $lv.$key = $rv.$key;
-        }
-    };
-}
-
-impl IProfiles {
-    pub fn new() -> Self {
-        match dirs::profiles_path().and_then(|path| help::read_yaml::<Self>(&path)) {
-            Ok(mut profiles) => {
-                if profiles.items.is_none() {
-                    profiles.items = Some(vec![]);
-                }
-                // compatible with the old old old version
-                profiles.items.as_mut().map(|items| {
-                    for item in items.iter_mut() {
-                        if item.uid.is_none() {
-                            item.uid = Some(help::get_uid("d"));
-                        }
-                    }
-                });
-                profiles
-            }
-            Err(err) => {
-                log::error!(target: "app", "{err}");
-                Self::template()
-            }
-        }
-    }
-
-    pub fn template() -> Self {
-        Self {
-            valid: Some(vec!["dns".into(), "sub-rules".into(), "unified-delay".into()]),
-            items: Some(vec![]),
-            ..Self::default()
-        }
-    }
-
-    pub fn save_file(&self) -> Result<()> {
-        help::save_yaml(
-            &dirs::profiles_path()?,
-            self,
-            Some("# Profiles Config for Clash Verge"),
-        )
-    }
-
-    /// 只修改current,valid和chain
-    pub fn patch_config(&mut self, patch: IProfiles) -> Result<()> {
-        if self.items.is_none() {
-            self.items = Some(vec![]);
-        }
-
-        if let Some(current) = patch.current {
-            let items = self.items.as_ref().unwrap();
-            let some_uid = Some(current);
-
-            if items.iter().any(|e| e.uid == some_uid) {
-                self.current = some_uid;
-            }
-        }
-
-        if let Some(chain) = patch.chain {
-            self.chain = Some(chain);
-        }
-
-        if let Some(valid) = patch.valid {
-            self.valid = Some(valid);
-        }
-
-        Ok(())
-    }
-
-    pub fn get_current(&self) -> Option<String> {
-        self.current.clone()
-    }
-
-    /// get items ref
-    pub fn get_items(&self) -> Option<&Vec<PrfItem>> {
-        self.items.as_ref()
-    }
-
-    /// find the item by the uid
-    pub fn get_item(&self, uid: &String) -> Result<&PrfItem> {
-        if let Some(items) = self.items.as_ref() {
-            let some_uid = Some(uid.clone());
-
-            for each in items.iter() {
-                if each.uid == some_uid {
-                    return Ok(each);
-                }
-            }
-        }
-
-        bail!("failed to get the profile item \"uid:{uid}\"");
-    }
-
-    /// append new item
-    /// if the file_data is some
-    /// then should save the data to file
-    pub fn append_item(&mut self, mut item: PrfItem) -> Result<()> {
-        if item.uid.is_none() {
-            bail!("the uid should not be null");
-        }
-
-        // save the file data
-        // move the field value after save
-        if let Some(file_data) = item.file_data.take() {
-            if item.file.is_none() {
-                bail!("the file should not be null");
-            }
-
-            let file = item.file.clone().unwrap();
-            let path = dirs::app_profiles_dir()?.join(&file);
-
-            fs::File::create(path)
-                .with_context(|| format!("failed to create file \"{}\"", file))?
-                .write(file_data.as_bytes())
-                .with_context(|| format!("failed to write to file \"{}\"", file))?;
-        }
-
-        if self.items.is_none() {
-            self.items = Some(vec![]);
-        }
-
-        self.items.as_mut().map(|items| items.push(item));
-        self.save_file()
-    }
-
-    /// update the item value
-    pub fn patch_item(&mut self, uid: String, item: PrfItem) -> Result<()> {
-        let mut items = self.items.take().unwrap_or(vec![]);
-
-        for each in items.iter_mut() {
-            if each.uid == Some(uid.clone()) {
-                patch!(each, item, itype);
-                patch!(each, item, name);
-                patch!(each, item, desc);
-                patch!(each, item, file);
-                patch!(each, item, url);
-                patch!(each, item, selected);
-                patch!(each, item, extra);
-                patch!(each, item, updated);
-                patch!(each, item, option);
-
-                self.items = Some(items);
-                return self.save_file();
-            }
-        }
-
-        self.items = Some(items);
-        bail!("failed to find the profile item \"uid:{uid}\"")
-    }
-
-    /// be used to update the remote item
-    /// only patch `updated` `extra` `file_data`
-    pub fn update_item(&mut self, uid: String, mut item: PrfItem) -> Result<()> {
-        if self.items.is_none() {
-            self.items = Some(vec![]);
-        }
-
-        // find the item
-        let _ = self.get_item(&uid)?;
-
-        if let Some(items) = self.items.as_mut() {
-            let some_uid = Some(uid.clone());
-
-            for each in items.iter_mut() {
-                if each.uid == some_uid {
-                    each.extra = item.extra;
-                    each.updated = item.updated;
-
-                    // save the file data
-                    // move the field value after save
-                    if let Some(file_data) = item.file_data.take() {
-                        let file = each.file.take();
-                        let file =
-                            file.unwrap_or(item.file.take().unwrap_or(format!("{}.yaml", &uid)));
-
-                        // the file must exists
-                        each.file = Some(file.clone());
-
-                        let path = dirs::app_profiles_dir()?.join(&file);
-
-                        fs::File::create(path)
-                            .with_context(|| format!("failed to create file \"{}\"", file))?
-                            .write(file_data.as_bytes())
-                            .with_context(|| format!("failed to write to file \"{}\"", file))?;
-                    }
-
-                    break;
-                }
-            }
-        }
-
-        self.save_file()
-    }
-
-    /// delete item
-    /// if delete the current then return true
-    pub fn delete_item(&mut self, uid: String) -> Result<bool> {
-        let current = self.current.as_ref().unwrap_or(&uid);
-        let current = current.clone();
-
-        let mut items = self.items.take().unwrap_or(vec![]);
-        let mut index = None;
-
-        // get the index
-        for i in 0..items.len() {
-            if items[i].uid == Some(uid.clone()) {
-                index = Some(i);
-                break;
-            }
-        }
-
-        if let Some(index) = index {
-            items.remove(index).file.map(|file| {
-                let _ = dirs::app_profiles_dir().map(|path| {
-                    let path = path.join(file);
-                    if path.exists() {
-                        let _ = fs::remove_file(path);
-                    }
-                });
-            });
-        }
-
-        // delete the original uid
-        if current == uid {
-            self.current = match items.len() > 0 {
-                true => items[0].uid.clone(),
-                false => None,
-            };
-        }
-
-        self.items = Some(items);
-        self.save_file()?;
-        Ok(current == uid)
-    }
-
-    /// 获取current指向的配置内容
-    pub fn current_mapping(&self) -> Result<Mapping> {
-        match (self.current.as_ref(), self.items.as_ref()) {
-            (Some(current), Some(items)) => {
-                if let Some(item) = items.iter().find(|e| e.uid.as_ref() == Some(current)) {
-                    let file_path = match item.file.as_ref() {
-                        Some(file) => dirs::app_profiles_dir()?.join(file),
-                        None => bail!("failed to get the file field"),
-                    };
-                    return Ok(help::read_merge_mapping(&file_path)?);
-                }
-                bail!("failed to find the current profile \"uid:{current}\"");
-            }
-            _ => Ok(Mapping::new()),
-        }
-    }
-}
diff --git a/src-tauri/src/config/runtime.rs b/src-tauri/src/config/runtime.rs
deleted file mode 100644
index cce376ba84bd2458ac50402b7aa34742573a9285..0000000000000000000000000000000000000000
--- a/src-tauri/src/config/runtime.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-use serde::{Deserialize, Serialize};
-use serde_yaml::Mapping;
-use std::collections::HashMap;
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize)]
-pub struct IRuntime {
-    pub config: Option<Mapping>,
-    // 记录在配置中(包括merge和script生成的)出现过的keys
-    // 这些keys不一定都生效
-    pub exists_keys: Vec<String>,
-    pub chain_logs: HashMap<String, Vec<(String, String)>>,
-}
-
-impl IRuntime {
-    pub fn new() -> Self {
-        Self::default()
-    }
-
-    // 这里只更改 allow-lan | ipv6 | log-level
-    pub fn patch_config(&mut self, patch: Mapping) {
-        if let Some(config) = self.config.as_mut() {
-            ["allow-lan", "ipv6", "log-level"]
-                .into_iter()
-                .for_each(|key| {
-                    if let Some(value) = patch.get(key).to_owned() {
-                        config.insert(key.into(), value.clone());
-                    }
-                });
-        }
-    }
-}
diff --git a/src-tauri/src/config/verge.rs b/src-tauri/src/config/verge.rs
deleted file mode 100644
index 961280eadae4d864e867ec3412a865a52e41bd8b..0000000000000000000000000000000000000000
--- a/src-tauri/src/config/verge.rs
+++ /dev/null
@@ -1,224 +0,0 @@
-use crate::utils::{dirs, help};
-use anyhow::Result;
-use log::LevelFilter;
-use serde::{Deserialize, Serialize};
-
-/// ### `verge.yaml` schema
-#[derive(Default, Debug, Clone, Deserialize, Serialize)]
-pub struct IVerge {
-    /// app listening port for app singleton
-    pub app_singleton_port: Option<u16>,
-
-    /// app log level
-    /// silent | error | warn | info | debug | trace
-    pub app_log_level: Option<String>,
-
-    // i18n
-    pub language: Option<String>,
-
-    /// `light` or `dark` or `system`
-    pub theme_mode: Option<String>,
-
-    /// enable blur mode
-    /// maybe be able to set the alpha
-    pub theme_blur: Option<bool>,
-
-    /// enable traffic graph default is true
-    pub traffic_graph: Option<bool>,
-
-    /// show memory info (only for Clash Meta)
-    pub enable_memory_usage: Option<bool>,
-
-    /// clash tun mode
-    pub enable_tun_mode: Option<bool>,
-
-    /// windows service mode
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub enable_service_mode: Option<bool>,
-
-    /// can the app auto startup
-    pub enable_auto_launch: Option<bool>,
-
-    /// not show the window on launch
-    pub enable_silent_start: Option<bool>,
-
-    /// set system proxy
-    pub enable_system_proxy: Option<bool>,
-
-    /// enable proxy guard
-    pub enable_proxy_guard: Option<bool>,
-
-    /// set system proxy bypass
-    pub system_proxy_bypass: Option<String>,
-
-    /// proxy guard duration
-    pub proxy_guard_duration: Option<u64>,
-
-    /// theme setting
-    pub theme_setting: Option<IVergeTheme>,
-
-    /// web ui list
-    pub web_ui_list: Option<Vec<String>>,
-
-    /// clash core path
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub clash_core: Option<String>,
-
-    /// hotkey map
-    /// format: {func},{key}
-    pub hotkeys: Option<Vec<String>>,
-
-    /// 切换代理时自动关闭连接
-    pub auto_close_connection: Option<bool>,
-
-    /// 默认的延迟测试连接
-    pub default_latency_test: Option<String>,
-
-    /// 支持关闭字段过滤,避免meta的新字段都被过滤掉,默认为真
-    pub enable_clash_fields: Option<bool>,
-
-    /// 是否使用内部的脚本支持,默认为真
-    pub enable_builtin_enhanced: Option<bool>,
-
-    /// proxy 页面布局 列数
-    pub proxy_layout_column: Option<i32>,
-
-    /// 日志清理
-    /// 0: 不清理; 1: 7天; 2: 30天; 3: 90天
-    pub auto_log_clean: Option<i32>,
-
-    /// window size and position
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub window_size_position: Option<Vec<f64>>,
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize)]
-pub struct IVergeTheme {
-    pub primary_color: Option<String>,
-    pub secondary_color: Option<String>,
-    pub primary_text: Option<String>,
-    pub secondary_text: Option<String>,
-
-    pub info_color: Option<String>,
-    pub error_color: Option<String>,
-    pub warning_color: Option<String>,
-    pub success_color: Option<String>,
-
-    pub font_family: Option<String>,
-    pub css_injection: Option<String>,
-}
-
-impl IVerge {
-    pub fn new() -> Self {
-        match dirs::verge_path().and_then(|path| help::read_yaml::<IVerge>(&path)) {
-            Ok(config) => config,
-            Err(err) => {
-                log::error!(target: "app", "{err}");
-                Self::template()
-            }
-        }
-    }
-
-    pub fn template() -> Self {
-        Self {
-            clash_core: match cfg!(feature = "default-meta") {
-                false => Some("clash".into()),
-                true => Some("clash-meta".into()),
-            },
-            language: match cfg!(feature = "default-meta") {
-                false => Some("en".into()),
-                true => Some("zh".into()),
-            },
-            theme_mode: Some("system".into()),
-            theme_blur: Some(false),
-            traffic_graph: Some(true),
-            enable_memory_usage: Some(true),
-            enable_auto_launch: Some(false),
-            enable_silent_start: Some(false),
-            enable_system_proxy: Some(false),
-            enable_proxy_guard: Some(false),
-            proxy_guard_duration: Some(30),
-            auto_close_connection: Some(true),
-            enable_builtin_enhanced: Some(true),
-            enable_clash_fields: Some(true),
-            auto_log_clean: Some(3),
-            ..Self::default()
-        }
-    }
-
-    /// Save IVerge App Config
-    pub fn save_file(&self) -> Result<()> {
-        help::save_yaml(&dirs::verge_path()?, &self, Some("# Clash Verge Config"))
-    }
-
-    /// patch verge config
-    /// only save to file
-    pub fn patch_config(&mut self, patch: IVerge) {
-        macro_rules! patch {
-            ($key: tt) => {
-                if patch.$key.is_some() {
-                    self.$key = patch.$key;
-                }
-            };
-        }
-
-        patch!(app_log_level);
-        patch!(language);
-        patch!(theme_mode);
-        patch!(theme_blur);
-        patch!(traffic_graph);
-        patch!(enable_memory_usage);
-
-        patch!(enable_tun_mode);
-        patch!(enable_service_mode);
-        patch!(enable_auto_launch);
-        patch!(enable_silent_start);
-        patch!(enable_system_proxy);
-        patch!(enable_proxy_guard);
-        patch!(system_proxy_bypass);
-        patch!(proxy_guard_duration);
-
-        patch!(theme_setting);
-        patch!(web_ui_list);
-        patch!(clash_core);
-        patch!(hotkeys);
-
-        patch!(auto_close_connection);
-        patch!(default_latency_test);
-        patch!(enable_builtin_enhanced);
-        patch!(proxy_layout_column);
-        patch!(enable_clash_fields);
-        patch!(auto_log_clean);
-        patch!(window_size_position);
-    }
-
-    /// 在初始化前尝试拿到单例端口的值
-    pub fn get_singleton_port() -> u16 {
-        #[cfg(not(feature = "verge-dev"))]
-        const SERVER_PORT: u16 = 33331;
-        #[cfg(feature = "verge-dev")]
-        const SERVER_PORT: u16 = 11233;
-
-        match dirs::verge_path().and_then(|path| help::read_yaml::<IVerge>(&path)) {
-            Ok(config) => config.app_singleton_port.unwrap_or(SERVER_PORT),
-            Err(_) => SERVER_PORT, // 这里就不log错误了
-        }
-    }
-
-    /// 获取日志等级
-    pub fn get_log_level(&self) -> LevelFilter {
-        if let Some(level) = self.app_log_level.as_ref() {
-            match level.to_lowercase().as_str() {
-                "silent" => LevelFilter::Off,
-                "error" => LevelFilter::Error,
-                "warn" => LevelFilter::Warn,
-                "info" => LevelFilter::Info,
-                "debug" => LevelFilter::Debug,
-                "trace" => LevelFilter::Trace,
-                _ => LevelFilter::Info,
-            }
-        } else {
-            LevelFilter::Info
-        }
-    }
-}
diff --git a/src-tauri/src/core/clash_api.rs b/src-tauri/src/core/clash_api.rs
deleted file mode 100644
index 0636b417ed8676a945320d29ba4472b0a33c383a..0000000000000000000000000000000000000000
--- a/src-tauri/src/core/clash_api.rs
+++ /dev/null
@@ -1,141 +0,0 @@
-use crate::config::Config;
-use anyhow::{bail, Result};
-use reqwest::header::HeaderMap;
-use serde::{Deserialize, Serialize};
-use serde_yaml::Mapping;
-use std::collections::HashMap;
-
-/// PUT /configs
-/// path 是绝对路径
-pub async fn put_configs(path: &str) -> Result<()> {
-    let (url, headers) = clash_client_info()?;
-    let url = format!("{url}/configs");
-
-    let mut data = HashMap::new();
-    data.insert("path", path);
-
-    let client = reqwest::ClientBuilder::new().no_proxy().build()?;
-    let builder = client.put(&url).headers(headers).json(&data);
-    let response = builder.send().await?;
-
-    match response.status().as_u16() {
-        204 => Ok(()),
-        status @ _ => {
-            bail!("failed to put configs with status \"{status}\"")
-        }
-    }
-}
-
-/// PATCH /configs
-pub async fn patch_configs(config: &Mapping) -> Result<()> {
-    let (url, headers) = clash_client_info()?;
-    let url = format!("{url}/configs");
-
-    let client = reqwest::ClientBuilder::new().no_proxy().build()?;
-    let builder = client.patch(&url).headers(headers.clone()).json(config);
-    builder.send().await?;
-    Ok(())
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize)]
-pub struct DelayRes {
-    delay: u64,
-}
-
-/// GET /proxies/{name}/delay
-/// 获取代理延迟
-pub async fn get_proxy_delay(name: String, test_url: Option<String>) -> Result<DelayRes> {
-    let (url, headers) = clash_client_info()?;
-    let url = format!("{url}/proxies/{name}/delay");
-
-    let default_url = "http://www.gstatic.com/generate_204";
-    let test_url = test_url
-        .map(|s| if s.is_empty() { default_url.into() } else { s })
-        .unwrap_or(default_url.into());
-
-    let client = reqwest::ClientBuilder::new().no_proxy().build()?;
-    let builder = client
-        .get(&url)
-        .headers(headers)
-        .query(&[("timeout", "10000"), ("url", &test_url)]);
-    let response = builder.send().await?;
-
-    Ok(response.json::<DelayRes>().await?)
-}
-
-/// 根据clash info获取clash服务地址和请求头
-fn clash_client_info() -> Result<(String, HeaderMap)> {
-    let client = { Config::clash().data().get_client_info() };
-
-    let server = format!("http://{}", client.server);
-
-    let mut headers = HeaderMap::new();
-    headers.insert("Content-Type", "application/json".parse()?);
-
-    if let Some(secret) = client.secret {
-        let secret = format!("Bearer {}", secret).parse()?;
-        headers.insert("Authorization", secret);
-    }
-
-    Ok((server, headers))
-}
-
-/// 缩短clash的日志
-pub fn parse_log(log: String) -> String {
-    if log.starts_with("time=") && log.len() > 33 {
-        return (&log[33..]).to_owned();
-    }
-    if log.len() > 9 {
-        return (&log[9..]).to_owned();
-    }
-    return log;
-}
-
-/// 缩短clash -t的错误输出
-/// 仅适配 clash p核 8-26、clash meta 1.13.1
-pub fn parse_check_output(log: String) -> String {
-    let t = log.find("time=");
-    let m = log.find("msg=");
-    let mr = log.rfind('"');
-
-    if let (Some(_), Some(m), Some(mr)) = (t, m, mr) {
-        let e = match log.find("level=error msg=") {
-            Some(e) => e + 17,
-            None => m + 5,
-        };
-
-        if mr > m {
-            return (&log[e..mr]).to_owned();
-        }
-    }
-
-    let l = log.find("error=");
-    let r = log.find("path=").or(Some(log.len()));
-
-    if let (Some(l), Some(r)) = (l, r) {
-        return (&log[(l + 6)..(r - 1)]).to_owned();
-    }
-
-    log
-}
-
-#[test]
-fn test_parse_check_output() {
-    let str1 = r#"xxxx\n time="2022-11-18T20:42:58+08:00" level=error msg="proxy 0: 'alpn' expected type 'string', got unconvertible type '[]interface {}'""#;
-    let str2 = r#"20:43:49 ERR [Config] configuration file test failed error=proxy 0: unsupport proxy type: hysteria path=xxx"#;
-    let str3 = r#"
-    "time="2022-11-18T21:38:01+08:00" level=info msg="Start initial configuration in progress"
-    time="2022-11-18T21:38:01+08:00" level=error msg="proxy 0: 'alpn' expected type 'string', got unconvertible type '[]interface {}'"
-    configuration file xxx\n
-    "#;
-
-    let res1 = parse_check_output(str1.into());
-    let res2 = parse_check_output(str2.into());
-    let res3 = parse_check_output(str3.into());
-
-    println!("res1: {res1}");
-    println!("res2: {res2}");
-    println!("res3: {res3}");
-
-    assert_eq!(res1, res3);
-}
diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs
deleted file mode 100644
index 6b3053b8bd766aeb39fd5632d044a7c48e2822a1..0000000000000000000000000000000000000000
--- a/src-tauri/src/core/core.rs
+++ /dev/null
@@ -1,325 +0,0 @@
-use super::{clash_api, logger::Logger};
-use crate::log_err;
-use crate::{config::*, utils::dirs};
-use anyhow::{bail, Context, Result};
-use once_cell::sync::OnceCell;
-use parking_lot::Mutex;
-use std::{fs, io::Write, sync::Arc, time::Duration};
-use sysinfo::{Pid, PidExt, ProcessExt, System, SystemExt};
-use tauri::api::process::{Command, CommandChild, CommandEvent};
-use tokio::time::sleep;
-
-#[derive(Debug)]
-pub struct CoreManager {
-    sidecar: Arc<Mutex<Option<CommandChild>>>,
-
-    #[allow(unused)]
-    use_service_mode: Arc<Mutex<bool>>,
-}
-
-impl CoreManager {
-    pub fn global() -> &'static CoreManager {
-        static CORE_MANAGER: OnceCell<CoreManager> = OnceCell::new();
-
-        CORE_MANAGER.get_or_init(|| CoreManager {
-            sidecar: Arc::new(Mutex::new(None)),
-            use_service_mode: Arc::new(Mutex::new(false)),
-        })
-    }
-
-    pub fn init(&self) -> Result<()> {
-        // kill old clash process
-        let _ = dirs::clash_pid_path()
-            .and_then(|path| fs::read(path).map(|p| p.to_vec()).context(""))
-            .and_then(|pid| String::from_utf8_lossy(&pid).parse().context(""))
-            .map(|pid| {
-                let mut system = System::new();
-                system.refresh_all();
-                system.process(Pid::from_u32(pid)).map(|proc| {
-                    if proc.name().contains("clash") {
-                        log::debug!(target: "app", "kill old clash process");
-                        proc.kill();
-                    }
-                });
-            });
-
-        tauri::async_runtime::spawn(async {
-            // 启动clash
-            log_err!(Self::global().run_core().await);
-        });
-
-        Ok(())
-    }
-
-    /// 检查配置是否正确
-    pub fn check_config(&self) -> Result<()> {
-        let config_path = Config::generate_file(ConfigType::Check)?;
-        let config_path = dirs::path_to_str(&config_path)?;
-
-        let clash_core = { Config::verge().latest().clash_core.clone() };
-        let clash_core = clash_core.unwrap_or("clash".into());
-
-        let app_dir = dirs::app_home_dir()?;
-        let app_dir = dirs::path_to_str(&app_dir)?;
-
-        let output = Command::new_sidecar(clash_core)?
-            .args(["-t", "-d", app_dir, "-f", config_path])
-            .output()?;
-
-        if !output.status.success() {
-            let error = clash_api::parse_check_output(output.stdout.clone());
-            let error = match error.len() > 0 {
-                true => error,
-                false => output.stdout.clone(),
-            };
-            Logger::global().set_log(output.stdout);
-            bail!("{error}");
-        }
-
-        Ok(())
-    }
-
-    /// 启动核心
-    pub async fn run_core(&self) -> Result<()> {
-        let config_path = Config::generate_file(ConfigType::Run)?;
-
-        #[allow(unused_mut)]
-        let mut should_kill = match self.sidecar.lock().take() {
-            Some(child) => {
-                log::debug!(target: "app", "stop the core by sidecar");
-                let _ = child.kill();
-                true
-            }
-            None => false,
-        };
-
-        #[cfg(target_os = "windows")]
-        if *self.use_service_mode.lock() {
-            log::debug!(target: "app", "stop the core by service");
-            log_err!(super::win_service::stop_core_by_service().await);
-            should_kill = true;
-        }
-
-        // 这里得等一会儿
-        if should_kill {
-            sleep(Duration::from_millis(500)).await;
-        }
-
-        #[cfg(target_os = "windows")]
-        {
-            use super::win_service;
-
-            // 服务模式
-            let enable = { Config::verge().latest().enable_service_mode.clone() };
-            let enable = enable.unwrap_or(false);
-
-            *self.use_service_mode.lock() = enable;
-
-            if enable {
-                // 服务模式启动失败就直接运行sidecar
-                log::debug!(target: "app", "try to run core in service mode");
-
-                match (|| async {
-                    win_service::check_service().await?;
-                    win_service::run_core_by_service(&config_path).await
-                })()
-                .await
-                {
-                    Ok(_) => return Ok(()),
-                    Err(err) => {
-                        // 修改这个值,免得stop出错
-                        *self.use_service_mode.lock() = false;
-                        log::error!(target: "app", "{err}");
-                    }
-                }
-            }
-        }
-
-        let app_dir = dirs::app_home_dir()?;
-        let app_dir = dirs::path_to_str(&app_dir)?;
-
-        let clash_core = { Config::verge().latest().clash_core.clone() };
-        let clash_core = clash_core.unwrap_or("clash".into());
-        let is_clash = clash_core == "clash";
-
-        let config_path = dirs::path_to_str(&config_path)?;
-
-        // fix #212
-        let args = match clash_core.as_str() {
-            "clash-meta" => vec!["-m", "-d", app_dir, "-f", config_path],
-            _ => vec!["-d", app_dir, "-f", config_path],
-        };
-
-        let cmd = Command::new_sidecar(clash_core)?;
-        let (mut rx, cmd_child) = cmd.args(args).spawn()?;
-
-        // 将pid写入文件中
-        crate::log_err!((|| {
-            let pid = cmd_child.pid();
-            let path = dirs::clash_pid_path()?;
-            fs::File::create(path)
-                .context("failed to create the pid file")?
-                .write(format!("{pid}").as_bytes())
-                .context("failed to write pid to the file")?;
-            <Result<()>>::Ok(())
-        })());
-
-        let mut sidecar = self.sidecar.lock();
-        *sidecar = Some(cmd_child);
-        drop(sidecar);
-
-        tauri::async_runtime::spawn(async move {
-            while let Some(event) = rx.recv().await {
-                match event {
-                    CommandEvent::Stdout(line) => {
-                        if is_clash {
-                            let stdout = clash_api::parse_log(line.clone());
-                            log::info!(target: "app", "[clash]: {stdout}");
-                        } else {
-                            log::info!(target: "app", "[clash]: {line}");
-                        };
-                        Logger::global().set_log(line);
-                    }
-                    CommandEvent::Stderr(err) => {
-                        // let stdout = clash_api::parse_log(err.clone());
-                        log::error!(target: "app", "[clash]: {err}");
-                        Logger::global().set_log(err);
-                    }
-                    CommandEvent::Error(err) => {
-                        log::error!(target: "app", "[clash]: {err}");
-                        Logger::global().set_log(err);
-                    }
-                    CommandEvent::Terminated(_) => {
-                        log::info!(target: "app", "clash core terminated");
-                        let _ = CoreManager::global().recover_core();
-                        break;
-                    }
-                    _ => {}
-                }
-            }
-        });
-
-        Ok(())
-    }
-
-    /// 重启内核
-    pub fn recover_core(&'static self) -> Result<()> {
-        // 服务模式不管
-        #[cfg(target_os = "windows")]
-        if *self.use_service_mode.lock() {
-            return Ok(());
-        }
-
-        // 清空原来的sidecar值
-        if let Some(sidecar) = self.sidecar.lock().take() {
-            let _ = sidecar.kill();
-        }
-
-        tauri::async_runtime::spawn(async move {
-            // 6秒之后再查看服务是否正常 (时间随便搞的)
-            // terminated 可能是切换内核 (切换内核已经有500ms的延迟)
-            sleep(Duration::from_millis(6666)).await;
-
-            if self.sidecar.lock().is_none() {
-                log::info!(target: "app", "recover clash core");
-
-                // 重新启动app
-                if let Err(err) = self.run_core().await {
-                    log::error!(target: "app", "failed to recover clash core");
-                    log::error!(target: "app", "{err}");
-
-                    let _ = self.recover_core();
-                }
-            }
-        });
-
-        Ok(())
-    }
-
-    /// 停止核心运行
-    pub fn stop_core(&self) -> Result<()> {
-        #[cfg(target_os = "windows")]
-        if *self.use_service_mode.lock() {
-            log::debug!(target: "app", "stop the core by service");
-            tauri::async_runtime::block_on(async move {
-                log_err!(super::win_service::stop_core_by_service().await);
-            });
-            return Ok(());
-        }
-
-        let mut sidecar = self.sidecar.lock();
-        if let Some(child) = sidecar.take() {
-            log::debug!(target: "app", "stop the core by sidecar");
-            let _ = child.kill();
-        }
-        Ok(())
-    }
-
-    /// 切换核心
-    pub async fn change_core(&self, clash_core: Option<String>) -> Result<()> {
-        let clash_core = clash_core.ok_or(anyhow::anyhow!("clash core is null"))?;
-
-        if &clash_core != "clash" && &clash_core != "clash-meta" {
-            bail!("invalid clash core name \"{clash_core}\"");
-        }
-
-        log::debug!(target: "app", "change core to `{clash_core}`");
-
-        Config::verge().draft().clash_core = Some(clash_core);
-
-        // 更新配置
-        Config::generate()?;
-
-        self.check_config()?;
-
-        // 清掉旧日志
-        Logger::global().clear_log();
-
-        match self.run_core().await {
-            Ok(_) => {
-                Config::verge().apply();
-                Config::runtime().apply();
-                log_err!(Config::verge().latest().save_file());
-                Ok(())
-            }
-            Err(err) => {
-                Config::verge().discard();
-                Config::runtime().discard();
-                Err(err)
-            }
-        }
-    }
-
-    /// 更新proxies那些
-    /// 如果涉及端口和外部控制则需要重启
-    pub async fn update_config(&self) -> Result<()> {
-        log::debug!(target: "app", "try to update clash config");
-
-        // 更新配置
-        Config::generate()?;
-
-        // 检查配置是否正常
-        self.check_config()?;
-
-        // 更新运行时配置
-        let path = Config::generate_file(ConfigType::Run)?;
-        let path = dirs::path_to_str(&path)?;
-
-        // 发送请求 发送5次
-        for i in 0..5 {
-            match clash_api::put_configs(path).await {
-                Ok(_) => break,
-                Err(err) => {
-                    if i < 4 {
-                        log::info!(target: "app", "{err}");
-                    } else {
-                        bail!(err);
-                    }
-                }
-            }
-            sleep(Duration::from_millis(250)).await;
-        }
-
-        Ok(())
-    }
-}
diff --git a/src-tauri/src/core/handle.rs b/src-tauri/src/core/handle.rs
deleted file mode 100644
index 5b46cea7c2de007502de7f189ec0e8b1807c6fed..0000000000000000000000000000000000000000
--- a/src-tauri/src/core/handle.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-use super::tray::Tray;
-use crate::log_err;
-use anyhow::{bail, Result};
-use once_cell::sync::OnceCell;
-use parking_lot::Mutex;
-use std::sync::Arc;
-use tauri::{AppHandle, Manager, Window};
-
-#[derive(Debug, Default, Clone)]
-pub struct Handle {
-    pub app_handle: Arc<Mutex<Option<AppHandle>>>,
-}
-
-impl Handle {
-    pub fn global() -> &'static Handle {
-        static HANDLE: OnceCell<Handle> = OnceCell::new();
-
-        HANDLE.get_or_init(|| Handle {
-            app_handle: Arc::new(Mutex::new(None)),
-        })
-    }
-
-    pub fn init(&self, app_handle: AppHandle) {
-        *self.app_handle.lock() = Some(app_handle);
-    }
-
-    pub fn get_window(&self) -> Option<Window> {
-        self.app_handle
-            .lock()
-            .as_ref()
-            .map_or(None, |a| a.get_window("main"))
-    }
-
-    pub fn refresh_clash() {
-        if let Some(window) = Self::global().get_window() {
-            log_err!(window.emit("verge://refresh-clash-config", "yes"));
-        }
-    }
-
-    pub fn refresh_verge() {
-        if let Some(window) = Self::global().get_window() {
-            log_err!(window.emit("verge://refresh-verge-config", "yes"));
-        }
-    }
-
-    #[allow(unused)]
-    pub fn refresh_profiles() {
-        if let Some(window) = Self::global().get_window() {
-            log_err!(window.emit("verge://refresh-profiles-config", "yes"));
-        }
-    }
-
-    pub fn notice_message<S: Into<String>, M: Into<String>>(status: S, msg: M) {
-        if let Some(window) = Self::global().get_window() {
-            log_err!(window.emit("verge://notice-message", (status.into(), msg.into())));
-        }
-    }
-
-    pub fn update_systray() -> Result<()> {
-        let app_handle = Self::global().app_handle.lock();
-        if app_handle.is_none() {
-            bail!("update_systray unhandled error");
-        }
-        Tray::update_systray(app_handle.as_ref().unwrap())?;
-        Ok(())
-    }
-
-    /// update the system tray state
-    pub fn update_systray_part() -> Result<()> {
-        let app_handle = Self::global().app_handle.lock();
-        if app_handle.is_none() {
-            bail!("update_systray unhandled error");
-        }
-        Tray::update_part(app_handle.as_ref().unwrap())?;
-        Ok(())
-    }
-}
diff --git a/src-tauri/src/core/hotkey.rs b/src-tauri/src/core/hotkey.rs
deleted file mode 100644
index cd4c149194f2eb553ea297e48d471648f8ca5e4f..0000000000000000000000000000000000000000
--- a/src-tauri/src/core/hotkey.rs
+++ /dev/null
@@ -1,181 +0,0 @@
-use crate::{config::Config, feat, log_err};
-use anyhow::{bail, Result};
-use once_cell::sync::OnceCell;
-use parking_lot::Mutex;
-use std::{collections::HashMap, sync::Arc};
-use tauri::{AppHandle, GlobalShortcutManager};
-use wry::application::accelerator::Accelerator;
-
-pub struct Hotkey {
-    current: Arc<Mutex<Vec<String>>>, // 保存当前的热键设置
-
-    app_handle: Arc<Mutex<Option<AppHandle>>>,
-}
-
-impl Hotkey {
-    pub fn global() -> &'static Hotkey {
-        static HOTKEY: OnceCell<Hotkey> = OnceCell::new();
-
-        HOTKEY.get_or_init(|| Hotkey {
-            current: Arc::new(Mutex::new(Vec::new())),
-            app_handle: Arc::new(Mutex::new(None)),
-        })
-    }
-
-    pub fn init(&self, app_handle: AppHandle) -> Result<()> {
-        *self.app_handle.lock() = Some(app_handle);
-
-        let verge = Config::verge();
-
-        if let Some(hotkeys) = verge.latest().hotkeys.as_ref() {
-            for hotkey in hotkeys.iter() {
-                let mut iter = hotkey.split(',');
-                let func = iter.next();
-                let key = iter.next();
-
-                match (key, func) {
-                    (Some(key), Some(func)) => {
-                        log_err!(Self::check_key(key).and_then(|_| self.register(key, func)));
-                    }
-                    _ => {
-                        let key = key.unwrap_or("None");
-                        let func = func.unwrap_or("None");
-                        log::error!(target: "app", "invalid hotkey `{key}`:`{func}`");
-                    }
-                }
-            }
-            *self.current.lock() = hotkeys.clone();
-        }
-
-        Ok(())
-    }
-
-    /// 检查一个键是否合法
-    fn check_key(hotkey: &str) -> Result<()> {
-        // fix #287
-        // tauri的这几个方法全部有Result expect,会panic,先检测一遍避免挂了
-        if hotkey.parse::<Accelerator>().is_err() {
-            bail!("invalid hotkey `{hotkey}`");
-        }
-        Ok(())
-    }
-
-    fn get_manager(&self) -> Result<impl GlobalShortcutManager> {
-        let app_handle = self.app_handle.lock();
-        if app_handle.is_none() {
-            bail!("failed to get the hotkey manager");
-        }
-        Ok(app_handle.as_ref().unwrap().global_shortcut_manager())
-    }
-
-    fn register(&self, hotkey: &str, func: &str) -> Result<()> {
-        let mut manager = self.get_manager()?;
-
-        if manager.is_registered(hotkey)? {
-            manager.unregister(hotkey)?;
-        }
-
-        let f = match func.trim() {
-            "open_dashboard" => || feat::open_dashboard(),
-            "clash_mode_rule" => || feat::change_clash_mode("rule".into()),
-            "clash_mode_global" => || feat::change_clash_mode("global".into()),
-            "clash_mode_direct" => || feat::change_clash_mode("direct".into()),
-            "clash_mode_script" => || feat::change_clash_mode("script".into()),
-            "toggle_system_proxy" => || feat::toggle_system_proxy(),
-            "enable_system_proxy" => || feat::enable_system_proxy(),
-            "disable_system_proxy" => || feat::disable_system_proxy(),
-            "toggle_tun_mode" => || feat::toggle_tun_mode(),
-            "enable_tun_mode" => || feat::enable_tun_mode(),
-            "disable_tun_mode" => || feat::disable_tun_mode(),
-
-            _ => bail!("invalid function \"{func}\""),
-        };
-
-        manager.register(hotkey, f)?;
-        log::info!(target: "app", "register hotkey {hotkey} {func}");
-        Ok(())
-    }
-
-    fn unregister(&self, hotkey: &str) -> Result<()> {
-        self.get_manager()?.unregister(&hotkey)?;
-        log::info!(target: "app", "unregister hotkey {hotkey}");
-        Ok(())
-    }
-
-    pub fn update(&self, new_hotkeys: Vec<String>) -> Result<()> {
-        let mut current = self.current.lock();
-        let old_map = Self::get_map_from_vec(&current);
-        let new_map = Self::get_map_from_vec(&new_hotkeys);
-
-        let (del, add) = Self::get_diff(old_map, new_map);
-
-        // 先检查一遍所有新的热键是不是可以用的
-        for (hotkey, _) in add.iter() {
-            Self::check_key(hotkey)?;
-        }
-
-        del.iter().for_each(|key| {
-            let _ = self.unregister(key);
-        });
-
-        add.iter().for_each(|(key, func)| {
-            log_err!(self.register(key, func));
-        });
-
-        *current = new_hotkeys;
-        Ok(())
-    }
-
-    fn get_map_from_vec<'a>(hotkeys: &'a Vec<String>) -> HashMap<&'a str, &'a str> {
-        let mut map = HashMap::new();
-
-        hotkeys.iter().for_each(|hotkey| {
-            let mut iter = hotkey.split(',');
-            let func = iter.next();
-            let key = iter.next();
-
-            if func.is_some() && key.is_some() {
-                let func = func.unwrap().trim();
-                let key = key.unwrap().trim();
-                map.insert(key, func);
-            }
-        });
-        map
-    }
-
-    fn get_diff<'a>(
-        old_map: HashMap<&'a str, &'a str>,
-        new_map: HashMap<&'a str, &'a str>,
-    ) -> (Vec<&'a str>, Vec<(&'a str, &'a str)>) {
-        let mut del_list = vec![];
-        let mut add_list = vec![];
-
-        old_map.iter().for_each(|(&key, func)| {
-            match new_map.get(key) {
-                Some(new_func) => {
-                    if new_func != func {
-                        del_list.push(key);
-                        add_list.push((key, *new_func));
-                    }
-                }
-                None => del_list.push(key),
-            };
-        });
-
-        new_map.iter().for_each(|(&key, &func)| {
-            if old_map.get(key).is_none() {
-                add_list.push((key, func));
-            }
-        });
-
-        (del_list, add_list)
-    }
-}
-
-impl Drop for Hotkey {
-    fn drop(&mut self) {
-        if let Ok(mut manager) = self.get_manager() {
-            let _ = manager.unregister_all();
-        }
-    }
-}
diff --git a/src-tauri/src/core/logger.rs b/src-tauri/src/core/logger.rs
deleted file mode 100644
index b4264153c3ccccff81f886c249c822c5141750e1..0000000000000000000000000000000000000000
--- a/src-tauri/src/core/logger.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-use once_cell::sync::OnceCell;
-use parking_lot::Mutex;
-use std::{collections::VecDeque, sync::Arc};
-
-const LOGS_QUEUE_LEN: usize = 100;
-
-pub struct Logger {
-    log_data: Arc<Mutex<VecDeque<String>>>,
-}
-
-impl Logger {
-    pub fn global() -> &'static Logger {
-        static LOGGER: OnceCell<Logger> = OnceCell::new();
-
-        LOGGER.get_or_init(|| Logger {
-            log_data: Arc::new(Mutex::new(VecDeque::with_capacity(LOGS_QUEUE_LEN + 10))),
-        })
-    }
-
-    pub fn get_log(&self) -> VecDeque<String> {
-        self.log_data.lock().clone()
-    }
-
-    pub fn set_log(&self, text: String) {
-        let mut logs = self.log_data.lock();
-        if logs.len() > LOGS_QUEUE_LEN {
-            logs.pop_front();
-        }
-        logs.push_back(text);
-    }
-
-    pub fn clear_log(&self) {
-        let mut logs = self.log_data.lock();
-        logs.clear();
-    }
-}
diff --git a/src-tauri/src/core/manager.rs b/src-tauri/src/core/manager.rs
deleted file mode 100644
index fdb92696b73dff89a9d6fd6b5240961cf5cb75be..0000000000000000000000000000000000000000
--- a/src-tauri/src/core/manager.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-use std::borrow::Cow;
-
-/// 给clash内核的tun模式授权
-#[cfg(any(target_os = "macos", target_os = "linux"))]
-pub fn grant_permission(core: String) -> anyhow::Result<()> {
-    use std::process::Command;
-    use tauri::utils::platform::current_exe;
-
-    let path = current_exe()?.with_file_name(core).canonicalize()?;
-    let path = path.display().to_string();
-
-    log::debug!("grant_permission path: {path}");
-
-    #[cfg(target_os = "macos")]
-    let output = {
-        // the path of clash /Applications/Clash Verge.app/Contents/MacOS/clash
-        // https://apple.stackexchange.com/questions/82967/problem-with-empty-spaces-when-executing-shell-commands-in-applescript
-        // let path = escape(&path);
-        let path = path.replace(' ', "\\\\ ");
-        let shell = format!("chown root:admin {path}\nchmod +sx {path}");
-        let command = format!(r#"do shell script "{shell}" with administrator privileges"#);
-        Command::new("osascript")
-            .args(vec!["-e", &command])
-            .output()?
-    };
-
-    #[cfg(target_os = "linux")]
-    let output = {
-        let path = path.replace(' ', "\\ "); // 避免路径中有空格
-        let shell = format!("setcap cap_net_bind_service,cap_net_admin=+ep {path}");
-
-        let sudo = match Command::new("which").arg("pkexec").output() {
-            Ok(output) => {
-                if output.stdout.is_empty() {
-                    "sudo"
-                } else {
-                    "pkexec"
-                }
-            }
-            Err(_) => "sudo",
-        };
-
-        Command::new(sudo).arg("sh").arg("-c").arg(shell).output()?
-    };
-
-    if output.status.success() {
-        Ok(())
-    } else {
-        let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
-        anyhow::bail!("{stderr}");
-    }
-}
-
-#[allow(unused)]
-pub fn escape<'a>(text: &'a str) -> Cow<'a, str> {
-    let bytes = text.as_bytes();
-
-    let mut owned = None;
-
-    for pos in 0..bytes.len() {
-        let special = match bytes[pos] {
-            b' ' => Some(b' '),
-            _ => None,
-        };
-        if let Some(s) = special {
-            if owned.is_none() {
-                owned = Some(bytes[0..pos].to_owned());
-            }
-            owned.as_mut().unwrap().push(b'\\');
-            owned.as_mut().unwrap().push(b'\\');
-            owned.as_mut().unwrap().push(s);
-        } else if let Some(owned) = owned.as_mut() {
-            owned.push(bytes[pos]);
-        }
-    }
-
-    if let Some(owned) = owned {
-        unsafe { Cow::Owned(String::from_utf8_unchecked(owned)) }
-    } else {
-        unsafe { Cow::Borrowed(std::str::from_utf8_unchecked(bytes)) }
-    }
-}
diff --git a/src-tauri/src/core/mod.rs b/src-tauri/src/core/mod.rs
deleted file mode 100644
index 4221721f1ee35ae8128c1f84d7881318ad94393f..0000000000000000000000000000000000000000
--- a/src-tauri/src/core/mod.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-pub mod clash_api;
-mod core;
-pub mod handle;
-pub mod hotkey;
-pub mod logger;
-pub mod manager;
-pub mod sysopt;
-pub mod timer;
-pub mod tray;
-pub mod win_service;
-
-pub use self::core::*;
diff --git a/src-tauri/src/core/sysopt.rs b/src-tauri/src/core/sysopt.rs
deleted file mode 100644
index c43114e2ebcfba722d4a2b7246a11805d28dc4ca..0000000000000000000000000000000000000000
--- a/src-tauri/src/core/sysopt.rs
+++ /dev/null
@@ -1,304 +0,0 @@
-use crate::{config::Config, log_err};
-use anyhow::{anyhow, Result};
-use auto_launch::{AutoLaunch, AutoLaunchBuilder};
-use once_cell::sync::OnceCell;
-use parking_lot::Mutex;
-use std::sync::Arc;
-use sysproxy::Sysproxy;
-use tauri::{async_runtime::Mutex as TokioMutex, utils::platform::current_exe};
-
-pub struct Sysopt {
-    /// current system proxy setting
-    cur_sysproxy: Arc<Mutex<Option<Sysproxy>>>,
-
-    /// record the original system proxy
-    /// recover it when exit
-    old_sysproxy: Arc<Mutex<Option<Sysproxy>>>,
-
-    /// helps to auto launch the app
-    auto_launch: Arc<Mutex<Option<AutoLaunch>>>,
-
-    /// record whether the guard async is running or not
-    guard_state: Arc<TokioMutex<bool>>,
-}
-
-#[cfg(target_os = "windows")]
-static DEFAULT_BYPASS: &str = "localhost;127.*;192.168.*;<local>";
-#[cfg(target_os = "linux")]
-static DEFAULT_BYPASS: &str = "localhost,127.0.0.1,::1";
-#[cfg(target_os = "macos")]
-static DEFAULT_BYPASS: &str = "127.0.0.1,localhost,<local>";
-
-impl Sysopt {
-    pub fn global() -> &'static Sysopt {
-        static SYSOPT: OnceCell<Sysopt> = OnceCell::new();
-
-        SYSOPT.get_or_init(|| Sysopt {
-            cur_sysproxy: Arc::new(Mutex::new(None)),
-            old_sysproxy: Arc::new(Mutex::new(None)),
-            auto_launch: Arc::new(Mutex::new(None)),
-            guard_state: Arc::new(TokioMutex::new(false)),
-        })
-    }
-
-    /// init the sysproxy
-    pub fn init_sysproxy(&self) -> Result<()> {
-        let port = { Config::clash().latest().get_mixed_port() };
-
-        let (enable, bypass) = {
-            let verge = Config::verge();
-            let verge = verge.latest();
-            (
-                verge.enable_system_proxy.clone().unwrap_or(false),
-                verge.system_proxy_bypass.clone(),
-            )
-        };
-
-        let current = Sysproxy {
-            enable,
-            host: String::from("127.0.0.1"),
-            port,
-            bypass: bypass.unwrap_or(DEFAULT_BYPASS.into()),
-        };
-
-        if enable {
-            let old = Sysproxy::get_system_proxy().map_or(None, |p| Some(p));
-            current.set_system_proxy()?;
-
-            *self.old_sysproxy.lock() = old;
-            *self.cur_sysproxy.lock() = Some(current);
-        }
-
-        // run the system proxy guard
-        self.guard_proxy();
-        Ok(())
-    }
-
-    /// update the system proxy
-    pub fn update_sysproxy(&self) -> Result<()> {
-        let mut cur_sysproxy = self.cur_sysproxy.lock();
-        let old_sysproxy = self.old_sysproxy.lock();
-
-        if cur_sysproxy.is_none() || old_sysproxy.is_none() {
-            drop(cur_sysproxy);
-            drop(old_sysproxy);
-            return self.init_sysproxy();
-        }
-
-        let (enable, bypass) = {
-            let verge = Config::verge();
-            let verge = verge.latest();
-            (
-                verge.enable_system_proxy.clone().unwrap_or(false),
-                verge.system_proxy_bypass.clone(),
-            )
-        };
-        let mut sysproxy = cur_sysproxy.take().unwrap();
-
-        sysproxy.enable = enable;
-        sysproxy.bypass = bypass.unwrap_or(DEFAULT_BYPASS.into());
-
-        sysproxy.set_system_proxy()?;
-        *cur_sysproxy = Some(sysproxy);
-
-        Ok(())
-    }
-
-    /// reset the sysproxy
-    pub fn reset_sysproxy(&self) -> Result<()> {
-        let mut cur_sysproxy = self.cur_sysproxy.lock();
-        let mut old_sysproxy = self.old_sysproxy.lock();
-
-        let cur_sysproxy = cur_sysproxy.take();
-
-        if let Some(mut old) = old_sysproxy.take() {
-            // 如果原代理和当前代理 端口一致,就disable关闭,否则就恢复原代理设置
-            // 当前没有设置代理的时候,不确定旧设置是否和当前一致,全关了
-            let port_same = cur_sysproxy.map_or(true, |cur| old.port == cur.port);
-
-            if old.enable && port_same {
-                old.enable = false;
-                log::info!(target: "app", "reset proxy by disabling the original proxy");
-            } else {
-                log::info!(target: "app", "reset proxy to the original proxy");
-            }
-
-            old.set_system_proxy()?;
-        } else if let Some(mut cur @ Sysproxy { enable: true, .. }) = cur_sysproxy {
-            // 没有原代理,就按现在的代理设置disable即可
-            log::info!(target: "app", "reset proxy by disabling the current proxy");
-            cur.enable = false;
-            cur.set_system_proxy()?;
-        } else {
-            log::info!(target: "app", "reset proxy with no action");
-        }
-
-        Ok(())
-    }
-
-    /// init the auto launch
-    pub fn init_launch(&self) -> Result<()> {
-        let enable = { Config::verge().latest().enable_auto_launch.clone() };
-        let enable = enable.unwrap_or(false);
-
-        let app_exe = current_exe()?;
-        let app_exe = dunce::canonicalize(app_exe)?;
-        let app_name = app_exe
-            .file_stem()
-            .and_then(|f| f.to_str())
-            .ok_or(anyhow!("failed to get file stem"))?;
-
-        let app_path = app_exe
-            .as_os_str()
-            .to_str()
-            .ok_or(anyhow!("failed to get app_path"))?
-            .to_string();
-
-        // fix issue #26
-        #[cfg(target_os = "windows")]
-        let app_path = format!("\"{app_path}\"");
-
-        // use the /Applications/Clash Verge.app path
-        #[cfg(target_os = "macos")]
-        let app_path = (|| -> Option<String> {
-            let path = std::path::PathBuf::from(&app_path);
-            let path = path.parent()?.parent()?.parent()?;
-            let extension = path.extension()?.to_str()?;
-            match extension == "app" {
-                true => Some(path.as_os_str().to_str()?.to_string()),
-                false => None,
-            }
-        })()
-        .unwrap_or(app_path);
-
-        // fix #403
-        #[cfg(target_os = "linux")]
-        let app_path = {
-            use crate::core::handle::Handle;
-            use tauri::Manager;
-
-            let handle = Handle::global();
-            match handle.app_handle.lock().as_ref() {
-                Some(app_handle) => {
-                    let appimage = app_handle.env().appimage;
-                    appimage
-                        .and_then(|p| p.to_str().map(|s| s.to_string()))
-                        .unwrap_or(app_path)
-                }
-                None => app_path,
-            }
-        };
-
-        let auto = AutoLaunchBuilder::new()
-            .set_app_name(app_name)
-            .set_app_path(&app_path)
-            .build()?;
-
-        // 避免在开发时将自启动关了
-        #[cfg(feature = "verge-dev")]
-        if !enable {
-            return Ok(());
-        }
-
-        #[cfg(target_os = "macos")]
-        {
-            if enable && !auto.is_enabled().unwrap_or(false) {
-                // 避免重复设置登录项
-                let _ = auto.disable();
-                auto.enable()?;
-            } else if !enable {
-                let _ = auto.disable();
-            }
-        }
-
-        #[cfg(not(target_os = "macos"))]
-        if enable {
-            auto.enable()?;
-        }
-
-        *self.auto_launch.lock() = Some(auto);
-
-        Ok(())
-    }
-
-    /// update the startup
-    pub fn update_launch(&self) -> Result<()> {
-        let auto_launch = self.auto_launch.lock();
-
-        if auto_launch.is_none() {
-            drop(auto_launch);
-            return self.init_launch();
-        }
-        let enable = { Config::verge().latest().enable_auto_launch.clone() };
-        let enable = enable.unwrap_or(false);
-        let auto_launch = auto_launch.as_ref().unwrap();
-
-        match enable {
-            true => auto_launch.enable()?,
-            false => log_err!(auto_launch.disable()), // 忽略关闭的错误
-        };
-
-        Ok(())
-    }
-
-    /// launch a system proxy guard
-    /// read config from file directly
-    pub fn guard_proxy(&self) {
-        use tokio::time::{sleep, Duration};
-
-        let guard_state = self.guard_state.clone();
-
-        tauri::async_runtime::spawn(async move {
-            // if it is running, exit
-            let mut state = guard_state.lock().await;
-            if *state {
-                return;
-            }
-            *state = true;
-            drop(state);
-
-            // default duration is 10s
-            let mut wait_secs = 10u64;
-
-            loop {
-                sleep(Duration::from_secs(wait_secs)).await;
-
-                let (enable, guard, guard_duration, bypass) = {
-                    let verge = Config::verge();
-                    let verge = verge.latest();
-                    (
-                        verge.enable_system_proxy.clone().unwrap_or(false),
-                        verge.enable_proxy_guard.clone().unwrap_or(false),
-                        verge.proxy_guard_duration.clone().unwrap_or(10),
-                        verge.system_proxy_bypass.clone(),
-                    )
-                };
-
-                // stop loop
-                if !enable || !guard {
-                    break;
-                }
-
-                // update duration
-                wait_secs = guard_duration;
-
-                log::debug!(target: "app", "try to guard the system proxy");
-
-                let port = { Config::clash().latest().get_mixed_port() };
-
-                let sysproxy = Sysproxy {
-                    enable: true,
-                    host: "127.0.0.1".into(),
-                    port,
-                    bypass: bypass.unwrap_or(DEFAULT_BYPASS.into()),
-                };
-
-                log_err!(sysproxy.set_system_proxy());
-            }
-
-            let mut state = guard_state.lock().await;
-            *state = false;
-            drop(state);
-        });
-    }
-}
diff --git a/src-tauri/src/core/timer.rs b/src-tauri/src/core/timer.rs
deleted file mode 100644
index 1b40f0fad40bd673f452a4ca3a7229543005b585..0000000000000000000000000000000000000000
--- a/src-tauri/src/core/timer.rs
+++ /dev/null
@@ -1,184 +0,0 @@
-use crate::config::Config;
-use crate::feat;
-use anyhow::{Context, Result};
-use delay_timer::prelude::{DelayTimer, DelayTimerBuilder, TaskBuilder};
-use once_cell::sync::OnceCell;
-use parking_lot::Mutex;
-use std::collections::HashMap;
-use std::sync::Arc;
-
-type TaskID = u64;
-
-pub struct Timer {
-    /// cron manager
-    delay_timer: Arc<Mutex<DelayTimer>>,
-
-    /// save the current state
-    timer_map: Arc<Mutex<HashMap<String, (TaskID, u64)>>>,
-
-    /// increment id
-    timer_count: Arc<Mutex<TaskID>>,
-}
-
-impl Timer {
-    pub fn global() -> &'static Timer {
-        static TIMER: OnceCell<Timer> = OnceCell::new();
-
-        TIMER.get_or_init(|| Timer {
-            delay_timer: Arc::new(Mutex::new(DelayTimerBuilder::default().build())),
-            timer_map: Arc::new(Mutex::new(HashMap::new())),
-            timer_count: Arc::new(Mutex::new(1)),
-        })
-    }
-
-    /// restore timer
-    pub fn init(&self) -> Result<()> {
-        self.refresh()?;
-
-        let cur_timestamp = chrono::Local::now().timestamp();
-
-        let timer_map = self.timer_map.lock();
-        let delay_timer = self.delay_timer.lock();
-
-        Config::profiles().latest().get_items().map(|items| {
-            items
-                .iter()
-                .filter_map(|item| {
-                    // mins to seconds
-                    let interval = ((item.option.as_ref()?.update_interval?) as i64) * 60;
-                    let updated = item.updated? as i64;
-
-                    if interval > 0 && cur_timestamp - updated >= interval {
-                        Some(item)
-                    } else {
-                        None
-                    }
-                })
-                .for_each(|item| {
-                    if let Some(uid) = item.uid.as_ref() {
-                        if let Some((task_id, _)) = timer_map.get(uid) {
-                            crate::log_err!(delay_timer.advance_task(*task_id));
-                        }
-                    }
-                })
-        });
-
-        Ok(())
-    }
-
-    /// Correctly update all cron tasks
-    pub fn refresh(&self) -> Result<()> {
-        let diff_map = self.gen_diff();
-
-        let mut timer_map = self.timer_map.lock();
-        let mut delay_timer = self.delay_timer.lock();
-
-        for (uid, diff) in diff_map.into_iter() {
-            match diff {
-                DiffFlag::Del(tid) => {
-                    let _ = timer_map.remove(&uid);
-                    crate::log_err!(delay_timer.remove_task(tid));
-                }
-                DiffFlag::Add(tid, val) => {
-                    let _ = timer_map.insert(uid.clone(), (tid, val));
-                    crate::log_err!(self.add_task(&mut delay_timer, uid, tid, val));
-                }
-                DiffFlag::Mod(tid, val) => {
-                    let _ = timer_map.insert(uid.clone(), (tid, val));
-                    crate::log_err!(delay_timer.remove_task(tid));
-                    crate::log_err!(self.add_task(&mut delay_timer, uid, tid, val));
-                }
-            }
-        }
-
-        Ok(())
-    }
-
-    /// generate a uid -> update_interval map
-    fn gen_map(&self) -> HashMap<String, u64> {
-        let mut new_map = HashMap::new();
-
-        if let Some(items) = Config::profiles().latest().get_items() {
-            for item in items.iter() {
-                if item.option.is_some() {
-                    let option = item.option.as_ref().unwrap();
-                    let interval = option.update_interval.unwrap_or(0);
-
-                    if interval > 0 {
-                        new_map.insert(item.uid.clone().unwrap(), interval);
-                    }
-                }
-            }
-        }
-
-        new_map
-    }
-
-    /// generate the diff map for refresh
-    fn gen_diff(&self) -> HashMap<String, DiffFlag> {
-        let mut diff_map = HashMap::new();
-
-        let timer_map = self.timer_map.lock();
-
-        let new_map = self.gen_map();
-        let cur_map = &timer_map;
-
-        cur_map.iter().for_each(|(uid, (tid, val))| {
-            let new_val = new_map.get(uid).unwrap_or(&0);
-
-            if *new_val == 0 {
-                diff_map.insert(uid.clone(), DiffFlag::Del(*tid));
-            } else if new_val != val {
-                diff_map.insert(uid.clone(), DiffFlag::Mod(*tid, *new_val));
-            }
-        });
-
-        let mut count = self.timer_count.lock();
-
-        new_map.iter().for_each(|(uid, val)| {
-            if cur_map.get(uid).is_none() {
-                diff_map.insert(uid.clone(), DiffFlag::Add(*count, *val));
-
-                *count += 1;
-            }
-        });
-
-        diff_map
-    }
-
-    /// add a cron task
-    fn add_task(
-        &self,
-        delay_timer: &mut DelayTimer,
-        uid: String,
-        tid: TaskID,
-        minutes: u64,
-    ) -> Result<()> {
-        let task = TaskBuilder::default()
-            .set_task_id(tid)
-            .set_maximum_parallel_runnable_num(1)
-            .set_frequency_repeated_by_minutes(minutes)
-            // .set_frequency_repeated_by_seconds(minutes) // for test
-            .spawn_async_routine(move || Self::async_task(uid.to_owned()))
-            .context("failed to create timer task")?;
-
-        delay_timer
-            .add_task(task)
-            .context("failed to add timer task")?;
-
-        Ok(())
-    }
-
-    /// the task runner
-    async fn async_task(uid: String) {
-        log::info!(target: "app", "running timer task `{uid}`");
-        crate::log_err!(feat::update_profile(uid, None).await);
-    }
-}
-
-#[derive(Debug)]
-enum DiffFlag {
-    Del(TaskID),
-    Add(TaskID, u64),
-    Mod(TaskID, u64),
-}
diff --git a/src-tauri/src/core/tray.rs b/src-tauri/src/core/tray.rs
deleted file mode 100644
index 307e35d5f8b3783b0a001a1ed99f57a446aaf229..0000000000000000000000000000000000000000
--- a/src-tauri/src/core/tray.rs
+++ /dev/null
@@ -1,175 +0,0 @@
-use crate::{cmds, config::Config, feat, utils::resolve};
-use anyhow::Result;
-use tauri::{
-    api, AppHandle, CustomMenuItem, Manager, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem,
-    SystemTraySubmenu,
-};
-
-pub struct Tray {}
-
-impl Tray {
-    pub fn tray_menu(app_handle: &AppHandle) -> SystemTrayMenu {
-        let zh = { Config::verge().latest().language == Some("zh".into()) };
-
-        let version = app_handle.package_info().version.to_string();
-
-        macro_rules! t {
-            ($en: expr, $zh: expr) => {
-                if zh {
-                    $zh
-                } else {
-                    $en
-                }
-            };
-        }
-
-        SystemTrayMenu::new()
-            .add_item(CustomMenuItem::new(
-                "open_window",
-                t!("Dashboard", "打开面板"),
-            ))
-            .add_native_item(SystemTrayMenuItem::Separator)
-            .add_item(CustomMenuItem::new(
-                "rule_mode",
-                t!("Rule Mode", "规则模式"),
-            ))
-            .add_item(CustomMenuItem::new(
-                "global_mode",
-                t!("Global Mode", "全局模式"),
-            ))
-            .add_item(CustomMenuItem::new(
-                "direct_mode",
-                t!("Direct Mode", "直连模式"),
-            ))
-            .add_item(CustomMenuItem::new(
-                "script_mode",
-                t!("Script Mode", "脚本模式"),
-            ))
-            .add_native_item(SystemTrayMenuItem::Separator)
-            .add_item(CustomMenuItem::new(
-                "system_proxy",
-                t!("System Proxy", "系统代理"),
-            ))
-            .add_item(CustomMenuItem::new("tun_mode", t!("TUN Mode", "Tun 模式")))
-            .add_item(CustomMenuItem::new(
-                "copy_env",
-                t!("Copy Env", "复制环境变量"),
-            ))
-            .add_submenu(SystemTraySubmenu::new(
-                t!("Open Dir", "打开目录"),
-                SystemTrayMenu::new()
-                    .add_item(CustomMenuItem::new(
-                        "open_app_dir",
-                        t!("App Dir", "应用目录"),
-                    ))
-                    .add_item(CustomMenuItem::new(
-                        "open_core_dir",
-                        t!("Core Dir", "内核目录"),
-                    ))
-                    .add_item(CustomMenuItem::new(
-                        "open_logs_dir",
-                        t!("Logs Dir", "日志目录"),
-                    )),
-            ))
-            .add_submenu(SystemTraySubmenu::new(
-                t!("More", "更多"),
-                SystemTrayMenu::new()
-                    .add_item(CustomMenuItem::new(
-                        "restart_clash",
-                        t!("Restart Clash", "重启 Clash"),
-                    ))
-                    .add_item(CustomMenuItem::new(
-                        "restart_app",
-                        t!("Restart App", "重启应用"),
-                    ))
-                    .add_item(
-                        CustomMenuItem::new("app_version", format!("Version {version}")).disabled(),
-                    ),
-            ))
-            .add_native_item(SystemTrayMenuItem::Separator)
-            .add_item(CustomMenuItem::new("quit", t!("Quit", "退出")).accelerator("CmdOrControl+Q"))
-    }
-
-    pub fn update_systray(app_handle: &AppHandle) -> Result<()> {
-        app_handle
-            .tray_handle()
-            .set_menu(Tray::tray_menu(app_handle))?;
-        Tray::update_part(app_handle)?;
-        Ok(())
-    }
-
-    pub fn update_part(app_handle: &AppHandle) -> Result<()> {
-        let mode = {
-            Config::clash()
-                .latest()
-                .0
-                .get("mode")
-                .map(|val| val.as_str().unwrap_or("rule"))
-                .unwrap_or("rule")
-                .to_owned()
-        };
-
-        let tray = app_handle.tray_handle();
-
-        let _ = tray.get_item("rule_mode").set_selected(mode == "rule");
-        let _ = tray.get_item("global_mode").set_selected(mode == "global");
-        let _ = tray.get_item("direct_mode").set_selected(mode == "direct");
-        let _ = tray.get_item("script_mode").set_selected(mode == "script");
-
-        let verge = Config::verge();
-        let verge = verge.latest();
-        let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
-        let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
-
-        #[cfg(target_os = "windows")]
-        {
-            let indication_icon = if *system_proxy {
-                include_bytes!("../../icons/win-tray-icon-activated.png").to_vec()
-            } else {
-                include_bytes!("../../icons/win-tray-icon.png").to_vec()
-            };
-
-            let _ = tray.set_icon(tauri::Icon::Raw(indication_icon));
-        }
-
-        let _ = tray.get_item("system_proxy").set_selected(*system_proxy);
-        let _ = tray.get_item("tun_mode").set_selected(*tun_mode);
-
-        Ok(())
-    }
-
-    pub fn on_system_tray_event(app_handle: &AppHandle, event: SystemTrayEvent) {
-        match event {
-            SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
-                mode @ ("rule_mode" | "global_mode" | "direct_mode" | "script_mode") => {
-                    let mode = &mode[0..mode.len() - 5];
-                    feat::change_clash_mode(mode.into());
-                }
-
-                "open_window" => resolve::create_window(app_handle),
-                "system_proxy" => feat::toggle_system_proxy(),
-                "tun_mode" => feat::toggle_tun_mode(),
-                "copy_env" => feat::copy_clash_env(),
-                "open_app_dir" => crate::log_err!(cmds::open_app_dir()),
-                "open_core_dir" => crate::log_err!(cmds::open_core_dir()),
-                "open_logs_dir" => crate::log_err!(cmds::open_logs_dir()),
-                "restart_clash" => feat::restart_clash_core(),
-                "restart_app" => api::process::restart(&app_handle.env()),
-                "quit" => {
-                    let _ = resolve::save_window_size_position(app_handle, true);
-
-                    resolve::resolve_reset();
-                    api::process::kill_children();
-                    app_handle.exit(0);
-                    std::process::exit(0);
-                }
-                _ => {}
-            },
-            #[cfg(target_os = "windows")]
-            SystemTrayEvent::LeftClick { .. } => {
-                resolve::create_window(app_handle);
-            }
-            _ => {}
-        }
-    }
-}
diff --git a/src-tauri/src/core/win_service.rs b/src-tauri/src/core/win_service.rs
deleted file mode 100644
index 865895b2082f83e97a6a88eb966a7a73f048babc..0000000000000000000000000000000000000000
--- a/src-tauri/src/core/win_service.rs
+++ /dev/null
@@ -1,178 +0,0 @@
-#![cfg(target_os = "windows")]
-
-use crate::config::Config;
-use crate::utils::dirs;
-use anyhow::{bail, Context, Result};
-use deelevate::{PrivilegeLevel, Token};
-use runas::Command as RunasCommand;
-use serde::{Deserialize, Serialize};
-use std::collections::HashMap;
-use std::os::windows::process::CommandExt;
-use std::path::PathBuf;
-use std::time::Duration;
-use std::{env::current_exe, process::Command as StdCommand};
-use tokio::time::sleep;
-
-const SERVICE_URL: &str = "http://127.0.0.1:33211";
-
-#[derive(Debug, Deserialize, Serialize, Clone)]
-pub struct ResponseBody {
-    pub core_type: Option<String>,
-    pub bin_path: String,
-    pub config_dir: String,
-    pub log_file: String,
-}
-
-#[derive(Debug, Deserialize, Serialize, Clone)]
-pub struct JsonResponse {
-    pub code: u64,
-    pub msg: String,
-    pub data: Option<ResponseBody>,
-}
-
-/// Install the Clash Verge Service
-/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
-pub async fn install_service() -> Result<()> {
-    let binary_path = dirs::service_path()?;
-    let install_path = binary_path.with_file_name("install-service.exe");
-
-    if !install_path.exists() {
-        bail!("installer exe not found");
-    }
-
-    let token = Token::with_current_process()?;
-    let level = token.privilege_level()?;
-
-    let status = match level {
-        PrivilegeLevel::NotPrivileged => RunasCommand::new(install_path).show(false).status()?,
-        _ => StdCommand::new(install_path)
-            .creation_flags(0x08000000)
-            .status()?,
-    };
-
-    if !status.success() {
-        bail!(
-            "failed to install service with status {}",
-            status.code().unwrap()
-        );
-    }
-
-    Ok(())
-}
-
-/// Uninstall the Clash Verge Service
-/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
-pub async fn uninstall_service() -> Result<()> {
-    let binary_path = dirs::service_path()?;
-    let uninstall_path = binary_path.with_file_name("uninstall-service.exe");
-
-    if !uninstall_path.exists() {
-        bail!("uninstaller exe not found");
-    }
-
-    let token = Token::with_current_process()?;
-    let level = token.privilege_level()?;
-
-    let status = match level {
-        PrivilegeLevel::NotPrivileged => RunasCommand::new(uninstall_path).show(false).status()?,
-        _ => StdCommand::new(uninstall_path)
-            .creation_flags(0x08000000)
-            .status()?,
-    };
-
-    if !status.success() {
-        bail!(
-            "failed to uninstall service with status {}",
-            status.code().unwrap()
-        );
-    }
-
-    Ok(())
-}
-
-/// check the windows service status
-pub async fn check_service() -> Result<JsonResponse> {
-    let url = format!("{SERVICE_URL}/get_clash");
-    let response = reqwest::ClientBuilder::new()
-        .no_proxy()
-        .build()?
-        .get(url)
-        .send()
-        .await
-        .context("failed to connect to the Clash Verge Service")?
-        .json::<JsonResponse>()
-        .await
-        .context("failed to parse the Clash Verge Service response")?;
-
-    Ok(response)
-}
-
-/// start the clash by service
-pub(super) async fn run_core_by_service(config_file: &PathBuf) -> Result<()> {
-    let status = check_service().await?;
-
-    if status.code == 0 {
-        stop_core_by_service().await?;
-        sleep(Duration::from_secs(1)).await;
-    }
-
-    let clash_core = { Config::verge().latest().clash_core.clone() };
-    let clash_core = clash_core.unwrap_or("clash".into());
-
-    let clash_bin = format!("{clash_core}.exe");
-    let bin_path = current_exe()?.with_file_name(clash_bin);
-    let bin_path = dirs::path_to_str(&bin_path)?;
-
-    let config_dir = dirs::app_home_dir()?;
-    let config_dir = dirs::path_to_str(&config_dir)?;
-
-    let log_path = dirs::service_log_file()?;
-    let log_path = dirs::path_to_str(&log_path)?;
-
-    let config_file = dirs::path_to_str(config_file)?;
-
-    let mut map = HashMap::new();
-    map.insert("core_type", clash_core.as_str());
-    map.insert("bin_path", bin_path);
-    map.insert("config_dir", config_dir);
-    map.insert("config_file", config_file);
-    map.insert("log_file", log_path);
-
-    let url = format!("{SERVICE_URL}/start_clash");
-    let res = reqwest::ClientBuilder::new()
-        .no_proxy()
-        .build()?
-        .post(url)
-        .json(&map)
-        .send()
-        .await?
-        .json::<JsonResponse>()
-        .await
-        .context("failed to connect to the Clash Verge Service")?;
-
-    if res.code != 0 {
-        bail!(res.msg);
-    }
-
-    Ok(())
-}
-
-/// stop the clash by service
-pub(super) async fn stop_core_by_service() -> Result<()> {
-    let url = format!("{SERVICE_URL}/stop_clash");
-    let res = reqwest::ClientBuilder::new()
-        .no_proxy()
-        .build()?
-        .post(url)
-        .send()
-        .await?
-        .json::<JsonResponse>()
-        .await
-        .context("failed to connect to the Clash Verge Service")?;
-
-    if res.code != 0 {
-        bail!(res.msg);
-    }
-
-    Ok(())
-}
diff --git a/src-tauri/src/enhance/builtin/meta_guard.js b/src-tauri/src/enhance/builtin/meta_guard.js
deleted file mode 100644
index be4183bb2c65420213f6bf34915cfa91401816b6..0000000000000000000000000000000000000000
--- a/src-tauri/src/enhance/builtin/meta_guard.js
+++ /dev/null
@@ -1,6 +0,0 @@
-function main(params) {
-  if (params.mode === "script") {
-    params.mode = "rule";
-  }
-  return params;
-}
diff --git a/src-tauri/src/enhance/builtin/meta_hy_alpn.js b/src-tauri/src/enhance/builtin/meta_hy_alpn.js
deleted file mode 100644
index da1fac0eb69743d4d21209133cd70ecd76310d30..0000000000000000000000000000000000000000
--- a/src-tauri/src/enhance/builtin/meta_hy_alpn.js
+++ /dev/null
@@ -1,10 +0,0 @@
-function main(params) {
-  if (Array.isArray(params.proxies)) {
-    params.proxies.forEach((p, i) => {
-      if (p.type === "hysteria" && typeof p.alpn === "string") {
-        params.proxies[i].alpn = [p.alpn];
-      }
-    });
-  }
-  return params;
-}
diff --git a/src-tauri/src/enhance/chain.rs b/src-tauri/src/enhance/chain.rs
deleted file mode 100644
index 75c61fb8542e4e5c99413c4121cdcbf8335499c9..0000000000000000000000000000000000000000
--- a/src-tauri/src/enhance/chain.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-use crate::{
-    config::PrfItem,
-    utils::{dirs, help},
-};
-use serde_yaml::Mapping;
-use std::fs;
-
-#[derive(Debug, Clone)]
-pub struct ChainItem {
-    pub uid: String,
-    pub data: ChainType,
-}
-
-#[derive(Debug, Clone)]
-pub enum ChainType {
-    Merge(Mapping),
-    Script(String),
-}
-
-#[derive(Debug, Clone)]
-pub enum ChainSupport {
-    Clash,
-    ClashMeta,
-    All,
-}
-
-impl From<&PrfItem> for Option<ChainItem> {
-    fn from(item: &PrfItem) -> Self {
-        let itype = item.itype.as_ref()?.as_str();
-        let file = item.file.clone()?;
-        let uid = item.uid.clone().unwrap_or("".into());
-        let path = dirs::app_profiles_dir().ok()?.join(file);
-
-        if !path.exists() {
-            return None;
-        }
-
-        match itype {
-            "script" => Some(ChainItem {
-                uid,
-                data: ChainType::Script(fs::read_to_string(path).ok()?),
-            }),
-            "merge" => Some(ChainItem {
-                uid,
-                data: ChainType::Merge(help::read_merge_mapping(&path).ok()?),
-            }),
-            _ => None,
-        }
-    }
-}
-
-impl ChainItem {
-    /// 内建支持一些脚本
-    pub fn builtin() -> Vec<(ChainSupport, ChainItem)> {
-        // meta 的一些处理
-        let meta_guard =
-            ChainItem::to_script("verge_meta_guard", include_str!("./builtin/meta_guard.js"));
-
-        // meta 1.13.2 alpn string 转 数组
-        let hy_alpn =
-            ChainItem::to_script("verge_hy_alpn", include_str!("./builtin/meta_hy_alpn.js"));
-
-        vec![
-            (ChainSupport::ClashMeta, hy_alpn),
-            (ChainSupport::ClashMeta, meta_guard),
-        ]
-    }
-
-    pub fn to_script<U: Into<String>, D: Into<String>>(uid: U, data: D) -> Self {
-        Self {
-            uid: uid.into(),
-            data: ChainType::Script(data.into()),
-        }
-    }
-}
-
-impl ChainSupport {
-    pub fn is_support(&self, core: Option<&String>) -> bool {
-        match core {
-            Some(core) => match (self, core.as_str()) {
-                (ChainSupport::All, _) => true,
-                (ChainSupport::Clash, "clash") => true,
-                (ChainSupport::ClashMeta, "clash-meta") => true,
-                _ => false,
-            },
-            None => true,
-        }
-    }
-}
diff --git a/src-tauri/src/enhance/field.rs b/src-tauri/src/enhance/field.rs
deleted file mode 100644
index 2130b41afde567d2dc1034deb36f7ddd6527a3ce..0000000000000000000000000000000000000000
--- a/src-tauri/src/enhance/field.rs
+++ /dev/null
@@ -1,155 +0,0 @@
-use serde_yaml::{Mapping, Value};
-use std::collections::HashSet;
-
-pub const HANDLE_FIELDS: [&str; 9] = [
-    "mode",
-    "port",
-    "socks-port",
-    "mixed-port",
-    "allow-lan",
-    "log-level",
-    "ipv6",
-    "secret",
-    "external-controller",
-];
-
-pub const DEFAULT_FIELDS: [&str; 5] = [
-    "proxies",
-    "proxy-groups",
-    "proxy-providers",
-    "rules",
-    "rule-providers",
-];
-
-pub const OTHERS_FIELDS: [&str; 30] = [
-    "dns",
-    "tun",
-    "ebpf",
-    "hosts",
-    "script",
-    "profile",
-    "payload",
-    "tunnels",
-    "auto-redir",
-    "experimental",
-    "interface-name",
-    "routing-mark",
-    "redir-port",
-    "tproxy-port",
-    "iptables",
-    "external-ui",
-    "bind-address",
-    "authentication",
-    "tls",                       // meta
-    "sniffer",                   // meta
-    "geox-url",                  // meta
-    "listeners",                 // meta
-    "sub-rules",                 // meta
-    "geodata-mode",              // meta
-    "unified-delay",             // meta
-    "tcp-concurrent",            // meta
-    "enable-process",            // meta
-    "find-process-mode",         // meta
-    "external-controller-tls",   // meta
-    "global-client-fingerprint", // meta
-];
-
-pub fn use_clash_fields() -> Vec<String> {
-    DEFAULT_FIELDS
-        .into_iter()
-        .chain(HANDLE_FIELDS)
-        .chain(OTHERS_FIELDS)
-        .map(|s| s.to_string())
-        .collect()
-}
-
-pub fn use_valid_fields(mut valid: Vec<String>) -> Vec<String> {
-    let others = Vec::from(OTHERS_FIELDS);
-
-    valid.iter_mut().for_each(|s| s.make_ascii_lowercase());
-    valid
-        .into_iter()
-        .filter(|s| others.contains(&s.as_str()))
-        .chain(DEFAULT_FIELDS.iter().map(|s| s.to_string()))
-        .collect()
-}
-
-pub fn use_filter(config: Mapping, filter: &Vec<String>, enable: bool) -> Mapping {
-    if !enable {
-        return config;
-    }
-
-    let mut ret = Mapping::new();
-
-    for (key, value) in config.into_iter() {
-        if let Some(key) = key.as_str() {
-            if filter.contains(&key.to_string()) {
-                ret.insert(Value::from(key), value);
-            }
-        }
-    }
-    ret
-}
-
-pub fn use_lowercase(config: Mapping) -> Mapping {
-    let mut ret = Mapping::new();
-
-    for (key, value) in config.into_iter() {
-        if let Some(key_str) = key.as_str() {
-            let mut key_str = String::from(key_str);
-            key_str.make_ascii_lowercase();
-            ret.insert(Value::from(key_str), value);
-        }
-    }
-    ret
-}
-
-pub fn use_sort(config: Mapping, enable_filter: bool) -> Mapping {
-    let mut ret = Mapping::new();
-
-    HANDLE_FIELDS
-        .into_iter()
-        .chain(OTHERS_FIELDS)
-        .chain(DEFAULT_FIELDS)
-        .for_each(|key| {
-            let key = Value::from(key);
-            config.get(&key).map(|value| {
-                ret.insert(key, value.clone());
-            });
-        });
-
-    if !enable_filter {
-        let supported_keys: HashSet<&str> = HANDLE_FIELDS
-            .into_iter()
-            .chain(OTHERS_FIELDS)
-            .chain(DEFAULT_FIELDS)
-            .collect();
-
-        let config_keys: HashSet<&str> = config
-            .keys()
-            .filter_map(|e| e.as_str())
-            .into_iter()
-            .collect();
-
-        config_keys.difference(&supported_keys).for_each(|&key| {
-            let key = Value::from(key);
-            config.get(&key).map(|value| {
-                ret.insert(key, value.clone());
-            });
-        });
-    }
-
-    ret
-}
-
-pub fn use_keys(config: &Mapping) -> Vec<String> {
-    config
-        .iter()
-        .filter_map(|(key, _)| key.as_str())
-        .map(|s| {
-            let mut s = s.to_string();
-            s.make_ascii_lowercase();
-            return s;
-        })
-        .collect()
-}
diff --git a/src-tauri/src/enhance/merge.rs b/src-tauri/src/enhance/merge.rs
deleted file mode 100644
index 20342c989882e273815ea72b08d86d35c1734eb9..0000000000000000000000000000000000000000
--- a/src-tauri/src/enhance/merge.rs
+++ /dev/null
@@ -1,92 +0,0 @@
-use super::{use_filter, use_lowercase};
-use serde_yaml::{self, Mapping, Sequence, Value};
-
-const MERGE_FIELDS: [&str; 6] = [
-    "prepend-rules",
-    "append-rules",
-    "prepend-proxies",
-    "append-proxies",
-    "prepend-proxy-groups",
-    "append-proxy-groups",
-];
-
-pub fn use_merge(merge: Mapping, mut config: Mapping) -> Mapping {
-    // 直接覆盖原字段
-    use_lowercase(merge.clone())
-        .into_iter()
-        .for_each(|(key, value)| {
-            config.insert(key, value);
-        });
-
-    let merge_list = MERGE_FIELDS.iter().map(|s| s.to_string());
-    let merge = use_filter(merge, &merge_list.collect(), true);
-
-    ["rules", "proxies", "proxy-groups"]
-        .iter()
-        .for_each(|key_str| {
-            let key_val = Value::from(key_str.to_string());
-
-            let mut list = Sequence::default();
-            list = config.get(&key_val).map_or(list.clone(), |val| {
-                val.as_sequence().map_or(list, |v| v.clone())
-            });
-
-            let pre_key = Value::from(format!("prepend-{key_str}"));
-            let post_key = Value::from(format!("append-{key_str}"));
-
-            if let Some(pre_val) = merge.get(&pre_key) {
-                if pre_val.is_sequence() {
-                    let mut pre_val = pre_val.as_sequence().unwrap().clone();
-                    pre_val.extend(list);
-                    list = pre_val;
-                }
-            }
-
-            if let Some(post_val) = merge.get(&post_key) {
-                if post_val.is_sequence() {
-                    list.extend(post_val.as_sequence().unwrap().clone());
-                }
-            }
-
-            config.insert(key_val, Value::from(list));
-        });
-    config
-}
-
-#[test]
-fn test_merge() -> anyhow::Result<()> {
-    let merge = r"
-    prepend-rules:
-      - prepend
-      - 1123123
-    append-rules:
-      - append
-    prepend-proxies:
-      - 9999
-    append-proxies:
-      - 1111
-    rules:
-      - replace
-    proxy-groups: 
-      - 123781923810
-    tun:
-      enable: true
-    dns:
-      enable: true
-  ";
-
-    let config = r"
-    rules:
-      - aaaaa
-    script1: test
-  ";
-
-    let merge = serde_yaml::from_str::<Mapping>(merge)?;
-    let config = serde_yaml::from_str::<Mapping>(config)?;
-
-    let result = serde_yaml::to_string(&use_merge(merge, config))?;
-
-    println!("{result}");
-
-    Ok(())
-}
diff --git a/src-tauri/src/enhance/mod.rs b/src-tauri/src/enhance/mod.rs
deleted file mode 100644
index 0a414000cbac85873a6004b971686b74e72ec5f7..0000000000000000000000000000000000000000
--- a/src-tauri/src/enhance/mod.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-mod chain;
-mod field;
-mod merge;
-mod script;
-mod tun;
-
-pub(self) use self::field::*;
-
-use self::chain::*;
-use self::merge::*;
-use self::script::*;
-use self::tun::*;
-use crate::config::Config;
-use serde_yaml::Mapping;
-use std::collections::HashMap;
-use std::collections::HashSet;
-
-type ResultLog = Vec<(String, String)>;
-
-/// Enhance mode
-/// 返回最终配置、该配置包含的键、和script执行的结果
-pub fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
-    // config.yaml 的配置
-    let clash_config = { Config::clash().latest().0.clone() };
-
-    let (clash_core, enable_tun, enable_builtin, enable_filter) = {
-        let verge = Config::verge();
-        let verge = verge.latest();
-        (
-            verge.clash_core.clone(),
-            verge.enable_tun_mode.clone().unwrap_or(false),
-            verge.enable_builtin_enhanced.clone().unwrap_or(true),
-            verge.enable_clash_fields.clone().unwrap_or(true),
-        )
-    };
-
-    // 从profiles里拿东西
-    let (mut config, chain, valid) = {
-        let profiles = Config::profiles();
-        let profiles = profiles.latest();
-
-        let current = profiles.current_mapping().unwrap_or(Mapping::new());
-
-        let chain = match profiles.chain.as_ref() {
-            Some(chain) => chain
-                .iter()
-                .filter_map(|uid| profiles.get_item(uid).ok())
-                .filter_map(|item| <Option<ChainItem>>::from(item))
-                .collect::<Vec<ChainItem>>(),
-            None => vec![],
-        };
-
-        let valid = profiles.valid.clone().unwrap_or(vec![]);
-
-        (current, chain, valid)
-    };
-
-    let mut result_map = HashMap::new(); // 保存脚本日志
-    let mut exists_keys = use_keys(&config); // 保存出现过的keys
-
-    let valid = use_valid_fields(valid);
-    config = use_filter(config, &valid, enable_filter);
-
-    // 处理用户的profile
-    chain.into_iter().for_each(|item| match item.data {
-        ChainType::Merge(merge) => {
-            exists_keys.extend(use_keys(&merge));
-            config = use_merge(merge, config.to_owned());
-            config = use_filter(config.to_owned(), &valid, enable_filter);
-        }
-        ChainType::Script(script) => {
-            let mut logs = vec![];
-
-            match use_script(script, config.to_owned()) {
-                Ok((res_config, res_logs)) => {
-                    exists_keys.extend(use_keys(&res_config));
-                    config = use_filter(res_config, &valid, enable_filter);
-                    logs.extend(res_logs);
-                }
-                Err(err) => logs.push(("exception".into(), err.to_string())),
-            }
-
-            result_map.insert(item.uid, logs);
-        }
-    });
-
-    // 合并默认的config
-    for (key, value) in clash_config.into_iter() {
-        config.insert(key, value);
-    }
-
-    let clash_fields = use_clash_fields();
-
-    // 内建脚本最后跑
-    if enable_builtin {
-        ChainItem::builtin()
-            .into_iter()
-            .filter(|(s, _)| s.is_support(clash_core.as_ref()))
-            .map(|(_, c)| c)
-            .for_each(|item| {
-                log::debug!(target: "app", "run builtin script {}", item.uid);
-
-                match item.data {
-                    ChainType::Script(script) => match use_script(script, config.to_owned()) {
-                        Ok((res_config, _)) => {
-                            config = use_filter(res_config, &clash_fields, enable_filter);
-                        }
-                        Err(err) => {
-                            log::error!(target: "app", "builtin script error `{err}`");
-                        }
-                    },
-                    _ => {}
-                }
-            });
-    }
-
-    config = use_filter(config, &clash_fields, enable_filter);
-    config = use_tun(config, enable_tun);
-    config = use_sort(config, enable_filter);
-
-    let mut exists_set = HashSet::new();
-    exists_set.extend(exists_keys.into_iter().filter(|s| clash_fields.contains(s)));
-    exists_keys = exists_set.into_iter().collect();
-
-    (config, exists_keys, result_map)
-}
diff --git a/src-tauri/src/enhance/script.rs b/src-tauri/src/enhance/script.rs
deleted file mode 100644
index 97b34c2092b4426ac00c3e3cf068eb6eae111ae9..0000000000000000000000000000000000000000
--- a/src-tauri/src/enhance/script.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-use super::use_lowercase;
-use anyhow::Result;
-use serde_yaml::Mapping;
-
-pub fn use_script(script: String, config: Mapping) -> Result<(Mapping, Vec<(String, String)>)> {
-    use rquickjs::{Context, Func, Runtime};
-    use std::sync::{Arc, Mutex};
-
-    let runtime = Runtime::new().unwrap();
-    let context = Context::full(&runtime).unwrap();
-    let outputs = Arc::new(Mutex::new(vec![]));
-
-    let copy_outputs = outputs.clone();
-    let result = context.with(|ctx| -> Result<Mapping> {
-        ctx.globals().set(
-            "__verge_log__",
-            Func::from(move |level: String, data: String| {
-                let mut out = copy_outputs.lock().unwrap();
-                out.push((level, data));
-            }),
-        )?;
-
-        ctx.eval(
-            r#"var console = Object.freeze({
-        log(data){__verge_log__("log",JSON.stringify(data))}, 
-        info(data){__verge_log__("info",JSON.stringify(data))}, 
-        error(data){__verge_log__("error",JSON.stringify(data))},
-        debug(data){__verge_log__("debug",JSON.stringify(data))},
-      });"#,
-        )?;
-
-        let config = use_lowercase(config.clone());
-        let config_str = serde_json::to_string(&config)?;
-
-        let code = format!(
-            r#"try{{
-        {script};
-        JSON.stringify(main({config_str})||'')
-      }} catch(err) {{
-        `__error_flag__ ${{err.toString()}}`
-      }}"#
-        );
-        let result: String = ctx.eval(code.as_str())?;
-        if result.starts_with("__error_flag__") {
-            anyhow::bail!(result[15..].to_owned());
-        }
-        if result == "\"\"" {
-            anyhow::bail!("main function should return object");
-        }
-        return Ok(serde_json::from_str::<Mapping>(result.as_str())?);
-    });
-
-    let mut out = outputs.lock().unwrap();
-    match result {
-        Ok(config) => Ok((use_lowercase(config), out.to_vec())),
-        Err(err) => {
-            out.push(("exception".into(), err.to_string()));
-            Ok((config, out.to_vec()))
-        }
-    }
-}
-
-#[test]
-fn test_script() {
-    let script = r#"
-    function main(config) {
-      if (Array.isArray(config.rules)) {
-        config.rules = [...config.rules, "add"];
-      }
-      console.log(config);
-      config.proxies = ["111"];
-      return config;
-    }
-  "#;
-
-    let config = r#"
-    rules:
-      - 111
-      - 222
-    tun:
-      enable: false
-    dns:
-      enable: false
-  "#;
-
-    let config = serde_yaml::from_str(config).unwrap();
-    let (config, results) = use_script(script.into(), config).unwrap();
-
-    let config_str = serde_yaml::to_string(&config).unwrap();
-
-    println!("{config_str}");
-
-    dbg!(results);
-}
diff --git a/src-tauri/src/enhance/tun.rs b/src-tauri/src/enhance/tun.rs
deleted file mode 100644
index b72823ac9246d1bb0c3e0d35e6435f10734f58f2..0000000000000000000000000000000000000000
--- a/src-tauri/src/enhance/tun.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-use serde_yaml::{Mapping, Value};
-
-macro_rules! revise {
-    ($map: expr, $key: expr, $val: expr) => {
-        let ret_key = Value::String($key.into());
-        $map.insert(ret_key, Value::from($val));
-    };
-}
-
-// if key not exists then append value
-macro_rules! append {
-    ($map: expr, $key: expr, $val: expr) => {
-        let ret_key = Value::String($key.into());
-        if !$map.contains_key(&ret_key) {
-            $map.insert(ret_key, Value::from($val));
-        }
-    };
-}
-
-pub fn use_tun(mut config: Mapping, enable: bool) -> Mapping {
-    let tun_key = Value::from("tun");
-    let tun_val = config.get(&tun_key);
-
-    if !enable && tun_val.is_none() {
-        return config;
-    }
-
-    let mut tun_val = tun_val.map_or(Mapping::new(), |val| {
-        val.as_mapping().cloned().unwrap_or(Mapping::new())
-    });
-
-    revise!(tun_val, "enable", enable);
-    if enable {
-        append!(tun_val, "stack", "gvisor");
-        append!(tun_val, "dns-hijack", vec!["any:53"]);
-        append!(tun_val, "auto-route", true);
-        append!(tun_val, "auto-detect-interface", true);
-    }
-
-    revise!(config, "tun", tun_val);
-
-    if enable {
-        use_dns_for_tun(config)
-    } else {
-        config
-    }
-}
-
-fn use_dns_for_tun(mut config: Mapping) -> Mapping {
-    let dns_key = Value::from("dns");
-    let dns_val = config.get(&dns_key);
-
-    let mut dns_val = dns_val.map_or(Mapping::new(), |val| {
-        val.as_mapping().cloned().unwrap_or(Mapping::new())
-    });
-
-    // 开启tun将同时开启dns
-    revise!(dns_val, "enable", true);
-
-    append!(dns_val, "enhanced-mode", "fake-ip");
-    append!(dns_val, "fake-ip-range", "198.18.0.1/16");
-    append!(
-        dns_val,
-        "nameserver",
-        vec!["114.114.114.114", "223.5.5.5", "8.8.8.8"]
-    );
-    append!(dns_val, "fallback", vec![] as Vec<&str>);
-
-    #[cfg(target_os = "windows")]
-    append!(
-        dns_val,
-        "fake-ip-filter",
-        vec![
-            "dns.msftncsi.com",
-            "www.msftncsi.com",
-            "www.msftconnecttest.com"
-        ]
-    );
-    revise!(config, "dns", dns_val);
-    config
-}
diff --git a/src-tauri/src/feat.rs b/src-tauri/src/feat.rs
deleted file mode 100644
index a446c2793bfabe6c18956cfda6e940279bb92ca1..0000000000000000000000000000000000000000
--- a/src-tauri/src/feat.rs
+++ /dev/null
@@ -1,341 +0,0 @@
-//!
-//! feat mod 里的函数主要用于
-//! - hotkey 快捷键
-//! - timer 定时器
-//! - cmds 页面调用
-//!
-use crate::config::*;
-use crate::core::*;
-use crate::log_err;
-use crate::utils::resolve;
-use anyhow::{bail, Result};
-use serde_yaml::{Mapping, Value};
-use wry::application::clipboard::Clipboard;
-
-// 打开面板
-pub fn open_dashboard() {
-    let handle = handle::Handle::global();
-    let app_handle = handle.app_handle.lock();
-    if let Some(app_handle) = app_handle.as_ref() {
-        resolve::create_window(app_handle);
-    }
-}
-
-// 重启clash
-pub fn restart_clash_core() {
-    tauri::async_runtime::spawn(async {
-        match CoreManager::global().run_core().await {
-            Ok(_) => {
-                handle::Handle::refresh_clash();
-                handle::Handle::notice_message("set_config::ok", "ok");
-            }
-            Err(err) => {
-                handle::Handle::notice_message("set_config::error", format!("{err}"));
-                log::error!(target:"app", "{err}");
-            }
-        }
-    });
-}
-
-// 切换模式 rule/global/direct/script mode
-pub fn change_clash_mode(mode: String) {
-    let mut mapping = Mapping::new();
-    mapping.insert(Value::from("mode"), mode.clone().into());
-
-    tauri::async_runtime::spawn(async move {
-        log::debug!(target: "app", "change clash mode to {mode}");
-
-        match clash_api::patch_configs(&mapping).await {
-            Ok(_) => {
-                // 更新配置
-                Config::clash().data().patch_config(mapping);
-
-                if Config::clash().data().save_config().is_ok() {
-                    handle::Handle::refresh_clash();
-                    log_err!(handle::Handle::update_systray_part());
-                }
-            }
-            Err(err) => log::error!(target: "app", "{err}"),
-        }
-    });
-}
-
-// 切换系统代理
-pub fn toggle_system_proxy() {
-    let enable = Config::verge().draft().enable_system_proxy.clone();
-    let enable = enable.unwrap_or(false);
-
-    tauri::async_runtime::spawn(async move {
-        match patch_verge(IVerge {
-            enable_system_proxy: Some(!enable),
-            ..IVerge::default()
-        })
-        .await
-        {
-            Ok(_) => handle::Handle::refresh_verge(),
-            Err(err) => log::error!(target: "app", "{err}"),
-        }
-    });
-}
-
-// 打开系统代理
-pub fn enable_system_proxy() {
-    tauri::async_runtime::spawn(async {
-        match patch_verge(IVerge {
-            enable_system_proxy: Some(true),
-            ..IVerge::default()
-        })
-        .await
-        {
-            Ok(_) => handle::Handle::refresh_verge(),
-            Err(err) => log::error!(target: "app", "{err}"),
-        }
-    });
-}
-
-// 关闭系统代理
-pub fn disable_system_proxy() {
-    tauri::async_runtime::spawn(async {
-        match patch_verge(IVerge {
-            enable_system_proxy: Some(false),
-            ..IVerge::default()
-        })
-        .await
-        {
-            Ok(_) => handle::Handle::refresh_verge(),
-            Err(err) => log::error!(target: "app", "{err}"),
-        }
-    });
-}
-
-// 切换tun模式
-pub fn toggle_tun_mode() {
-    let enable = Config::verge().data().enable_tun_mode.clone();
-    let enable = enable.unwrap_or(false);
-
-    tauri::async_runtime::spawn(async move {
-        match patch_verge(IVerge {
-            enable_tun_mode: Some(!enable),
-            ..IVerge::default()
-        })
-        .await
-        {
-            Ok(_) => handle::Handle::refresh_verge(),
-            Err(err) => log::error!(target: "app", "{err}"),
-        }
-    });
-}
-
-// 打开tun模式
-pub fn enable_tun_mode() {
-    tauri::async_runtime::spawn(async {
-        match patch_verge(IVerge {
-            enable_tun_mode: Some(true),
-            ..IVerge::default()
-        })
-        .await
-        {
-            Ok(_) => handle::Handle::refresh_verge(),
-            Err(err) => log::error!(target: "app", "{err}"),
-        }
-    });
-}
-
-// 关闭tun模式
-pub fn disable_tun_mode() {
-    tauri::async_runtime::spawn(async {
-        match patch_verge(IVerge {
-            enable_tun_mode: Some(false),
-            ..IVerge::default()
-        })
-        .await
-        {
-            Ok(_) => handle::Handle::refresh_verge(),
-            Err(err) => log::error!(target: "app", "{err}"),
-        }
-    });
-}
-
-/// 修改clash的配置
-pub async fn patch_clash(patch: Mapping) -> Result<()> {
-    Config::clash().draft().patch_config(patch.clone());
-
-    match {
-        let mixed_port = patch.get("mixed-port");
-        if mixed_port.is_some() {
-            let changed = mixed_port != Config::clash().data().0.get("mixed-port");
-            // 检查端口占用
-            if changed {
-                if let Some(port) = mixed_port.clone().unwrap().as_u64() {
-                    if !port_scanner::local_port_available(port as u16) {
-                        Config::clash().discard();
-                        bail!("port already in use");
-                    }
-                }
-            }
-        };
-
-        // 激活配置
-        if mixed_port.is_some()
-            || patch.get("secret").is_some()
-            || patch.get("external-controller").is_some()
-        {
-            Config::generate()?;
-            CoreManager::global().run_core().await?;
-            handle::Handle::refresh_clash();
-        }
-
-        // 更新系统代理
-        if mixed_port.is_some() {
-            log_err!(sysopt::Sysopt::global().init_sysproxy());
-        }
-
-        if patch.get("mode").is_some() {
-            log_err!(handle::Handle::update_systray_part());
-        }
-
-        Config::runtime().latest().patch_config(patch);
-
-        <Result<()>>::Ok(())
-    } {
-        Ok(()) => {
-            Config::clash().apply();
-            Config::clash().data().save_config()?;
-            Ok(())
-        }
-        Err(err) => {
-            Config::clash().discard();
-            Err(err)
-        }
-    }
-}
-
-/// 修改verge的配置
-/// 一般都是一个个的修改
-pub async fn patch_verge(patch: IVerge) -> Result<()> {
-    Config::verge().draft().patch_config(patch.clone());
-
-    let tun_mode = patch.enable_tun_mode;
-    let auto_launch = patch.enable_auto_launch;
-    let system_proxy = patch.enable_system_proxy;
-    let proxy_bypass = patch.system_proxy_bypass;
-    let language = patch.language;
-
-    match {
-        #[cfg(target_os = "windows")]
-        {
-            let service_mode = patch.enable_service_mode;
-
-            if service_mode.is_some() {
-                log::debug!(target: "app", "change service mode to {}", service_mode.unwrap());
-
-                Config::generate()?;
-                CoreManager::global().run_core().await?;
-            } else if tun_mode.is_some() {
-                update_core_config().await?;
-            }
-        }
-
-        #[cfg(not(target_os = "windows"))]
-        if tun_mode.is_some() {
-            update_core_config().await?;
-        }
-
-        if auto_launch.is_some() {
-            sysopt::Sysopt::global().update_launch()?;
-        }
-        if system_proxy.is_some() || proxy_bypass.is_some() {
-            sysopt::Sysopt::global().update_sysproxy()?;
-            sysopt::Sysopt::global().guard_proxy();
-        }
-
-        if let Some(true) = patch.enable_proxy_guard {
-            sysopt::Sysopt::global().guard_proxy();
-        }
-
-        if let Some(hotkeys) = patch.hotkeys {
-            hotkey::Hotkey::global().update(hotkeys)?;
-        }
-
-        if language.is_some() {
-            handle::Handle::update_systray()?;
-        } else if system_proxy.or(tun_mode).is_some() {
-            handle::Handle::update_systray_part()?;
-        }
-
-        <Result<()>>::Ok(())
-    } {
-        Ok(()) => {
-            Config::verge().apply();
-            Config::verge().data().save_file()?;
-            Ok(())
-        }
-        Err(err) => {
-            Config::verge().discard();
-            Err(err)
-        }
-    }
-}
-
-/// 更新某个profile
-/// 如果更新当前配置就激活配置
-pub async fn update_profile(uid: String, option: Option<PrfOption>) -> Result<()> {
-    let url_opt = {
-        let profiles = Config::profiles();
-        let profiles = profiles.latest();
-        let item = profiles.get_item(&uid)?;
-        let is_remote = item.itype.as_ref().map_or(false, |s| s == "remote");
-
-        if !is_remote {
-            None // 直接更新
-        } else if item.url.is_none() {
-            bail!("failed to get the profile item url");
-        } else {
-            Some((item.url.clone().unwrap(), item.option.clone()))
-        }
-    };
-
-    let should_update = match url_opt {
-        Some((url, opt)) => {
-            let merged_opt = PrfOption::merge(opt, option);
-            let item = PrfItem::from_url(&url, None, None, merged_opt).await?;
-
-            let profiles = Config::profiles();
-            let mut profiles = profiles.latest();
-            profiles.update_item(uid.clone(), item)?;
-
-            Some(uid) == profiles.get_current()
-        }
-        None => true,
-    };
-
-    if should_update {
-        update_core_config().await?;
-    }
-
-    Ok(())
-}
-
-/// 更新配置
-async fn update_core_config() -> Result<()> {
-    match CoreManager::global().update_config().await {
-        Ok(_) => {
-            handle::Handle::refresh_clash();
-            handle::Handle::notice_message("set_config::ok", "ok");
-            Ok(())
-        }
-        Err(err) => {
-            handle::Handle::notice_message("set_config::error", format!("{err}"));
-            Err(err)
-        }
-    }
-}
-
-/// copy env variable
-pub fn copy_clash_env() {
-    let port = { Config::clash().data().get_client_info().port };
-    let text = format!("export https_proxy=http://127.0.0.1:{port} http_proxy=http://127.0.0.1:{port} all_proxy=socks5://127.0.0.1:{port}");
-
-    let mut cliboard = Clipboard::new();
-    cliboard.write_text(text);
-}
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
deleted file mode 100644
index 0c20becbd85ab8db82d30e568c5dfb597dd01e1c..0000000000000000000000000000000000000000
--- a/src-tauri/src/main.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-#![cfg_attr(
-    all(not(debug_assertions), target_os = "windows"),
-    windows_subsystem = "windows"
-)]
-
-mod cmds;
-mod config;
-mod core;
-mod enhance;
-mod feat;
-mod utils;
-
-use crate::utils::{init, resolve, server};
-use tauri::{api, SystemTray};
-
-fn main() -> std::io::Result<()> {
-    // 单例检测
-    if server::check_singleton().is_err() {
-        println!("app exists");
-        return Ok(());
-    }
-
-    crate::log_err!(init::init_config());
-
-    #[allow(unused_mut)]
-    let mut builder = tauri::Builder::default()
-        .system_tray(SystemTray::new())
-        .setup(|app| Ok(resolve::resolve_setup(app)))
-        .on_system_tray_event(core::tray::Tray::on_system_tray_event)
-        .invoke_handler(tauri::generate_handler![
-            // common
-            cmds::get_sys_proxy,
-            cmds::open_app_dir,
-            cmds::open_logs_dir,
-            cmds::open_web_url,
-            cmds::open_core_dir,
-            // cmds::kill_sidecar,
-            cmds::restart_sidecar,
-            cmds::grant_permission,
-            // clash
-            cmds::get_clash_info,
-            cmds::get_clash_logs,
-            cmds::patch_clash_config,
-            cmds::change_clash_core,
-            cmds::get_runtime_config,
-            cmds::get_runtime_yaml,
-            cmds::get_runtime_exists,
-            cmds::get_runtime_logs,
-            // verge
-            cmds::get_verge_config,
-            cmds::patch_verge_config,
-            // cmds::update_hotkeys,
-            // profile
-            cmds::get_profiles,
-            cmds::enhance_profiles,
-            cmds::patch_profiles_config,
-            cmds::view_profile,
-            cmds::patch_profile,
-            cmds::create_profile,
-            cmds::import_profile,
-            cmds::update_profile,
-            cmds::delete_profile,
-            cmds::read_profile_file,
-            cmds::save_profile_file,
-            // service mode
-            cmds::service::check_service,
-            cmds::service::install_service,
-            cmds::service::uninstall_service,
-            // clash api
-            cmds::clash_api_get_proxy_delay
-        ]);
-
-    #[cfg(target_os = "macos")]
-    {
-        use tauri::{Menu, MenuItem, Submenu};
-
-        builder = builder.menu(
-            Menu::new().add_submenu(Submenu::new(
-                "Edit",
-                Menu::new()
-                    .add_native_item(MenuItem::Undo)
-                    .add_native_item(MenuItem::Redo)
-                    .add_native_item(MenuItem::Copy)
-                    .add_native_item(MenuItem::Paste)
-                    .add_native_item(MenuItem::Cut)
-                    .add_native_item(MenuItem::SelectAll)
-                    .add_native_item(MenuItem::CloseWindow)
-                    .add_native_item(MenuItem::Quit),
-            )),
-        );
-    }
-
-    let app = builder
-        .build(tauri::generate_context!())
-        .expect("error while running tauri application");
-
-    app.run(|app_handle, e| match e {
-        tauri::RunEvent::ExitRequested { api, .. } => {
-            api.prevent_exit();
-        }
-        tauri::RunEvent::Exit => {
-            resolve::resolve_reset();
-            api::process::kill_children();
-            app_handle.exit(0);
-        }
-        #[cfg(target_os = "macos")]
-        tauri::RunEvent::WindowEvent { label, event, .. } => {
-            use tauri::Manager;
-
-            if label == "main" {
-                match event {
-                    tauri::WindowEvent::CloseRequested { api, .. } => {
-                        api.prevent_close();
-                        let _ = resolve::save_window_size_position(&app_handle, true);
-
-                        app_handle.get_window("main").map(|win| {
-                            let _ = win.hide();
-                        });
-                    }
-                    _ => {}
-                }
-            }
-        }
-        #[cfg(not(target_os = "macos"))]
-        tauri::RunEvent::WindowEvent { label, event, .. } => {
-            if label == "main" {
-                match event {
-                    tauri::WindowEvent::CloseRequested { .. } => {
-                        let _ = resolve::save_window_size_position(&app_handle, true);
-                    }
-                    tauri::WindowEvent::Moved(_) | tauri::WindowEvent::Resized(_) => {
-                        let _ = resolve::save_window_size_position(&app_handle, false);
-                    }
-                    _ => {}
-                }
-            }
-        }
-        _ => {}
-    });
-
-    Ok(())
-}
diff --git a/src-tauri/src/utils/dirs.rs b/src-tauri/src/utils/dirs.rs
deleted file mode 100644
index 696831de86e97c7430da18941a1c863adfabb122..0000000000000000000000000000000000000000
--- a/src-tauri/src/utils/dirs.rs
+++ /dev/null
@@ -1,159 +0,0 @@
-use anyhow::Result;
-use std::path::PathBuf;
-use tauri::{
-    api::path::{home_dir, resource_dir},
-    Env, PackageInfo,
-};
-
-#[cfg(not(feature = "verge-dev"))]
-static APP_DIR: &str = "clash-verge";
-#[cfg(feature = "verge-dev")]
-static APP_DIR: &str = "clash-verge-dev";
-
-static CLASH_CONFIG: &str = "config.yaml";
-static VERGE_CONFIG: &str = "verge.yaml";
-static PROFILE_YAML: &str = "profiles.yaml";
-
-static mut RESOURCE_DIR: Option<PathBuf> = None;
-
-/// portable flag
-#[allow(unused)]
-static mut PORTABLE_FLAG: bool = false;
-
-pub static mut APP_VERSION: &str = "v1.2.0";
-
-/// initialize portable flag
-#[cfg(target_os = "windows")]
-pub unsafe fn init_portable_flag() -> Result<()> {
-    use tauri::utils::platform::current_exe;
-
-    let exe = current_exe()?;
-
-    if let Some(dir) = exe.parent() {
-        let dir = PathBuf::from(dir).join(".config/PORTABLE");
-
-        if dir.exists() {
-            PORTABLE_FLAG = true;
-        }
-    }
-
-    Ok(())
-}
-
-/// get the verge app home dir
-pub fn app_home_dir() -> Result<PathBuf> {
-    #[cfg(target_os = "windows")]
-    unsafe {
-        use tauri::utils::platform::current_exe;
-
-        if !PORTABLE_FLAG {
-            Ok(home_dir()
-                .ok_or(anyhow::anyhow!("failed to get app home dir"))?
-                .join(".config")
-                .join(APP_DIR))
-        } else {
-            let app_exe = current_exe()?;
-            let app_exe = dunce::canonicalize(app_exe)?;
-            let app_dir = app_exe
-                .parent()
-                .ok_or(anyhow::anyhow!("failed to get the portable app dir"))?;
-            Ok(PathBuf::from(app_dir).join(".config").join(APP_DIR))
-        }
-    }
-
-    #[cfg(not(target_os = "windows"))]
-    Ok(home_dir()
-        .ok_or(anyhow::anyhow!("failed to get the app home dir"))?
-        .join(".config")
-        .join(APP_DIR))
-}
-
-/// get the resources dir
-pub fn app_resources_dir(package_info: &PackageInfo) -> Result<PathBuf> {
-    let res_dir = resource_dir(package_info, &Env::default())
-        .ok_or(anyhow::anyhow!("failed to get the resource dir"))?
-        .join("resources");
-
-    unsafe {
-        RESOURCE_DIR = Some(res_dir.clone());
-
-        let ver = package_info.version.to_string();
-        let ver_str = format!("v{ver}");
-        APP_VERSION = Box::leak(Box::new(ver_str));
-    }
-
-    Ok(res_dir)
-}
-
-/// profiles dir
-pub fn app_profiles_dir() -> Result<PathBuf> {
-    Ok(app_home_dir()?.join("profiles"))
-}
-
-/// logs dir
-pub fn app_logs_dir() -> Result<PathBuf> {
-    Ok(app_home_dir()?.join("logs"))
-}
-
-pub fn clash_path() -> Result<PathBuf> {
-    Ok(app_home_dir()?.join(CLASH_CONFIG))
-}
-
-pub fn verge_path() -> Result<PathBuf> {
-    Ok(app_home_dir()?.join(VERGE_CONFIG))
-}
-
-pub fn profiles_path() -> Result<PathBuf> {
-    Ok(app_home_dir()?.join(PROFILE_YAML))
-}
-
-#[allow(unused)]
-pub fn app_res_dir() -> Result<PathBuf> {
-    unsafe {
-        Ok(RESOURCE_DIR
-            .clone()
-            .ok_or(anyhow::anyhow!("failed to get the resource dir"))?)
-    }
-}
-
-pub fn clash_pid_path() -> Result<PathBuf> {
-    unsafe {
-        Ok(RESOURCE_DIR
-            .clone()
-            .ok_or(anyhow::anyhow!("failed to get the resource dir"))?
-            .join("clash.pid"))
-    }
-}
-
-#[cfg(windows)]
-pub fn service_path() -> Result<PathBuf> {
-    unsafe {
-        let res_dir = RESOURCE_DIR
-            .clone()
-            .ok_or(anyhow::anyhow!("failed to get the resource dir"))?;
-        Ok(res_dir.join("clash-verge-service.exe"))
-    }
-}
-
-#[cfg(windows)]
-pub fn service_log_file() -> Result<PathBuf> {
-    use chrono::Local;
-
-    let log_dir = app_logs_dir()?.join("service");
-
-    let local_time = Local::now().format("%Y-%m-%d-%H%M").to_string();
-    let log_file = format!("{}.log", local_time);
-    let log_file = log_dir.join(log_file);
-
-    let _ = std::fs::create_dir_all(&log_dir);
-
-    Ok(log_file)
-}
-
-pub fn path_to_str(path: &PathBuf) -> Result<&str> {
-    let path_str = path
-        .as_os_str()
-        .to_str()
-        .ok_or(anyhow::anyhow!("failed to get path from {:?}", path))?;
-    Ok(path_str)
-}
diff --git a/src-tauri/src/utils/help.rs b/src-tauri/src/utils/help.rs
deleted file mode 100644
index 03a89f444af8a173141a9e29fb7367b918b09d86..0000000000000000000000000000000000000000
--- a/src-tauri/src/utils/help.rs
+++ /dev/null
@@ -1,172 +0,0 @@
-use anyhow::{anyhow, bail, Context, Result};
-use nanoid::nanoid;
-use serde::{de::DeserializeOwned, Serialize};
-use serde_yaml::{Mapping, Value};
-use std::{fs, path::PathBuf, str::FromStr};
-
-/// read data from yaml as struct T
-pub fn read_yaml<T: DeserializeOwned>(path: &PathBuf) -> Result<T> {
-    if !path.exists() {
-        bail!("file not found \"{}\"", path.display());
-    }
-
-    let yaml_str = fs::read_to_string(&path)
-        .with_context(|| format!("failed to read the file \"{}\"", path.display()))?;
-
-    serde_yaml::from_str::<T>(&yaml_str).with_context(|| {
-        format!(
-            "failed to read the file with yaml format \"{}\"",
-            path.display()
-        )
-    })
-}
-
-/// read mapping from yaml fix #165
-pub fn read_merge_mapping(path: &PathBuf) -> Result<Mapping> {
-    let mut val: Value = read_yaml(path)?;
-    val.apply_merge()
-        .with_context(|| format!("failed to apply merge \"{}\"", path.display()))?;
-
-    Ok(val
-        .as_mapping()
-        .ok_or(anyhow!(
-            "failed to transform to yaml mapping \"{}\"",
-            path.display()
-        ))?
-        .to_owned())
-}
-
-/// save the data to the file
-/// can set `prefix` string to add some comments
-pub fn save_yaml<T: Serialize>(path: &PathBuf, data: &T, prefix: Option<&str>) -> Result<()> {
-    let data_str = serde_yaml::to_string(data)?;
-
-    let yaml_str = match prefix {
-        Some(prefix) => format!("{prefix}\n\n{data_str}"),
-        None => data_str,
-    };
-
-    let path_str = path.as_os_str().to_string_lossy().to_string();
-    fs::write(path, yaml_str.as_bytes())
-        .with_context(|| format!("failed to save file \"{path_str}\""))
-}
-
-const ALPHABET: [char; 62] = [
-    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
-    'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B',
-    'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
-    'V', 'W', 'X', 'Y', 'Z',
-];
-
-/// generate the uid
-pub fn get_uid(prefix: &str) -> String {
-    let id = nanoid!(11, &ALPHABET);
-    format!("{prefix}{id}")
-}
-
-/// parse the string
-/// xxx=123123; => 123123
-pub fn parse_str<T: FromStr>(target: &str, key: &str) -> Option<T> {
-    target.find(key).and_then(|idx| {
-        let idx = idx + key.len();
-        let value = &target[idx..];
-
-        match value.split(';').nth(0) {
-            Some(value) => value.trim().parse(),
-            None => value.trim().parse(),
-        }
-        .ok()
-    })
-}
-
-/// open file
-/// use vscode by default
-pub fn open_file(path: PathBuf) -> Result<()> {
-    #[cfg(target_os = "macos")]
-    let code = "Visual Studio Code";
-    #[cfg(not(target_os = "macos"))]
-    let code = "code";
-
-    // use vscode first
-    if let Err(err) = open::with(&path, code) {
-        log::error!(target: "app", "failed to open file with VScode `{err}`");
-        // default open
-        open::that(path)?;
-    }
-
-    Ok(())
-}
-
-#[macro_export]
-macro_rules! error {
-    ($result: expr) => {
-        log::error!(target: "app", "{}", $result);
-    };
-}
-
-#[macro_export]
-macro_rules! log_err {
-    ($result: expr) => {
-        if let Err(err) = $result {
-            log::error!(target: "app", "{err}");
-        }
-    };
-
-    ($result: expr, $err_str: expr) => {
-        if let Err(_) = $result {
-            log::error!(target: "app", "{}", $err_str);
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! trace_err {
-    ($result: expr, $err_str: expr) => {
-        if let Err(err) = $result {
-            log::trace!(target: "app", "{}, err {}", $err_str, err);
-        }
-    }
-}
-
-/// wrap the anyhow error
-/// transform the error to String
-#[macro_export]
-macro_rules! wrap_err {
-    ($stat: expr) => {
-        match $stat {
-            Ok(a) => Ok(a),
-            Err(err) => {
-                log::error!(target: "app", "{}", err.to_string());
-                Err(format!("{}", err.to_string()))
-            }
-        }
-    };
-}
-
-/// return the string literal error
-#[macro_export]
-macro_rules! ret_err {
-    ($str: expr) => {
-        return Err($str.into())
-    };
-}
-
-#[test]
-fn test_parse_value() {
-    let test_1 = "upload=111; download=2222; total=3333; expire=444";
-    let test_2 = "attachment; filename=Clash.yaml";
-
-    assert_eq!(parse_str::<usize>(test_1, "upload=").unwrap(), 111);
-    assert_eq!(parse_str::<usize>(test_1, "download=").unwrap(), 2222);
-    assert_eq!(parse_str::<usize>(test_1, "total=").unwrap(), 3333);
-    assert_eq!(parse_str::<usize>(test_1, "expire=").unwrap(), 444);
-    assert_eq!(
-        parse_str::<String>(test_2, "filename=").unwrap(),
-        format!("Clash.yaml")
-    );
-
-    assert_eq!(parse_str::<usize>(test_1, "aaa="), None);
-    assert_eq!(parse_str::<usize>(test_1, "upload1="), None);
-    assert_eq!(parse_str::<usize>(test_1, "expire1="), None);
-    assert_eq!(parse_str::<usize>(test_2, "attachment="), None);
-}
diff --git a/src-tauri/src/utils/init.rs b/src-tauri/src/utils/init.rs
deleted file mode 100644
index e9bcd4206e07138642d6255c64bf031920630d43..0000000000000000000000000000000000000000
--- a/src-tauri/src/utils/init.rs
+++ /dev/null
@@ -1,243 +0,0 @@
-use crate::config::*;
-use crate::utils::{dirs, help};
-use anyhow::Result;
-use chrono::{DateTime, Local};
-use log::LevelFilter;
-use log4rs::append::console::ConsoleAppender;
-use log4rs::append::file::FileAppender;
-use log4rs::config::{Appender, Logger, Root};
-use log4rs::encode::pattern::PatternEncoder;
-use std::fs::{self, DirEntry};
-use std::str::FromStr;
-use tauri::PackageInfo;
-
-/// initialize this instance's log file
-fn init_log() -> Result<()> {
-    let log_dir = dirs::app_logs_dir()?;
-    if !log_dir.exists() {
-        let _ = fs::create_dir_all(&log_dir);
-    }
-
-    let log_level = Config::verge().data().get_log_level();
-    if log_level == LevelFilter::Off {
-        return Ok(());
-    }
-
-    let local_time = Local::now().format("%Y-%m-%d-%H%M").to_string();
-    let log_file = format!("{}.log", local_time);
-    let log_file = log_dir.join(log_file);
-
-    let log_pattern = match log_level {
-        LevelFilter::Trace => "{d(%Y-%m-%d %H:%M:%S)} {l} [{M}] - {m}{n}",
-        _ => "{d(%Y-%m-%d %H:%M:%S)} {l} - {m}{n}",
-    };
-
-    let encode = Box::new(PatternEncoder::new(log_pattern));
-
-    let stdout = ConsoleAppender::builder().encoder(encode.clone()).build();
-    let tofile = FileAppender::builder().encoder(encode).build(log_file)?;
-
-    let mut logger_builder = Logger::builder();
-    let mut root_builder = Root::builder();
-
-    let log_more = log_level == LevelFilter::Trace || log_level == LevelFilter::Debug;
-
-    #[cfg(feature = "verge-dev")]
-    {
-        logger_builder = logger_builder.appenders(["file", "stdout"]);
-        if log_more {
-            root_builder = root_builder.appenders(["file", "stdout"]);
-        } else {
-            root_builder = root_builder.appenders(["stdout"]);
-        }
-    }
-    #[cfg(not(feature = "verge-dev"))]
-    {
-        logger_builder = logger_builder.appenders(["file"]);
-        if log_more {
-            root_builder = root_builder.appenders(["file"]);
-        }
-    }
-
-    let (config, _) = log4rs::config::Config::builder()
-        .appender(Appender::builder().build("stdout", Box::new(stdout)))
-        .appender(Appender::builder().build("file", Box::new(tofile)))
-        .logger(logger_builder.additive(false).build("app", log_level))
-        .build_lossy(root_builder.build(log_level));
-
-    log4rs::init_config(config)?;
-
-    Ok(())
-}
-
-/// 删除log文件
-pub fn delete_log() -> Result<()> {
-    let log_dir = dirs::app_logs_dir()?;
-    if !log_dir.exists() {
-        return Ok(());
-    }
-
-    let auto_log_clean = {
-        let verge = Config::verge();
-        let verge = verge.data();
-        verge.auto_log_clean.clone().unwrap_or(0)
-    };
-
-    let day = match auto_log_clean {
-        1 => 7,
-        2 => 30,
-        3 => 90,
-        _ => return Ok(()),
-    };
-
-    log::debug!(target: "app", "try to delete log files, day: {day}");
-
-    // %Y-%m-%d to NaiveDateTime
-    let parse_time_str = |s: &str| {
-        let sa: Vec<&str> = s.split('-').collect();
-        if sa.len() != 4 {
-            return Err(anyhow::anyhow!("invalid time str"));
-        }
-
-        let year = i32::from_str(sa[0])?;
-        let month = u32::from_str(sa[1])?;
-        let day = u32::from_str(sa[2])?;
-        let time = chrono::NaiveDate::from_ymd_opt(year, month, day)
-            .ok_or(anyhow::anyhow!("invalid time str"))?
-            .and_hms_opt(0, 0, 0)
-            .ok_or(anyhow::anyhow!("invalid time str"))?;
-        Ok(time)
-    };
-
-    let process_file = |file: DirEntry| -> Result<()> {
-        let file_name = file.file_name();
-        let file_name = file_name.to_str().unwrap_or_default();
-
-        if file_name.ends_with(".log") {
-            let now = Local::now();
-            let created_time = parse_time_str(&file_name[0..file_name.len() - 4])?;
-            let file_time = DateTime::<Local>::from_local(created_time, now.offset().clone());
-
-            let duration = now.signed_duration_since(file_time);
-            if duration.num_days() > day {
-                let file_path = file.path();
-                let _ = fs::remove_file(file_path);
-                log::info!(target: "app", "delete log file: {file_name}");
-            }
-        }
-        Ok(())
-    };
-
-    for file in fs::read_dir(&log_dir)? {
-        if let Ok(file) = file {
-            let _ = process_file(file);
-        }
-    }
-    Ok(())
-}
-
-/// Initialize all the config files
-/// before tauri setup
-pub fn init_config() -> Result<()> {
-    #[cfg(target_os = "windows")]
-    unsafe {
-        let _ = dirs::init_portable_flag();
-    }
-
-    let _ = init_log();
-    let _ = delete_log();
-
-    crate::log_err!(dirs::app_home_dir().map(|app_dir| {
-        if !app_dir.exists() {
-            let _ = fs::create_dir_all(&app_dir);
-        }
-    }));
-
-    crate::log_err!(dirs::app_profiles_dir().map(|profiles_dir| {
-        if !profiles_dir.exists() {
-            let _ = fs::create_dir_all(&profiles_dir);
-        }
-    }));
-
-    crate::log_err!(dirs::clash_path().map(|path| {
-        if !path.exists() {
-            help::save_yaml(&path, &IClashTemp::template().0, Some("# Clash Verge"))?;
-        }
-        <Result<()>>::Ok(())
-    }));
-
-    crate::log_err!(dirs::verge_path().map(|path| {
-        if !path.exists() {
-            help::save_yaml(&path, &IVerge::template(), Some("# Clash Verge"))?;
-        }
-        <Result<()>>::Ok(())
-    }));
-
-    crate::log_err!(dirs::profiles_path().map(|path| {
-        if !path.exists() {
-            help::save_yaml(&path, &IProfiles::template(), Some("# Clash Verge"))?;
-        }
-        <Result<()>>::Ok(())
-    }));
-
-    Ok(())
-}
-
-/// initialize app resources
-/// after tauri setup
-pub fn init_resources(package_info: &PackageInfo) -> Result<()> {
-    let app_dir = dirs::app_home_dir()?;
-    let res_dir = dirs::app_resources_dir(package_info)?;
-
-    if !app_dir.exists() {
-        let _ = fs::create_dir_all(&app_dir);
-    }
-    if !res_dir.exists() {
-        let _ = fs::create_dir_all(&res_dir);
-    }
-
-    #[cfg(target_os = "windows")]
-    let file_list = ["Country.mmdb", "geoip.dat", "geosite.dat", "wintun.dll"];
-    #[cfg(not(target_os = "windows"))]
-    let file_list = ["Country.mmdb", "geoip.dat", "geosite.dat"];
-
-    // copy the resource file
-    // if the source file is newer than the destination file, copy it over
-    for file in file_list.iter() {
-        let src_path = res_dir.join(file);
-        let dest_path = app_dir.join(file);
-
-        let handle_copy = || {
-            match fs::copy(&src_path, &dest_path) {
-                Ok(_) => log::debug!(target: "app", "resources copied '{file}'"),
-                Err(err) => {
-                    log::error!(target: "app", "failed to copy resources '{file}', {err}")
-                }
-            };
-        };
-
-        if src_path.exists() && !dest_path.exists() {
-            handle_copy();
-            continue;
-        }
-
-        let src_modified = fs::metadata(&src_path).and_then(|m| m.modified());
-        let dest_modified = fs::metadata(&dest_path).and_then(|m| m.modified());
-
-        match (src_modified, dest_modified) {
-            (Ok(src_modified), Ok(dest_modified)) => {
-                if src_modified > dest_modified {
-                    handle_copy();
-                } else {
-                    log::debug!(target: "app", "skipping resource copy '{file}'");
-                }
-            }
-            _ => {
-                log::debug!(target: "app", "failed to get modified '{file}'");
-                handle_copy();
-            }
-        };
-    }
-
-    Ok(())
-}
diff --git a/src-tauri/src/utils/mod.rs b/src-tauri/src/utils/mod.rs
deleted file mode 100644
index aeb0a60c8481f819d06dfd9acb50375b7c328299..0000000000000000000000000000000000000000
--- a/src-tauri/src/utils/mod.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-pub mod dirs;
-pub mod help;
-pub mod init;
-pub mod resolve;
-pub mod server;
-pub mod tmpl;
-// mod winhelp;
diff --git a/src-tauri/src/utils/resolve.rs b/src-tauri/src/utils/resolve.rs
deleted file mode 100644
index 14d4bdd68e663ac54b2b3694d51192996eb4464e..0000000000000000000000000000000000000000
--- a/src-tauri/src/utils/resolve.rs
+++ /dev/null
@@ -1,179 +0,0 @@
-use crate::{config::Config, core::*, utils::init, utils::server};
-use crate::{log_err, trace_err};
-use anyhow::Result;
-use tauri::{App, AppHandle, Manager};
-
-/// handle something when start app
-pub fn resolve_setup(app: &mut App) {
-    #[cfg(target_os = "macos")]
-    app.set_activation_policy(tauri::ActivationPolicy::Accessory);
-
-    handle::Handle::global().init(app.app_handle());
-
-    log_err!(init::init_resources(app.package_info()));
-
-    // 启动核心
-    log::trace!("init config");
-    log_err!(Config::init_config());
-
-    log::trace!("launch core");
-    log_err!(CoreManager::global().init());
-
-    // setup a simple http server for singleton
-    log::trace!("launch embed server");
-    server::embed_server(app.app_handle());
-
-    log::trace!("init system tray");
-    log_err!(tray::Tray::update_systray(&app.app_handle()));
-
-    let silent_start = { Config::verge().data().enable_silent_start.clone() };
-    if !silent_start.unwrap_or(false) {
-        create_window(&app.app_handle());
-    }
-
-    log_err!(sysopt::Sysopt::global().init_launch());
-    log_err!(sysopt::Sysopt::global().init_sysproxy());
-
-    log_err!(handle::Handle::update_systray_part());
-    log_err!(hotkey::Hotkey::global().init(app.app_handle()));
-    log_err!(timer::Timer::global().init());
-}
-
-/// reset system proxy
-pub fn resolve_reset() {
-    log_err!(sysopt::Sysopt::global().reset_sysproxy());
-    log_err!(CoreManager::global().stop_core());
-}
-
-/// create main window
-pub fn create_window(app_handle: &AppHandle) {
-    if let Some(window) = app_handle.get_window("main") {
-        trace_err!(window.unminimize(), "set win unminimize");
-        trace_err!(window.show(), "set win visible");
-        trace_err!(window.set_focus(), "set win focus");
-        return;
-    }
-
-    let mut builder = tauri::window::WindowBuilder::new(
-        app_handle,
-        "main".to_string(),
-        tauri::WindowUrl::App("index.html".into()),
-    )
-    .title("Clash Verge")
-    .fullscreen(false)
-    .min_inner_size(600.0, 520.0);
-
-    match Config::verge().latest().window_size_position.clone() {
-        Some(size_pos) if size_pos.len() == 4 => {
-            let size = (size_pos[0], size_pos[1]);
-            let pos = (size_pos[2], size_pos[3]);
-            let w = size.0.clamp(600.0, f64::INFINITY);
-            let h = size.1.clamp(520.0, f64::INFINITY);
-            builder = builder.inner_size(w, h).position(pos.0, pos.1);
-        }
-        _ => {
-            #[cfg(target_os = "windows")]
-            {
-                builder = builder.inner_size(800.0, 636.0).center();
-            }
-
-            #[cfg(target_os = "macos")]
-            {
-                builder = builder.inner_size(800.0, 642.0).center();
-            }
-
-            #[cfg(target_os = "linux")]
-            {
-                builder = builder.inner_size(800.0, 642.0).center();
-            }
-        }
-    };
-
-    #[cfg(target_os = "windows")]
-    {
-        use std::time::Duration;
-        use tokio::time::sleep;
-        use window_shadows::set_shadow;
-
-        match builder
-            .decorations(false)
-            .transparent(true)
-            .visible(false)
-            .build()
-        {
-            Ok(win) => {
-                log::trace!("try to calculate the monitor size");
-                let center = (|| -> Result<bool> {
-                    let mut center = false;
-                    let monitor = win.current_monitor()?.ok_or(anyhow::anyhow!(""))?;
-                    let size = monitor.size();
-                    let pos = win.outer_position()?;
-
-                    if pos.x < -400
-                        || pos.x > (size.width - 200).try_into()?
-                        || pos.y < -200
-                        || pos.y > (size.height - 200).try_into()?
-                    {
-                        center = true;
-                    }
-                    Ok(center)
-                })();
-
-                if center.unwrap_or(true) {
-                    trace_err!(win.center(), "set win center");
-                }
-
-                log::trace!("try to create window");
-                let app_handle = app_handle.clone();
-
-                // 加点延迟避免界面闪一下
-                tauri::async_runtime::spawn(async move {
-                    sleep(Duration::from_millis(888)).await;
-
-                    if let Some(window) = app_handle.get_window("main") {
-                        trace_err!(set_shadow(&window, true), "set win shadow");
-                        trace_err!(window.show(), "set win visible");
-                        trace_err!(window.unminimize(), "set win unminimize");
-                        trace_err!(window.set_focus(), "set win focus");
-                    } else {
-                        log::error!(target: "app", "failed to create window, get_window is None")
-                    }
-                });
-            }
-            Err(err) => log::error!(target: "app", "failed to create window, {err}"),
-        }
-    }
-
-    #[cfg(target_os = "macos")]
-    crate::log_err!(builder
-        .decorations(true)
-        .hidden_title(true)
-        .title_bar_style(tauri::TitleBarStyle::Overlay)
-        .build());
-
-    #[cfg(target_os = "linux")]
-    crate::log_err!(builder.decorations(true).transparent(false).build());
-}
-
-/// save window size and position
-pub fn save_window_size_position(app_handle: &AppHandle, save_to_file: bool) -> Result<()> {
-    let win = app_handle
-        .get_window("main")
-        .ok_or(anyhow::anyhow!("failed to get window"))?;
-
-    let scale = win.scale_factor()?;
-    let size = win.inner_size()?;
-    let size = size.to_logical::<f64>(scale);
-    let pos = win.outer_position()?;
-    let pos = pos.to_logical::<f64>(scale);
-
-    let verge = Config::verge();
-    let mut verge = verge.latest();
-    verge.window_size_position = Some(vec![size.width, size.height, pos.x, pos.y]);
-
-    if save_to_file {
-        verge.save_file()?;
-    }
-
-    Ok(())
-}
diff --git a/src-tauri/src/utils/server.rs b/src-tauri/src/utils/server.rs
deleted file mode 100644
index f4e98368abadac296ef2442df0622b712a8af45f..0000000000000000000000000000000000000000
--- a/src-tauri/src/utils/server.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-extern crate warp;
-
-use super::resolve;
-use crate::config::IVerge;
-use anyhow::{bail, Result};
-use port_scanner::local_port_available;
-use tauri::AppHandle;
-use warp::Filter;
-
-/// check whether there is already exists
-pub fn check_singleton() -> Result<()> {
-    let port = IVerge::get_singleton_port();
-
-    if !local_port_available(port) {
-        tauri::async_runtime::block_on(async {
-            let url = format!("http://127.0.0.1:{port}/commands/visible");
-            let resp = reqwest::get(url).await?.text().await?;
-
-            if &resp == "ok" {
-                bail!("app exists");
-            }
-
-            log::error!("failed to setup singleton listen server");
-            Ok(())
-        })
-    } else {
-        Ok(())
-    }
-}
-
-/// The embed server only be used to implement singleton process
-/// maybe it can be used as pac server later
-pub fn embed_server(app_handle: AppHandle) {
-    let port = IVerge::get_singleton_port();
-
-    tauri::async_runtime::spawn(async move {
-        let commands = warp::path!("commands" / "visible").map(move || {
-            resolve::create_window(&app_handle);
-            format!("ok")
-        });
-
-        warp::serve(commands).bind(([127, 0, 0, 1], port)).await;
-    });
-}
diff --git a/src-tauri/src/utils/tmpl.rs b/src-tauri/src/utils/tmpl.rs
deleted file mode 100644
index ec17c336eb5cd7771beef7764418504445a44834..0000000000000000000000000000000000000000
--- a/src-tauri/src/utils/tmpl.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-///! Some config file template
-
-/// template for new a profile item
-pub const ITEM_LOCAL: &str = "# Profile Template for clash verge
-
-proxies:
-
-proxy-groups:
-
-rules:
-";
-
-/// enhanced profile
-pub const ITEM_MERGE: &str = "# Merge Template for clash verge
-# The `Merge` format used to enhance profile
-
-prepend-rules:
-
-prepend-proxies:
-
-prepend-proxy-groups:
-
-append-rules:
-
-append-proxies:
-
-append-proxy-groups:
-";
-
-/// enhanced profile
-pub const ITEM_SCRIPT: &str = "// Define the `main` function
-
-function main(params) {
-  return params;
-}
-";
diff --git a/src-tauri/src/utils/winhelp.rs b/src-tauri/src/utils/winhelp.rs
deleted file mode 100644
index e903d951c25f6f311579492df9016b0b50726394..0000000000000000000000000000000000000000
--- a/src-tauri/src/utils/winhelp.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-#![cfg(target_os = "windows")]
-#![allow(non_snake_case)]
-#![allow(non_camel_case_types)]
-
-//!
-//! From https://github.com/tauri-apps/window-vibrancy/blob/dev/src/windows.rs
-//!
-
-use windows_sys::Win32::{
-    Foundation::*,
-    System::{LibraryLoader::*, SystemInformation::*},
-};
-
-fn get_function_impl(library: &str, function: &str) -> Option<FARPROC> {
-    assert_eq!(library.chars().last(), Some('\0'));
-    assert_eq!(function.chars().last(), Some('\0'));
-
-    let module = unsafe { LoadLibraryA(library.as_ptr()) };
-    if module == 0 {
-        return None;
-    }
-    Some(unsafe { GetProcAddress(module, function.as_ptr()) })
-}
-
-macro_rules! get_function {
-    ($lib:expr, $func:ident) => {
-        get_function_impl(concat!($lib, '\0'), concat!(stringify!($func), '\0')).map(|f| unsafe {
-            std::mem::transmute::<::windows_sys::Win32::Foundation::FARPROC, $func>(f)
-        })
-    };
-}
-
-/// Returns a tuple of (major, minor, buildnumber)
-fn get_windows_ver() -> Option<(u32, u32, u32)> {
-    type RtlGetVersion = unsafe extern "system" fn(*mut OSVERSIONINFOW) -> i32;
-    let handle = get_function!("ntdll.dll", RtlGetVersion);
-    if let Some(rtl_get_version) = handle {
-        unsafe {
-            let mut vi = OSVERSIONINFOW {
-                dwOSVersionInfoSize: 0,
-                dwMajorVersion: 0,
-                dwMinorVersion: 0,
-                dwBuildNumber: 0,
-                dwPlatformId: 0,
-                szCSDVersion: [0; 128],
-            };
-
-            let status = (rtl_get_version)(&mut vi as _);
-
-            if status >= 0 {
-                Some((vi.dwMajorVersion, vi.dwMinorVersion, vi.dwBuildNumber))
-            } else {
-                None
-            }
-        }
-    } else {
-        None
-    }
-}
-
-pub fn is_win11() -> bool {
-    let v = get_windows_ver().unwrap_or_default();
-    v.2 >= 22000
-}
-
-#[test]
-fn test_version() {
-    dbg!(get_windows_ver().unwrap_or_default());
-}
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
deleted file mode 100644
index 71c7200be85e63387fec8926d9c7bb8e2a1d008f..0000000000000000000000000000000000000000
--- a/src-tauri/tauri.conf.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
-  "package": {
-    "productName": "Clash Verge",
-    "version": "1.3.8"
-  },
-  "build": {
-    "distDir": "../dist",
-    "devPath": "http://localhost:3000/",
-    "beforeDevCommand": "yarn run web:dev",
-    "beforeBuildCommand": "yarn run web:build"
-  },
-  "tauri": {
-    "systemTray": {
-      "iconPath": "icons/tray-icon.ico",
-      "iconAsTemplate": true
-    },
-    "bundle": {
-      "active": true,
-      "targets": "all",
-      "identifier": "top.gydi.clashverge",
-      "icon": [
-        "icons/32x32.png",
-        "icons/128x128.png",
-        "icons/128x128@2x.png",
-        "icons/icon-new.icns",
-        "icons/icon.ico"
-      ],
-      "resources": ["resources"],
-      "externalBin": ["sidecar/clash", "sidecar/clash-meta"],
-      "copyright": "© 2022 zzzgydi All Rights Reserved",
-      "category": "DeveloperTool",
-      "shortDescription": "A Clash GUI based on tauri.",
-      "longDescription": "A Clash GUI based on tauri.",
-      "deb": {
-        "depends": ["openssl"]
-      },
-      "macOS": {
-        "frameworks": [],
-        "minimumSystemVersion": "",
-        "exceptionDomain": "",
-        "signingIdentity": null,
-        "entitlements": null
-      },
-      "windows": {
-        "certificateThumbprint": null,
-        "digestAlgorithm": "sha256",
-        "timestampUrl": "",
-        "wix": {
-          "language": ["zh-CN", "en-US", "ru-RU"]
-        }
-      }
-    },
-    "updater": {
-      "active": true,
-      "endpoints": [
-        "https://ghproxy.com/https://github.com/zzzgydi/clash-verge/releases/download/updater/update-proxy.json",
-        "https://github.com/zzzgydi/clash-verge/releases/download/updater/update.json"
-      ],
-      "dialog": false,
-      "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDExNUFBNTBBN0FDNEFBRTUKUldUbHFzUjZDcVZhRVRJM25NS3NkSFlFVElxUkNZMzZ6bHUwRVJjb2F3alJXVzRaeDdSaTA2YWYK"
-    },
-    "allowlist": {
-      "shell": {
-        "all": true
-      },
-      "window": {
-        "all": true
-      },
-      "process": {
-        "all": true
-      },
-      "globalShortcut": {
-        "all": true
-      }
-    },
-    "windows": [],
-    "security": {
-      "csp": "script-src 'unsafe-eval' 'self'; default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'; img-src data: 'self';"
-    }
-  }
-}
diff --git a/src/assets/image/logo-box.png b/src/assets/image/logo-box.png
deleted file mode 100644
index fe64a1f62eba57285b1d2ad2791783e30fa783ed..0000000000000000000000000000000000000000
Binary files a/src/assets/image/logo-box.png and /dev/null differ
diff --git a/src/assets/image/logo.ico b/src/assets/image/logo.ico
deleted file mode 100644
index e406a78f26db8439871a6536024a5116e3254951..0000000000000000000000000000000000000000
Binary files a/src/assets/image/logo.ico and /dev/null differ
diff --git a/src/assets/image/logo.png b/src/assets/image/logo.png
deleted file mode 100644
index c384c7c3556a979804b31457bfe87caba0f885e1..0000000000000000000000000000000000000000
Binary files a/src/assets/image/logo.png and /dev/null differ
diff --git a/src/assets/image/logo.svg b/src/assets/image/logo.svg
deleted file mode 100644
index 750fb40f2a26809f3423049c9c842104dc39dde3..0000000000000000000000000000000000000000
--- a/src/assets/image/logo.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-<svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400"
-  height="400" viewBox="0, 0, 400,400">
-  <defs>
-    <linearGradient id="Gradient2" x1="0" x2="-0.1" y1="0" y2="1">
-      <stop offset="0%" stop-color="#5b5c9d" />
-      <stop offset="80%" stop-color="rgb(63, 64, 109)" />
-      <stop offset="100%" stop-color="rgb(63, 64, 109)" />
-    </linearGradient>
-  </defs>
-  <g id="svgg">
-    <path id="path0"
-      d="M118.124 39.858 C 116.645 40.182,114.562 42.930,113.283 46.247 C 111.908 49.812,110.887 54.542,107.205 74.400 C 106.736 76.930,105.926 81.160,105.404 83.800 C 104.527 88.237,103.654 92.889,102.177 101.000 C 101.856 102.760,101.413 105.100,101.192 106.200 C 100.754 108.375,100.784 108.199,98.436 122.200 C 96.675 132.702,95.947 137.215,94.984 143.600 C 94.636 145.910,94.098 149.420,93.789 151.400 C 92.649 158.697,91.961 164.413,92.180 164.768 C 92.304 164.968,92.223 165.192,92.000 165.266 C 91.777 165.340,96.852 165.347,103.277 165.282 C 116.520 165.149,115.721 165.379,116.358 161.519 C 122.839 122.279,179.334 121.580,186.617 160.650 C 186.981 162.602,187.463 164.425,187.689 164.700 C 188.328 165.481,229.717 165.423,230.367 164.640 C 230.622 164.332,231.013 162.937,231.235 161.540 C 237.531 121.949,295.239 121.807,301.620 161.367 C 302.274 165.421,301.855 165.252,310.962 165.117 C 315.273 165.052,318.861 165.090,318.935 165.200 C 319.009 165.310,319.005 165.152,318.927 164.848 C 318.849 164.545,318.519 162.610,318.193 160.548 C 317.867 158.487,317.330 155.135,317.000 153.100 C 316.162 147.934,315.312 142.663,314.823 139.600 C 314.595 138.170,314.226 136.010,314.004 134.800 C 313.781 133.590,312.423 125.400,310.985 116.600 C 304.278 75.545,304.008 74.156,298.145 50.400 C 295.961 41.553,294.621 39.584,290.800 39.611 C 287.927 39.631,283.053 43.395,279.420 48.400 C 277.509 51.032,261.566 79.109,256.960 87.953 C 253.991 93.654,253.647 93.789,245.600 92.402 C 218.757 87.774,194.454 87.780,170.478 92.420 C 162.868 93.893,163.987 94.596,157.579 84.306 C 133.879 46.247,126.566 38.009,118.124 39.858 M147.277 134.807 C 123.365 138.118,111.083 165.918,124.948 185.349 C 140.543 207.202,173.704 202.274,182.466 176.800 C 190.000 154.900,170.471 131.596,147.277 134.807 M262.051 134.810 C 235.780 138.440,224.730 170.720,243.356 189.422 C 264.398 210.548,299.874 195.275,298.689 165.600 C 297.927 146.523,280.892 132.207,262.051 134.810 M157.600 153.840 C 163.092 156.341,166.343 161.914,165.902 168.074 C 164.875 182.425,145.082 186.221,138.715 173.287 C 132.759 161.189,145.324 148.250,157.600 153.840 M273.193 153.597 C 279.788 156.926,283.287 165.159,280.844 171.600 C 275.229 186.406,253.594 183.910,252.135 168.287 C 251.125 157.467,263.609 148.758,273.193 153.597 M91.200 168.809 C 91.200 169.522,90.939 171.836,90.621 173.952 C 89.933 178.523,87.567 196.170,85.788 210.000 C 85.462 212.530,85.012 215.860,84.786 217.400 C 84.561 218.940,84.191 221.820,83.964 223.800 C 83.737 225.780,83.288 229.560,82.965 232.200 C 81.886 241.026,80.172 255.664,79.404 262.600 C 78.867 267.450,78.532 270.381,76.987 283.800 C 76.251 290.187,75.405 297.881,74.568 305.800 C 74.220 309.100,73.789 313.150,73.613 314.800 C 73.436 316.450,73.063 320.230,72.784 323.200 C 72.504 326.170,72.169 328.723,72.038 328.874 C 71.701 329.262,59.638 327.033,54.028 325.546 C 34.668 320.412,26.096 301.951,35.625 285.911 C 38.026 281.869,41.515 278.587,49.795 272.581 C 58.081 266.570,59.262 265.247,59.510 261.702 C 59.969 255.136,50.677 252.070,40.551 255.447 C -6.127 271.014,-3.894 337.227,43.806 351.951 C 50.541 354.030,58.050 355.239,67.760 355.807 C 72.410 356.079,75.202 356.542,82.181 358.199 C 88.822 359.777,100.215 360.425,156.000 362.398 C 170.725 362.918,255.192 362.921,267.760 362.401 C 273.062 362.182,281.900 361.820,287.400 361.597 C 302.851 360.972,326.558 359.339,333.200 358.444 C 343.055 357.116,343.889 354.966,341.839 336.200 C 341.502 333.120,340.948 327.900,340.607 324.600 C 340.266 321.300,339.709 315.990,339.370 312.800 C 339.030 309.610,338.499 304.570,338.189 301.600 C 337.022 290.393,335.650 278.160,334.622 269.800 C 333.105 257.460,332.638 254.027,330.408 238.800 C 329.716 234.070,328.983 229.030,328.781 227.600 C 328.579 226.170,328.231 223.920,328.008 222.600 C 327.785 221.280,326.695 214.260,325.587 207.000 C 324.478 199.740,323.124 191.010,322.578 187.600 C 322.032 184.190,321.325 179.780,321.007 177.800 C 320.689 175.820,320.203 172.711,319.925 170.892 C 319.508 168.155,319.315 167.635,318.810 167.885 C 318.475 168.051,314.780 168.279,310.600 168.393 C 301.870 168.631,302.159 168.535,301.810 171.300 C 299.468 189.825,283.036 203.371,264.230 202.279 C 247.552 201.310,233.532 188.465,231.203 172.020 C 230.651 168.125,232.337 168.400,209.000 168.400 C 185.703 168.400,187.432 168.114,186.814 172.064 C 180.639 211.474,123.556 212.329,116.559 173.117 C 115.684 168.218,116.787 168.629,103.881 168.400 C 97.676 168.290,92.285 168.046,91.900 167.857 C 91.307 167.567,91.200 167.712,91.200 168.809 M211.015 197.632 C 214.247 200.942,215.394 201.357,220.447 201.050 C 225.236 200.759,225.846 201.071,224.310 203.023 C 221.899 206.089,216.333 205.843,210.779 202.425 C 208.312 200.907,207.846 200.906,205.600 202.405 C 200.180 206.022,193.561 206.136,191.600 202.647 C 190.824 201.267,191.555 200.665,193.600 201.001 C 199.643 201.993,201.561 201.450,204.900 197.805 C 207.534 194.929,208.352 194.906,211.015 197.632 "
-      stroke="none" fill="url(#Gradient2)" fill-rule="evenodd"></path>
-    <path id="path1"
-      d="M148.000 131.622 C 132.020 133.140,119.114 145.293,116.377 161.400 C 115.675 165.535,116.697 165.239,103.579 165.112 C 97.252 165.050,92.159 165.135,92.261 165.300 C 92.364 165.465,92.279 165.600,92.074 165.600 C 91.391 165.600,91.684 167.617,92.424 168.013 C 92.839 168.235,97.730 168.400,103.897 168.400 C 116.551 168.400,115.666 168.070,116.562 173.117 C 123.522 212.326,180.639 211.470,186.814 172.064 C 187.432 168.114,185.703 168.400,209.000 168.400 C 232.337 168.400,230.651 168.125,231.203 172.020 C 233.532 188.465,247.552 201.310,264.230 202.279 C 283.039 203.371,299.468 189.826,301.811 171.294 C 302.169 168.458,302.345 168.400,310.600 168.400 C 318.988 168.400,319.609 168.159,318.852 165.200 C 318.824 165.090,315.273 165.052,310.961 165.117 C 301.855 165.252,302.274 165.421,301.620 161.367 C 295.239 121.807,237.531 121.949,231.235 161.540 C 231.013 162.937,230.622 164.332,230.367 164.640 C 229.717 165.423,188.328 165.481,187.689 164.700 C 187.463 164.425,186.981 162.602,186.617 160.650 C 183.194 142.288,166.648 129.850,148.000 131.622 M159.886 135.622 C 183.880 141.759,192.035 172.033,174.435 189.636 C 156.404 207.671,125.892 198.962,119.944 174.084 C 114.368 150.761,136.343 129.601,159.886 135.622 M274.658 135.615 C 299.082 141.861,307.061 172.817,288.734 190.222 C 267.975 209.936,234.188 195.420,234.219 166.800 C 234.241 145.502,253.935 130.315,274.658 135.615 M148.542 152.793 C 139.499 154.706,134.598 164.925,138.715 173.287 C 145.082 186.221,164.875 182.425,165.902 168.074 C 166.591 158.446,157.916 150.811,148.542 152.793 M262.091 153.188 C 253.922 156.127,249.883 165.408,253.408 173.139 C 257.835 182.850,271.593 184.491,278.201 176.097 C 287.389 164.426,275.974 148.192,262.091 153.188 M204.900 197.805 C 201.561 201.450,199.643 201.993,193.600 201.001 C 191.555 200.665,190.824 201.267,191.600 202.647 C 193.561 206.136,200.180 206.022,205.600 202.405 C 207.846 200.906,208.312 200.907,210.779 202.425 C 216.333 205.843,221.899 206.089,224.310 203.023 C 225.846 201.071,225.236 200.759,220.447 201.050 C 215.394 201.357,214.247 200.942,211.015 197.632 C 208.352 194.906,207.534 194.929,204.900 197.805 "
-      stroke="none" fill="#ffffff" fill-rule="evenodd"></path>
-  </g>
-</svg>
diff --git a/src/assets/styles/index.scss b/src/assets/styles/index.scss
deleted file mode 100644
index 2fdcc9e7005d582561ba8b8ab7f835164eb38c85..0000000000000000000000000000000000000000
--- a/src/assets/styles/index.scss
+++ /dev/null
@@ -1,50 +0,0 @@
-body {
-  margin: 0;
-  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
-    "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
-    sans-serif;
-  -webkit-font-smoothing: antialiased;
-
-  user-select: none;
-  -webkit-user-select: none;
-  -moz-user-select: none;
-  -ms-user-select: none;
-}
-
-:root {
-  --primary-main: #5b5c9d;
-  --text-primary: #637381;
-  --selection-color: #f5f5f5;
-  --scroller-color: #90939980;
-}
-
-::selection {
-  color: var(--selection-color);
-  background-color: var(--primary-main);
-}
-
-*::-webkit-scrollbar {
-  width: 6px;
-  height: 6px;
-  background: transparent;
-}
-*::-webkit-scrollbar-thumb {
-  border-radius: 6px;
-  background-color: var(--scroller-color);
-}
-
-@import "./layout.scss";
-@import "./page.scss";
-
-@media (prefers-color-scheme: dark) {
-  :root {
-    background-color: rgba(18, 18, 18, 1);
-  }
-}
-
-.user-none {
-  user-select: none;
-  -webkit-user-select: none;
-  -moz-user-select: none;
-  -ms-user-select: none;
-}
diff --git a/src/assets/styles/layout.scss b/src/assets/styles/layout.scss
deleted file mode 100644
index 3d16c864a691f548475692a67c5c9994013524f6..0000000000000000000000000000000000000000
--- a/src/assets/styles/layout.scss
+++ /dev/null
@@ -1,117 +0,0 @@
-.layout {
-  width: 100%;
-  height: 100vh;
-  display: flex;
-  overflow: hidden;
-
-  &__left {
-    flex: 1 0 25%;
-    display: flex;
-    height: 100%;
-    max-width: 225px;
-    min-width: 125px;
-    padding: 16px 0 8px;
-    flex-direction: column;
-    box-sizing: border-box;
-    user-select: none;
-    -webkit-user-select: none;
-    -moz-user-select: none;
-    -ms-user-select: none;
-    overflow: hidden;
-
-    $maxLogo: 100px;
-
-    .the-logo {
-      position: relative;
-      flex: 0 1 $maxLogo;
-      width: 100%;
-      max-width: $maxLogo + 32px;
-      max-height: $maxLogo;
-      margin: 0 auto;
-      padding: 0 16px;
-      text-align: center;
-      box-sizing: border-box;
-
-      img,
-      svg {
-        width: 100%;
-        height: 100%;
-        pointer-events: none;
-      }
-
-      .the-newbtn {
-        position: absolute;
-        right: 10px;
-        bottom: 0px;
-        transform: scale(0.8);
-      }
-    }
-
-    .the-menu {
-      flex: 1 1 80%;
-      overflow-y: auto;
-      margin-bottom: 8px;
-    }
-
-    .the-traffic {
-      flex: 0 0 60px;
-
-      > div {
-        margin: 0 auto;
-      }
-    }
-  }
-
-  &__right {
-    position: relative;
-    flex: 1 1 75%;
-    height: 100%;
-
-    .the-bar {
-      position: absolute;
-      top: 2px;
-      right: 8px;
-      height: 36px;
-      display: flex;
-      align-items: center;
-      box-sizing: border-box;
-      z-index: 2;
-    }
-
-    .the-content {
-      position: absolute;
-      top: 0;
-      left: 0;
-      right: 2px;
-      bottom: 10px;
-    }
-  }
-}
-
-.linux,
-.windows,
-.unknown {
-  &.layout {
-    $maxLogo: 115px;
-    .layout__left .the-logo {
-      flex: 0 1 $maxLogo;
-      max-width: $maxLogo + 32px;
-      max-height: $maxLogo;
-    }
-
-    .layout__right .the-content {
-      top: 30px;
-    }
-  }
-}
-
-.macos {
-  &.layout {
-    .layout__left {
-      padding-top: 24px;
-    }
-    .layout__right .the-content {
-      top: 20px;
-    }
-  }
-}
diff --git a/src/assets/styles/page.scss b/src/assets/styles/page.scss
deleted file mode 100644
index ae7fce373a6abaee9da47c9ea1c2e05072621fda..0000000000000000000000000000000000000000
--- a/src/assets/styles/page.scss
+++ /dev/null
@@ -1,35 +0,0 @@
-.base-page {
-  width: 100%;
-  height: 100%;
-  display: flex;
-  flex-direction: column;
-
-  > header {
-    flex: 0 0 58px;
-    width: 90%;
-    // max-width: 850px;
-    margin: 0 auto;
-    padding-right: 4px;
-    box-sizing: border-box;
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-  }
-
-  > section {
-    position: relative;
-    flex: 1 1 100%;
-    width: 100%;
-    height: 100%;
-    overflow: auto;
-    padding: 8px 0;
-    box-sizing: border-box;
-    scrollbar-gutter: stable;
-
-    .base-content {
-      width: 90%;
-      // max-width: 850px;
-      margin: 0 auto;
-    }
-  }
-}
diff --git a/src/components/base/base-dialog.tsx b/src/components/base/base-dialog.tsx
deleted file mode 100644
index db4226c6b0521ff63193343a4529fbf3ef99101f..0000000000000000000000000000000000000000
--- a/src/components/base/base-dialog.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import { ReactNode } from "react";
-import {
-  Button,
-  Dialog,
-  DialogActions,
-  DialogContent,
-  DialogTitle,
-  type SxProps,
-  type Theme,
-} from "@mui/material";
-
-interface Props {
-  title: ReactNode;
-  open: boolean;
-  okBtn?: ReactNode;
-  cancelBtn?: ReactNode;
-  disableOk?: boolean;
-  disableCancel?: boolean;
-  disableFooter?: boolean;
-  contentSx?: SxProps<Theme>;
-  children?: ReactNode;
-  onOk?: () => void;
-  onCancel?: () => void;
-  onClose?: () => void;
-}
-
-export interface DialogRef {
-  open: () => void;
-  close: () => void;
-}
-
-export const BaseDialog: React.FC<Props> = (props) => {
-  const {
-    open,
-    title,
-    children,
-    okBtn,
-    cancelBtn,
-    contentSx,
-    disableCancel,
-    disableOk,
-    disableFooter,
-  } = props;
-
-  return (
-    <Dialog open={open} onClose={props.onClose}>
-      <DialogTitle>{title}</DialogTitle>
-
-      <DialogContent sx={contentSx}>{children}</DialogContent>
-
-      {!disableFooter && (
-        <DialogActions>
-          {!disableCancel && (
-            <Button variant="outlined" onClick={props.onCancel}>
-              {cancelBtn}
-            </Button>
-          )}
-          {!disableOk && (
-            <Button variant="contained" onClick={props.onOk}>
-              {okBtn}
-            </Button>
-          )}
-        </DialogActions>
-      )}
-    </Dialog>
-  );
-};
diff --git a/src/components/base/base-empty.tsx b/src/components/base/base-empty.tsx
deleted file mode 100644
index c364a50ab72b1c486b2b4b55941d9060116de876..0000000000000000000000000000000000000000
--- a/src/components/base/base-empty.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { alpha, Box, Typography } from "@mui/material";
-import { InboxRounded } from "@mui/icons-material";
-
-interface Props {
-  text?: React.ReactNode;
-  extra?: React.ReactNode;
-}
-
-export const BaseEmpty = (props: Props) => {
-  const { text = "Empty", extra } = props;
-
-  return (
-    <Box
-      sx={({ palette }) => ({
-        width: "100%",
-        height: "100%",
-        display: "flex",
-        flexDirection: "column",
-        alignItems: "center",
-        justifyContent: "center",
-        color: alpha(palette.text.secondary, 0.75),
-      })}
-    >
-      <InboxRounded sx={{ fontSize: "4em" }} />
-      <Typography sx={{ fontSize: "1.25em" }}>{text}</Typography>
-      {extra}
-    </Box>
-  );
-};
diff --git a/src/components/base/base-error-boundary.tsx b/src/components/base/base-error-boundary.tsx
deleted file mode 100644
index 2475a2ffdff3aba17391c6785083e0592d77009f..0000000000000000000000000000000000000000
--- a/src/components/base/base-error-boundary.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { ReactNode } from "react";
-import { ErrorBoundary, FallbackProps } from "react-error-boundary";
-
-function ErrorFallback({ error }: FallbackProps) {
-  return (
-    <div role="alert" style={{ padding: 16 }}>
-      <h4>Something went wrong:(</h4>
-
-      <pre>{error.message}</pre>
-
-      <details title="Error Stack">
-        <summary>Error Stack</summary>
-        <pre>{error.stack}</pre>
-      </details>
-    </div>
-  );
-}
-
-interface Props {
-  children?: ReactNode;
-}
-
-export const BaseErrorBoundary = (props: Props) => {
-  return (
-    <ErrorBoundary FallbackComponent={ErrorFallback}>
-      {props.children}
-    </ErrorBoundary>
-  );
-};
diff --git a/src/components/base/base-loading.tsx b/src/components/base/base-loading.tsx
deleted file mode 100644
index 0fdbebf1e579a7d5b925a3295a21362255bb9758..0000000000000000000000000000000000000000
--- a/src/components/base/base-loading.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { styled } from "@mui/material";
-
-const Loading = styled("div")`
-  position: relative;
-  display: flex;
-  height: 100%;
-  min-height: 18px;
-  box-sizing: border-box;
-  align-items: center;
-
-  & > div {
-    box-sizing: border-box;
-    width: 6px;
-    height: 6px;
-    margin: 2px;
-    border-radius: 100%;
-    animation: loading 0.7s -0.15s infinite linear;
-  }
-
-  & > div:nth-child(2n-1) {
-    animation-delay: -0.5s;
-  }
-
-  @keyframes loading {
-    50% {
-      opacity: 0.2;
-      transform: scale(0.75);
-    }
-    100% {
-      opacity: 1;
-      transform: scale(1);
-    }
-  }
-`;
-
-const LoadingItem = styled("div")(({ theme }) => ({
-  background: theme.palette.text.secondary,
-}));
-
-export const BaseLoading = () => {
-  return (
-    <Loading>
-      <LoadingItem />
-      <LoadingItem />
-      <LoadingItem />
-    </Loading>
-  );
-};
diff --git a/src/components/base/base-notice.tsx b/src/components/base/base-notice.tsx
deleted file mode 100644
index 58490344dd0011fe3ac4645f171cb473f3f10515..0000000000000000000000000000000000000000
--- a/src/components/base/base-notice.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import { createRoot } from "react-dom/client";
-import { ReactNode, useState } from "react";
-import { Box, IconButton, Slide, Snackbar, Typography } from "@mui/material";
-import { Close, CheckCircleRounded, ErrorRounded } from "@mui/icons-material";
-
-interface InnerProps {
-  type: string;
-  duration?: number;
-  message: ReactNode;
-  onClose: () => void;
-}
-
-const NoticeInner = (props: InnerProps) => {
-  const { type, message, duration = 1500, onClose } = props;
-  const [visible, setVisible] = useState(true);
-
-  const onBtnClose = () => {
-    setVisible(false);
-    onClose();
-  };
-  const onAutoClose = (_e: any, reason: string) => {
-    if (reason !== "clickaway") onBtnClose();
-  };
-
-  const msgElement =
-    type === "info" ? (
-      message
-    ) : (
-      <Box sx={{ width: 328, display: "flex", alignItems: "center" }}>
-        {type === "error" && <ErrorRounded color="error" />}
-        {type === "success" && <CheckCircleRounded color="success" />}
-
-        <Typography
-          component="span"
-          sx={{ ml: 1, wordWrap: "break-word", width: "calc(100% - 35px)" }}
-        >
-          {message}
-        </Typography>
-      </Box>
-    );
-
-  return (
-    <Snackbar
-      open={visible}
-      anchorOrigin={{ vertical: "top", horizontal: "right" }}
-      autoHideDuration={duration}
-      onClose={onAutoClose}
-      message={msgElement}
-      sx={{ maxWidth: 360 }}
-      TransitionComponent={(p) => <Slide {...p} direction="left" />}
-      transitionDuration={200}
-      action={
-        <IconButton size="small" color="inherit" onClick={onBtnClose}>
-          <Close fontSize="inherit" />
-        </IconButton>
-      }
-    />
-  );
-};
-
-interface NoticeInstance {
-  (props: Omit<InnerProps, "onClose">): void;
-
-  info(message: ReactNode, duration?: number): void;
-  error(message: ReactNode, duration?: number): void;
-  success(message: ReactNode, duration?: number): void;
-}
-
-let parent: HTMLDivElement = null!;
-
-// @ts-ignore
-export const Notice: NoticeInstance = (props) => {
-  if (!parent) {
-    parent = document.createElement("div");
-    document.body.appendChild(parent);
-  }
-
-  const container = document.createElement("div");
-  parent.appendChild(container);
-  const root = createRoot(container);
-
-  const onUnmount = () => {
-    root.unmount();
-    if (parent) setTimeout(() => parent.removeChild(container), 500);
-  };
-
-  root.render(<NoticeInner {...props} onClose={onUnmount} />);
-};
-
-(["info", "error", "success"] as const).forEach((type) => {
-  Notice[type] = (message, duration) => {
-    setTimeout(() => Notice({ type, message, duration }), 0);
-  };
-});
diff --git a/src/components/base/base-page.tsx b/src/components/base/base-page.tsx
deleted file mode 100644
index 869731af58e4256d6a7b8fafeca2a62c817b0eca..0000000000000000000000000000000000000000
--- a/src/components/base/base-page.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import React, { ReactNode } from "react";
-import { Typography } from "@mui/material";
-import { BaseErrorBoundary } from "./base-error-boundary";
-
-interface Props {
-  title?: React.ReactNode; // the page title
-  header?: React.ReactNode; // something behind title
-  contentStyle?: React.CSSProperties;
-  children?: ReactNode;
-}
-
-export const BasePage: React.FC<Props> = (props) => {
-  const { title, header, contentStyle, children } = props;
-
-  return (
-    <BaseErrorBoundary>
-      <div className="base-page" data-windrag>
-        <header data-windrag style={{ userSelect: "none" }}>
-          <Typography variant="h4" component="h1" data-windrag>
-            {title}
-          </Typography>
-
-          {header}
-        </header>
-
-        <section>
-          <div className="base-content" style={contentStyle} data-windrag>
-            {children}
-          </div>
-        </section>
-      </div>
-    </BaseErrorBoundary>
-  );
-};
diff --git a/src/components/base/index.ts b/src/components/base/index.ts
deleted file mode 100644
index 3e0e32403a5d0b52d0dc8ecb374fcf127c637dfd..0000000000000000000000000000000000000000
--- a/src/components/base/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export { BaseDialog, type DialogRef } from "./base-dialog";
-export { BasePage } from "./base-page";
-export { BaseEmpty } from "./base-empty";
-export { BaseLoading } from "./base-loading";
-export { BaseErrorBoundary } from "./base-error-boundary";
-export { Notice } from "./base-notice";
diff --git a/src/components/connection/connection-detail.tsx b/src/components/connection/connection-detail.tsx
deleted file mode 100644
index 7ed786e2e24b1acef78f67f5a72f771359c600a7..0000000000000000000000000000000000000000
--- a/src/components/connection/connection-detail.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import dayjs from "dayjs";
-import { forwardRef, useImperativeHandle, useState } from "react";
-import { useLockFn } from "ahooks";
-import { Box, Button, Snackbar } from "@mui/material";
-import { deleteConnection } from "@/services/api";
-import { truncateStr } from "@/utils/truncate-str";
-import parseTraffic from "@/utils/parse-traffic";
-
-export interface ConnectionDetailRef {
-  open: (detail: IConnectionsItem) => void;
-}
-
-export const ConnectionDetail = forwardRef<ConnectionDetailRef>(
-  (props, ref) => {
-    const [open, setOpen] = useState(false);
-    const [detail, setDetail] = useState<IConnectionsItem>(null!);
-
-    useImperativeHandle(ref, () => ({
-      open: (detail: IConnectionsItem) => {
-        if (open) return;
-        setOpen(true);
-        setDetail(detail);
-      },
-    }));
-
-    const onClose = () => setOpen(false);
-
-    return (
-      <Snackbar
-        anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
-        open={open}
-        onClose={onClose}
-        message={
-          detail ? (
-            <InnerConnectionDetail data={detail} onClose={onClose} />
-          ) : null
-        }
-      />
-    );
-  }
-);
-
-interface InnerProps {
-  data: IConnectionsItem;
-  onClose?: () => void;
-}
-
-const InnerConnectionDetail = ({ data, onClose }: InnerProps) => {
-  const { metadata, rulePayload } = data;
-  const chains = [...data.chains].reverse().join(" / ");
-  const rule = rulePayload ? `${data.rule}(${rulePayload})` : data.rule;
-  const host = metadata.host
-    ? `${metadata.host}:${metadata.destinationPort}`
-    : `${metadata.destinationIP}:${metadata.destinationPort}`;
-
-  const information = [
-    { label: "Host", value: host },
-    { label: "Download", value: parseTraffic(data.download).join(" ") },
-    { label: "Upload", value: parseTraffic(data.upload).join(" ") },
-    {
-      label: "DL Speed",
-      value: parseTraffic(data.curDownload ?? -1).join(" ") + "/s",
-    },
-    {
-      label: "UL Speed",
-      value: parseTraffic(data.curUpload ?? -1).join(" ") + "/s",
-    },
-    { label: "Chains", value: chains },
-    { label: "Rule", value: rule },
-    {
-      label: "Process",
-      value: truncateStr(metadata.process || metadata.processPath),
-    },
-    { label: "Time", value: dayjs(data.start).fromNow() },
-    { label: "Source", value: `${metadata.sourceIP}:${metadata.sourcePort}` },
-    { label: "Destination IP", value: metadata.destinationIP },
-    { label: "Type", value: `${metadata.type}(${metadata.network})` },
-  ];
-
-  const onDelete = useLockFn(async () => deleteConnection(data.id));
-
-  return (
-    <Box sx={{ userSelect: "text" }}>
-      {information.map((each) => (
-        <div key={each.label}>
-          <b>{each.label}</b>: <span>{each.value}</span>
-        </div>
-      ))}
-
-      <Box sx={{ textAlign: "right" }}>
-        <Button
-          variant="contained"
-          title="Close Connection"
-          onClick={() => {
-            onDelete();
-            onClose?.();
-          }}
-        >
-          Close
-        </Button>
-      </Box>
-    </Box>
-  );
-};
diff --git a/src/components/connection/connection-item.tsx b/src/components/connection/connection-item.tsx
deleted file mode 100644
index d6c78eb01f01b9204877409f98e8f5f7e38584c1..0000000000000000000000000000000000000000
--- a/src/components/connection/connection-item.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import dayjs from "dayjs";
-import { useLockFn } from "ahooks";
-import {
-  styled,
-  ListItem,
-  IconButton,
-  ListItemText,
-  Box,
-  alpha,
-} from "@mui/material";
-import { CloseRounded } from "@mui/icons-material";
-import { deleteConnection } from "@/services/api";
-import parseTraffic from "@/utils/parse-traffic";
-
-const Tag = styled("span")(({ theme }) => ({
-  fontSize: "10px",
-  padding: "0 4px",
-  lineHeight: 1.375,
-  border: "1px solid",
-  borderRadius: 4,
-  borderColor: alpha(theme.palette.text.secondary, 0.35),
-  marginRight: "4px",
-}));
-
-interface Props {
-  value: IConnectionsItem;
-  onShowDetail?: () => void;
-}
-
-export const ConnectionItem = (props: Props) => {
-  const { value, onShowDetail } = props;
-
-  const { id, metadata, chains, start, curUpload, curDownload } = value;
-
-  const onDelete = useLockFn(async () => deleteConnection(id));
-  const showTraffic = curUpload! >= 100 || curDownload! >= 100;
-
-  return (
-    <ListItem
-      dense
-      secondaryAction={
-        <IconButton edge="end" color="inherit" onClick={onDelete}>
-          <CloseRounded />
-        </IconButton>
-      }
-    >
-      <ListItemText
-        sx={{ userSelect: "text", cursor: "pointer" }}
-        primary={metadata.host || metadata.destinationIP}
-        onClick={onShowDetail}
-        secondary={
-          <Box sx={{ display: "flex", flexWrap: "wrap" }}>
-            <Tag sx={{ textTransform: "uppercase", color: "success" }}>
-              {metadata.network}
-            </Tag>
-
-            <Tag>{metadata.type}</Tag>
-
-            {!!metadata.process && <Tag>{metadata.process}</Tag>}
-
-            {chains?.length > 0 && <Tag>{chains[value.chains.length - 1]}</Tag>}
-
-            <Tag>{dayjs(start).fromNow()}</Tag>
-
-            {showTraffic && (
-              <Tag>
-                {parseTraffic(curUpload!)} / {parseTraffic(curDownload!)}
-              </Tag>
-            )}
-          </Box>
-        }
-      />
-    </ListItem>
-  );
-};
diff --git a/src/components/connection/connection-table.tsx b/src/components/connection/connection-table.tsx
deleted file mode 100644
index 143bf9f65baa887c2c892db99f042ee3705d1599..0000000000000000000000000000000000000000
--- a/src/components/connection/connection-table.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-import dayjs from "dayjs";
-import { useMemo, useState } from "react";
-import { DataGrid, GridColDef } from "@mui/x-data-grid";
-import { truncateStr } from "@/utils/truncate-str";
-import parseTraffic from "@/utils/parse-traffic";
-
-interface Props {
-  connections: IConnectionsItem[];
-  onShowDetail: (data: IConnectionsItem) => void;
-}
-
-export const ConnectionTable = (props: Props) => {
-  const { connections, onShowDetail } = props;
-
-  const [columnVisible, setColumnVisible] = useState<
-    Partial<Record<keyof IConnectionsItem, boolean>>
-  >({});
-
-  const columns: GridColDef[] = [
-    { field: "host", headerName: "Host", flex: 220, minWidth: 220 },
-    {
-      field: "download",
-      headerName: "Download",
-      width: 88,
-      align: "right",
-      headerAlign: "right",
-    },
-    {
-      field: "upload",
-      headerName: "Upload",
-      width: 88,
-      align: "right",
-      headerAlign: "right",
-    },
-    {
-      field: "dlSpeed",
-      headerName: "DL Speed",
-      width: 88,
-      align: "right",
-      headerAlign: "right",
-    },
-    {
-      field: "ulSpeed",
-      headerName: "UL Speed",
-      width: 88,
-      align: "right",
-      headerAlign: "right",
-    },
-    { field: "chains", headerName: "Chains", flex: 360, minWidth: 360 },
-    { field: "rule", headerName: "Rule", flex: 300, minWidth: 250 },
-    { field: "process", headerName: "Process", flex: 480, minWidth: 480 },
-    {
-      field: "time",
-      headerName: "Time",
-      flex: 120,
-      minWidth: 100,
-      align: "right",
-      headerAlign: "right",
-    },
-    { field: "source", headerName: "Source", flex: 200, minWidth: 130 },
-    {
-      field: "destinationIP",
-      headerName: "Destination IP",
-      flex: 200,
-      minWidth: 130,
-    },
-    { field: "type", headerName: "Type", flex: 160, minWidth: 100 },
-  ];
-
-  const connRows = useMemo(() => {
-    return connections.map((each) => {
-      const { metadata, rulePayload } = each;
-      const chains = [...each.chains].reverse().join(" / ");
-      const rule = rulePayload ? `${each.rule}(${rulePayload})` : each.rule;
-
-      return {
-        id: each.id,
-        host: metadata.host
-          ? `${metadata.host}:${metadata.destinationPort}`
-          : `${metadata.destinationIP}:${metadata.destinationPort}`,
-        download: parseTraffic(each.download).join(" "),
-        upload: parseTraffic(each.upload).join(" "),
-        dlSpeed: parseTraffic(each.curDownload).join(" ") + "/s",
-        ulSpeed: parseTraffic(each.curUpload).join(" ") + "/s",
-        chains,
-        rule,
-        process: truncateStr(metadata.process || metadata.processPath),
-        time: dayjs(each.start).fromNow(),
-        source: `${metadata.sourceIP}:${metadata.sourcePort}`,
-        destinationIP: metadata.destinationIP,
-        type: `${metadata.type}(${metadata.network})`,
-
-        connectionData: each,
-      };
-    });
-  }, [connections]);
-
-  return (
-    <DataGrid
-      hideFooter
-      rows={connRows}
-      columns={columns}
-      onRowClick={(e) => onShowDetail(e.row.connectionData)}
-      density="compact"
-      sx={{ border: "none", "div:focus": { outline: "none !important" } }}
-      columnVisibilityModel={columnVisible}
-      onColumnVisibilityModelChange={(e) => setColumnVisible(e)}
-    />
-  );
-};
diff --git a/src/components/layout/layout-control.tsx b/src/components/layout/layout-control.tsx
deleted file mode 100644
index 6ec12b970a695f17570bf289570765fbb648d827..0000000000000000000000000000000000000000
--- a/src/components/layout/layout-control.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { Button } from "@mui/material";
-import { appWindow } from "@tauri-apps/api/window";
-import {
-  CloseRounded,
-  CropSquareRounded,
-  HorizontalRuleRounded,
-} from "@mui/icons-material";
-
-export const LayoutControl = () => {
-  const minWidth = 40;
-
-  return (
-    <>
-      <Button
-        size="small"
-        sx={{ minWidth, svg: { transform: "scale(0.9)" } }}
-        onClick={() => appWindow.minimize()}
-      >
-        <HorizontalRuleRounded fontSize="small" />
-      </Button>
-
-      <Button
-        size="small"
-        sx={{ minWidth, svg: { transform: "scale(0.9)" } }}
-        onClick={() => appWindow.toggleMaximize()}
-      >
-        <CropSquareRounded fontSize="small" />
-      </Button>
-
-      <Button
-        size="small"
-        sx={{ minWidth, svg: { transform: "scale(1.05)" } }}
-        onClick={() => appWindow.close()}
-      >
-        <CloseRounded fontSize="small" />
-      </Button>
-    </>
-  );
-};
diff --git a/src/components/layout/layout-item.tsx b/src/components/layout/layout-item.tsx
deleted file mode 100644
index 5a33da22a38e91e505444a88b4c20c610a959240..0000000000000000000000000000000000000000
--- a/src/components/layout/layout-item.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { alpha, ListItem, ListItemButton, ListItemText } from "@mui/material";
-import { useMatch, useResolvedPath, useNavigate } from "react-router-dom";
-import type { LinkProps } from "react-router-dom";
-
-export const LayoutItem = (props: LinkProps) => {
-  const { to, children } = props;
-
-  const resolved = useResolvedPath(to);
-  const match = useMatch({ path: resolved.pathname, end: true });
-  const navigate = useNavigate();
-
-  return (
-    <ListItem sx={{ py: 0.5, maxWidth: 250, mx: "auto" }}>
-      <ListItemButton
-        selected={!!match}
-        sx={[
-          {
-            borderRadius: 2,
-            textAlign: "center",
-            "& .MuiListItemText-primary": { color: "text.secondary" },
-          },
-          ({ palette: { mode, primary } }) => {
-            const bgcolor =
-              mode === "light"
-                ? alpha(primary.main, 0.15)
-                : alpha(primary.main, 0.35);
-            const color = mode === "light" ? primary.main : primary.light;
-
-            return {
-              "&.Mui-selected": { bgcolor },
-              "&.Mui-selected:hover": { bgcolor },
-              "&.Mui-selected .MuiListItemText-primary": { color },
-            };
-          },
-        ]}
-        onClick={() => navigate(to)}
-      >
-        <ListItemText primary={children} />
-      </ListItemButton>
-    </ListItem>
-  );
-};
diff --git a/src/components/layout/layout-traffic.tsx b/src/components/layout/layout-traffic.tsx
deleted file mode 100644
index 4e65a87059e68473b0d3d80c6cf6879d53938960..0000000000000000000000000000000000000000
--- a/src/components/layout/layout-traffic.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-import { useEffect, useRef, useState } from "react";
-import { Box, Typography } from "@mui/material";
-import {
-  ArrowDownward,
-  ArrowUpward,
-  MemoryOutlined,
-} from "@mui/icons-material";
-import { useClashInfo } from "@/hooks/use-clash";
-import { useVerge } from "@/hooks/use-verge";
-import { TrafficGraph, type TrafficRef } from "./traffic-graph";
-import { useLogSetup } from "./use-log-setup";
-import { useVisibility } from "@/hooks/use-visibility";
-import { useWebsocket } from "@/hooks/use-websocket";
-import parseTraffic from "@/utils/parse-traffic";
-
-// setup the traffic
-export const LayoutTraffic = () => {
-  const { clashInfo } = useClashInfo();
-  const { verge } = useVerge();
-
-  // whether hide traffic graph
-  const trafficGraph = verge?.traffic_graph ?? true;
-
-  const trafficRef = useRef<TrafficRef>(null);
-  const [traffic, setTraffic] = useState({ up: 0, down: 0 });
-  const [memory, setMemory] = useState({ inuse: 0 });
-  const pageVisible = useVisibility();
-
-  // setup log ws during layout
-  useLogSetup();
-
-  const { connect, disconnect } = useWebsocket((event) => {
-    const data = JSON.parse(event.data) as ITrafficItem;
-    trafficRef.current?.appendData(data);
-    setTraffic(data);
-  });
-
-  useEffect(() => {
-    if (!clashInfo || !pageVisible) return;
-
-    const { server = "", secret = "" } = clashInfo;
-    connect(`ws://${server}/traffic?token=${encodeURIComponent(secret)}`);
-
-    return () => {
-      disconnect();
-    };
-  }, [clashInfo, pageVisible]);
-
-  /* --------- meta memory information --------- */
-  const isMetaCore = verge?.clash_core === "clash-meta";
-  const displayMemory = isMetaCore && (verge?.enable_memory_usage ?? true);
-
-  const memoryWs = useWebsocket(
-    (event) => {
-      setMemory(JSON.parse(event.data));
-    },
-    { onError: () => setMemory({ inuse: 0 }) }
-  );
-
-  useEffect(() => {
-    if (!clashInfo || !pageVisible || !displayMemory) return;
-    const { server = "", secret = "" } = clashInfo;
-    memoryWs.connect(
-      `ws://${server}/memory?token=${encodeURIComponent(secret)}`
-    );
-    return () => memoryWs.disconnect();
-  }, [clashInfo, pageVisible, displayMemory]);
-
-  const [up, upUnit] = parseTraffic(traffic.up);
-  const [down, downUnit] = parseTraffic(traffic.down);
-  const [inuse, inuseUnit] = parseTraffic(memory.inuse);
-
-  const iconStyle: any = {
-    sx: { mr: "8px", fontSize: 16 },
-  };
-  const valStyle: any = {
-    component: "span",
-    color: "primary",
-    textAlign: "center",
-    sx: { flex: "1 1 56px", userSelect: "none" },
-  };
-  const unitStyle: any = {
-    component: "span",
-    color: "grey.500",
-    fontSize: "12px",
-    textAlign: "right",
-    sx: { flex: "0 1 27px", userSelect: "none" },
-  };
-
-  return (
-    <Box
-      width="110px"
-      position="relative"
-      onClick={trafficRef.current?.toggleStyle}
-    >
-      {trafficGraph && pageVisible && (
-        <div style={{ width: "100%", height: 60, marginBottom: 6 }}>
-          <TrafficGraph ref={trafficRef} />
-        </div>
-      )}
-
-      <Box display="flex" flexDirection="column" gap={0.75}>
-        <Box display="flex" alignItems="center" whiteSpace="nowrap">
-          <ArrowUpward
-            {...iconStyle}
-            color={+up > 0 ? "primary" : "disabled"}
-          />
-          <Typography {...valStyle}>{up}</Typography>
-          <Typography {...unitStyle}>{upUnit}/s</Typography>
-        </Box>
-
-        <Box display="flex" alignItems="center" whiteSpace="nowrap">
-          <ArrowDownward
-            {...iconStyle}
-            color={+down > 0 ? "primary" : "disabled"}
-          />
-          <Typography {...valStyle}>{down}</Typography>
-          <Typography {...unitStyle}>{downUnit}/s</Typography>
-        </Box>
-
-        {displayMemory && (
-          <Box
-            display="flex"
-            alignItems="center"
-            whiteSpace="nowrap"
-            title="Memory Usage"
-          >
-            <MemoryOutlined {...iconStyle} color="disabled" />
-            <Typography {...valStyle}>{inuse}</Typography>
-            <Typography {...unitStyle}>{inuseUnit}</Typography>
-          </Box>
-        )}
-      </Box>
-    </Box>
-  );
-};
diff --git a/src/components/layout/traffic-graph.tsx b/src/components/layout/traffic-graph.tsx
deleted file mode 100644
index 5c1a6b7ef9687e9ebe938408ce098e52296523a4..0000000000000000000000000000000000000000
--- a/src/components/layout/traffic-graph.tsx
+++ /dev/null
@@ -1,195 +0,0 @@
-import { forwardRef, useEffect, useImperativeHandle, useRef } from "react";
-import { useTheme } from "@mui/material";
-
-const maxPoint = 30;
-
-const refLineAlpha = 1;
-const refLineWidth = 2;
-
-const upLineAlpha = 0.6;
-const upLineWidth = 4;
-
-const downLineAlpha = 1;
-const downLineWidth = 4;
-
-const defaultList = Array(maxPoint + 2).fill({ up: 0, down: 0 });
-
-type TrafficData = { up: number; down: number };
-
-export interface TrafficRef {
-  appendData: (data: TrafficData) => void;
-  toggleStyle: () => void;
-}
-
-/**
- * draw the traffic graph
- */
-export const TrafficGraph = forwardRef<TrafficRef>((props, ref) => {
-  const countRef = useRef(0);
-  const styleRef = useRef(true);
-  const listRef = useRef<TrafficData[]>(defaultList);
-  const canvasRef = useRef<HTMLCanvasElement>(null!);
-
-  const cacheRef = useRef<TrafficData | null>(null);
-
-  const { palette } = useTheme();
-
-  useImperativeHandle(ref, () => ({
-    appendData: (data: TrafficData) => {
-      cacheRef.current = data;
-    },
-    toggleStyle: () => {
-      styleRef.current = !styleRef.current;
-    },
-  }));
-
-  useEffect(() => {
-    let timer: any;
-    const zero = { up: 0, down: 0 };
-
-    const handleData = () => {
-      const data = cacheRef.current ? cacheRef.current : zero;
-      cacheRef.current = null;
-
-      const list = listRef.current;
-      if (list.length > maxPoint + 2) list.shift();
-      list.push(data);
-      countRef.current = 0;
-
-      timer = setTimeout(handleData, 1000);
-    };
-
-    handleData();
-
-    return () => {
-      if (timer) clearTimeout(timer);
-    };
-  }, []);
-
-  useEffect(() => {
-    let raf = 0;
-    const canvas = canvasRef.current!;
-
-    if (!canvas) return;
-
-    const context = canvas.getContext("2d")!;
-
-    if (!context) return;
-
-    const { primary, secondary, divider } = palette;
-    const refLineColor = divider || "rgba(0, 0, 0, 0.12)";
-    const upLineColor = secondary.main || "#9c27b0";
-    const downLineColor = primary.main || "#5b5c9d";
-
-    const width = canvas.width;
-    const height = canvas.height;
-    const dx = width / maxPoint;
-    const dy = height / 7;
-    const l1 = dy;
-    const l2 = dy * 4;
-
-    const countY = (v: number) => {
-      const h = height;
-
-      if (v == 0) return h - 1;
-      if (v <= 10) return h - (v / 10) * dy;
-      if (v <= 100) return h - (v / 100 + 1) * dy;
-      if (v <= 1024) return h - (v / 1024 + 2) * dy;
-      if (v <= 10240) return h - (v / 10240 + 3) * dy;
-      if (v <= 102400) return h - (v / 102400 + 4) * dy;
-      if (v <= 1048576) return h - (v / 1048576 + 5) * dy;
-      if (v <= 10485760) return h - (v / 10485760 + 6) * dy;
-      return 1;
-    };
-
-    const drawBezier = (list: number[], offset: number) => {
-      const points = list.map((y, i) => [
-        (dx * (i - 1) - offset + 3) | 0,
-        countY(y),
-      ]);
-
-      let x = points[0][0];
-      let y = points[0][1];
-
-      context.moveTo(x, y);
-
-      for (let i = 1; i < points.length; i++) {
-        const p1 = points[i];
-        const p2 = points[i + 1] || p1;
-
-        const x1 = (p1[0] + p2[0]) / 2;
-        const y1 = (p1[1] + p2[1]) / 2;
-
-        context.quadraticCurveTo(p1[0], p1[1], x1, y1);
-        x = x1;
-        y = y1;
-      }
-    };
-
-    const drawLine = (list: number[], offset: number) => {
-      const points = list.map((y, i) => [
-        (dx * (i - 1) - offset) | 0,
-        countY(y),
-      ]);
-
-      context.moveTo(points[0][0], points[0][1]);
-
-      for (let i = 1; i < points.length; i++) {
-        const p = points[i];
-        context.lineTo(p[0], p[1]);
-      }
-    };
-
-    const drawGraph = (lastTime: number) => {
-      const listUp = listRef.current.map((v) => v.up);
-      const listDown = listRef.current.map((v) => v.down);
-      const lineStyle = styleRef.current;
-
-      const now = Date.now();
-      const diff = now - lastTime;
-      const temp = Math.min((diff / 1000) * dx + countRef.current, dx);
-      const offset = countRef.current === 0 ? 0 : temp;
-      countRef.current = temp;
-
-      context.clearRect(0, 0, width, height);
-
-      // Reference lines
-      context.beginPath();
-      context.globalAlpha = refLineAlpha;
-      context.lineWidth = refLineWidth;
-      context.strokeStyle = refLineColor;
-      context.moveTo(0, l1);
-      context.lineTo(width, l1);
-      context.moveTo(0, l2);
-      context.lineTo(width, l2);
-      context.stroke();
-      context.closePath();
-
-      context.beginPath();
-      context.globalAlpha = upLineAlpha;
-      context.lineWidth = upLineWidth;
-      context.strokeStyle = upLineColor;
-      lineStyle ? drawBezier(listUp, offset) : drawLine(listUp, offset);
-      context.stroke();
-      context.closePath();
-
-      context.beginPath();
-      context.globalAlpha = downLineAlpha;
-      context.lineWidth = downLineWidth;
-      context.strokeStyle = downLineColor;
-      lineStyle ? drawBezier(listDown, offset) : drawLine(listDown, offset);
-      context.stroke();
-      context.closePath();
-
-      raf = requestAnimationFrame(() => drawGraph(now));
-    };
-
-    drawGraph(Date.now());
-
-    return () => {
-      cancelAnimationFrame(raf);
-    };
-  }, [palette]);
-
-  return <canvas ref={canvasRef} style={{ width: "100%", height: "100%" }} />;
-});
diff --git a/src/components/layout/update-button.tsx b/src/components/layout/update-button.tsx
deleted file mode 100644
index b71ea07b65f581e85713dd50302a4d33b48ecd61..0000000000000000000000000000000000000000
--- a/src/components/layout/update-button.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import useSWR from "swr";
-import { useRef } from "react";
-import { Button } from "@mui/material";
-import { checkUpdate } from "@tauri-apps/api/updater";
-import { UpdateViewer } from "../setting/mods/update-viewer";
-import { DialogRef } from "../base";
-
-interface Props {
-  className?: string;
-}
-
-export const UpdateButton = (props: Props) => {
-  const { className } = props;
-
-  const viewerRef = useRef<DialogRef>(null);
-
-  const { data: updateInfo } = useSWR("checkUpdate", checkUpdate, {
-    errorRetryCount: 2,
-    revalidateIfStale: false,
-    focusThrottleInterval: 36e5, // 1 hour
-  });
-
-  if (!updateInfo?.shouldUpdate) return null;
-
-  return (
-    <>
-      <UpdateViewer ref={viewerRef} />
-
-      <Button
-        color="error"
-        variant="contained"
-        size="small"
-        className={className}
-        onClick={() => viewerRef.current?.open()}
-      >
-        New
-      </Button>
-    </>
-  );
-};
diff --git a/src/components/layout/use-custom-theme.ts b/src/components/layout/use-custom-theme.ts
deleted file mode 100644
index e02949413133848dd5aa76369d39df1b3b333a09..0000000000000000000000000000000000000000
--- a/src/components/layout/use-custom-theme.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-import { useEffect, useMemo } from "react";
-import { useRecoilState } from "recoil";
-import { createTheme, Theme } from "@mui/material";
-import { appWindow } from "@tauri-apps/api/window";
-import { atomThemeMode } from "@/services/states";
-import { defaultTheme, defaultDarkTheme } from "@/pages/_theme";
-import { useVerge } from "@/hooks/use-verge";
-
-/**
- * custom theme
- */
-export const useCustomTheme = () => {
-  const { verge } = useVerge();
-  const { theme_mode, theme_setting } = verge ?? {};
-  const [mode, setMode] = useRecoilState(atomThemeMode);
-
-  useEffect(() => {
-    const themeMode = ["light", "dark", "system"].includes(theme_mode!)
-      ? theme_mode!
-      : "light";
-
-    if (themeMode !== "system") {
-      setMode(themeMode);
-      return;
-    }
-
-    appWindow.theme().then((m) => m && setMode(m));
-    const unlisten = appWindow.onThemeChanged((e) => setMode(e.payload));
-
-    return () => {
-      unlisten.then((fn) => fn());
-    };
-  }, [theme_mode]);
-
-  const theme = useMemo(() => {
-    const setting = theme_setting || {};
-    const dt = mode === "light" ? defaultTheme : defaultDarkTheme;
-
-    let theme: Theme;
-
-    try {
-      theme = createTheme({
-        breakpoints: {
-          values: { xs: 0, sm: 650, md: 900, lg: 1200, xl: 1536 },
-        },
-        palette: {
-          mode,
-          primary: { main: setting.primary_color || dt.primary_color },
-          secondary: { main: setting.secondary_color || dt.secondary_color },
-          info: { main: setting.info_color || dt.info_color },
-          error: { main: setting.error_color || dt.error_color },
-          warning: { main: setting.warning_color || dt.warning_color },
-          success: { main: setting.success_color || dt.success_color },
-          text: {
-            primary: setting.primary_text || dt.primary_text,
-            secondary: setting.secondary_text || dt.secondary_text,
-          },
-        },
-        typography: {
-          // todo
-          fontFamily: setting.font_family
-            ? `${setting.font_family}, ${dt.font_family}`
-            : dt.font_family,
-        },
-      });
-    } catch {
-      // fix #294
-      theme = createTheme({
-        breakpoints: {
-          values: { xs: 0, sm: 650, md: 900, lg: 1200, xl: 1536 },
-        },
-        palette: {
-          mode,
-          primary: { main: dt.primary_color },
-          secondary: { main: dt.secondary_color },
-          info: { main: dt.info_color },
-          error: { main: dt.error_color },
-          warning: { main: dt.warning_color },
-          success: { main: dt.success_color },
-          text: { primary: dt.primary_text, secondary: dt.secondary_text },
-        },
-        typography: { fontFamily: dt.font_family },
-      });
-    }
-
-    // css
-    const selectColor = mode === "light" ? "#f5f5f5" : "#d5d5d5";
-    const scrollColor = mode === "light" ? "#90939980" : "#54545480";
-
-    const rootEle = document.documentElement;
-    rootEle.style.setProperty("--selection-color", selectColor);
-    rootEle.style.setProperty("--scroller-color", scrollColor);
-    rootEle.style.setProperty("--primary-main", theme.palette.primary.main);
-
-    // inject css
-    let style = document.querySelector("style#verge-theme");
-    if (!style) {
-      style = document.createElement("style");
-      style.id = "verge-theme";
-      document.head.appendChild(style!);
-    }
-    if (style) {
-      style.innerHTML = setting.css_injection || "";
-    }
-
-    // update svg icon
-    const { palette } = theme;
-
-    setTimeout(() => {
-      const dom = document.querySelector("#Gradient2");
-      if (dom) {
-        dom.innerHTML = `
-        <stop offset="0%" stop-color="${palette.primary.main}" />
-        <stop offset="80%" stop-color="${palette.primary.dark}" />
-        <stop offset="100%" stop-color="${palette.primary.dark}" />
-        `;
-      }
-    }, 0);
-
-    return theme;
-  }, [mode, theme_setting]);
-
-  return { theme };
-};
diff --git a/src/components/layout/use-log-setup.ts b/src/components/layout/use-log-setup.ts
deleted file mode 100644
index 0c130ac9e85df1e9b0b61d2e850fb6682cce3c16..0000000000000000000000000000000000000000
--- a/src/components/layout/use-log-setup.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import dayjs from "dayjs";
-import { useEffect } from "react";
-import { useRecoilValue, useSetRecoilState } from "recoil";
-import { getClashLogs } from "@/services/cmds";
-import { useClashInfo } from "@/hooks/use-clash";
-import { atomEnableLog, atomLogData } from "@/services/states";
-import { useWebsocket } from "@/hooks/use-websocket";
-
-const MAX_LOG_NUM = 1000;
-
-// setup the log websocket
-export const useLogSetup = () => {
-  const { clashInfo } = useClashInfo();
-
-  const enableLog = useRecoilValue(atomEnableLog);
-  const setLogData = useSetRecoilState(atomLogData);
-
-  const { connect, disconnect } = useWebsocket((event) => {
-    const data = JSON.parse(event.data) as ILogItem;
-    const time = dayjs().format("MM-DD HH:mm:ss");
-    setLogData((l) => {
-      if (l.length >= MAX_LOG_NUM) l.shift();
-      return [...l, { ...data, time }];
-    });
-  });
-
-  useEffect(() => {
-    if (!enableLog || !clashInfo) return;
-
-    getClashLogs().then(setLogData);
-
-    const { server = "", secret = "" } = clashInfo;
-    connect(`ws://${server}/logs?token=${encodeURIComponent(secret)}`);
-
-    return () => {
-      disconnect();
-    };
-  }, [clashInfo, enableLog]);
-};
diff --git a/src/components/log/log-item.tsx b/src/components/log/log-item.tsx
deleted file mode 100644
index 1aa08040586ee4fce7657a1df6bb042fa027b473..0000000000000000000000000000000000000000
--- a/src/components/log/log-item.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import { styled, Box } from "@mui/material";
-
-const Item = styled(Box)(({ theme: { palette, typography } }) => ({
-  padding: "8px 0",
-  margin: "0 12px",
-  lineHeight: 1.35,
-  borderBottom: `1px solid ${palette.divider}`,
-  fontSize: "0.875rem",
-  fontFamily: typography.fontFamily,
-  userSelect: "text",
-  "& .time": {
-    color: palette.text.secondary,
-  },
-  "& .type": {
-    display: "inline-block",
-    marginLeft: 8,
-    textAlign: "center",
-    borderRadius: 2,
-    textTransform: "uppercase",
-    fontWeight: "600",
-  },
-  '& .type[data-type="error"], & .type[data-type="err"]': {
-    color: palette.error.main,
-  },
-  '& .type[data-type="warning"], & .type[data-type="warn"]': {
-    color: palette.warning.main,
-  },
-  '& .type[data-type="info"], & .type[data-type="inf"]': {
-    color: palette.info.main,
-  },
-  "& .data": {
-    color: palette.text.primary,
-  },
-}));
-
-interface Props {
-  value: ILogItem;
-}
-
-const LogItem = (props: Props) => {
-  const { value } = props;
-
-  return (
-    <Item>
-      <div>
-        <span className="time">{value.time}</span>
-        <span className="type" data-type={value.type.toLowerCase()}>
-          {value.type}
-        </span>
-      </div>
-      <div>
-        <span className="data">{value.payload}</span>
-      </div>
-    </Item>
-  );
-};
-
-export default LogItem;
diff --git a/src/components/profile/editor-viewer.tsx b/src/components/profile/editor-viewer.tsx
deleted file mode 100644
index 28608e955fd50608c3f6316169379c9018b99cbc..0000000000000000000000000000000000000000
--- a/src/components/profile/editor-viewer.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import { useEffect, useRef } from "react";
-import { useLockFn } from "ahooks";
-import { useRecoilValue } from "recoil";
-import { useTranslation } from "react-i18next";
-import {
-  Button,
-  Dialog,
-  DialogActions,
-  DialogContent,
-  DialogTitle,
-} from "@mui/material";
-import { atomThemeMode } from "@/services/states";
-import { readProfileFile, saveProfileFile } from "@/services/cmds";
-import { Notice } from "@/components/base";
-
-import "monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution.js";
-import "monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution.js";
-import "monaco-editor/esm/vs/editor/contrib/folding/browser/folding.js";
-import { editor } from "monaco-editor/esm/vs/editor/editor.api";
-
-interface Props {
-  uid: string;
-  open: boolean;
-  mode: "yaml" | "javascript";
-  onClose: () => void;
-  onChange?: () => void;
-}
-
-export const EditorViewer = (props: Props) => {
-  const { uid, open, mode, onClose, onChange } = props;
-
-  const { t } = useTranslation();
-  const editorRef = useRef<any>();
-  const instanceRef = useRef<editor.IStandaloneCodeEditor | null>(null);
-  const themeMode = useRecoilValue(atomThemeMode);
-
-  useEffect(() => {
-    if (!open) return;
-
-    readProfileFile(uid).then((data) => {
-      const dom = editorRef.current;
-
-      if (!dom) return;
-      if (instanceRef.current) instanceRef.current.dispose();
-
-      instanceRef.current = editor.create(editorRef.current, {
-        value: data,
-        language: mode,
-        theme: themeMode === "light" ? "vs" : "vs-dark",
-        minimap: { enabled: false },
-      });
-    });
-
-    return () => {
-      if (instanceRef.current) {
-        instanceRef.current.dispose();
-        instanceRef.current = null;
-      }
-    };
-  }, [open]);
-
-  const onSave = useLockFn(async () => {
-    const value = instanceRef.current?.getValue();
-
-    if (value == null) return;
-
-    try {
-      await saveProfileFile(uid, value);
-      onChange?.();
-      onClose();
-    } catch (err: any) {
-      Notice.error(err.message || err.toString());
-    }
-  });
-
-  return (
-    <Dialog open={open} onClose={onClose}>
-      <DialogTitle>{t("Edit File")}</DialogTitle>
-
-      <DialogContent sx={{ width: 520, pb: 1, userSelect: "text" }}>
-        <div style={{ width: "100%", height: "420px" }} ref={editorRef} />
-      </DialogContent>
-
-      <DialogActions>
-        <Button onClick={onClose} variant="outlined">
-          {t("Cancel")}
-        </Button>
-        <Button onClick={onSave} variant="contained">
-          {t("Save")}
-        </Button>
-      </DialogActions>
-    </Dialog>
-  );
-};
diff --git a/src/components/profile/file-input.tsx b/src/components/profile/file-input.tsx
deleted file mode 100644
index 5357224a464b5ee18177ce0e4c5ed8fa9cc55ab9..0000000000000000000000000000000000000000
--- a/src/components/profile/file-input.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import { useRef, useState } from "react";
-import { useLockFn } from "ahooks";
-import { useTranslation } from "react-i18next";
-import { Box, Button, Typography } from "@mui/material";
-
-interface Props {
-  onChange: (value: string) => void;
-}
-
-export const FileInput = (props: Props) => {
-  const { onChange } = props;
-
-  const { t } = useTranslation();
-  // file input
-  const inputRef = useRef<any>();
-  const [loading, setLoading] = useState(false);
-  const [fileName, setFileName] = useState("");
-
-  const onFileInput = useLockFn(async (e: any) => {
-    const file = e.target.files?.[0] as File;
-
-    if (!file) return;
-
-    setFileName(file.name);
-    setLoading(true);
-
-    return new Promise((resolve, reject) => {
-      const reader = new FileReader();
-      reader.onload = (event) => {
-        resolve(null);
-        onChange(event.target?.result as string);
-      };
-      reader.onerror = reject;
-      reader.readAsText(file);
-    }).finally(() => setLoading(false));
-  });
-
-  return (
-    <Box sx={{ mt: 2, mb: 1, display: "flex", alignItems: "center" }}>
-      <Button
-        variant="outlined"
-        sx={{ flex: "none" }}
-        onClick={() => inputRef.current?.click()}
-      >
-        {t("Choose File")}
-      </Button>
-
-      <input
-        type="file"
-        accept=".yaml,.yml"
-        ref={inputRef}
-        style={{ display: "none" }}
-        onChange={onFileInput}
-      />
-
-      <Typography noWrap sx={{ ml: 1 }}>
-        {loading ? "Loading..." : fileName}
-      </Typography>
-    </Box>
-  );
-};
diff --git a/src/components/profile/log-viewer.tsx b/src/components/profile/log-viewer.tsx
deleted file mode 100644
index 47924683712f87265e2edd096418ddf8587630b4..0000000000000000000000000000000000000000
--- a/src/components/profile/log-viewer.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import { Fragment } from "react";
-import { useTranslation } from "react-i18next";
-import {
-  Button,
-  Chip,
-  Dialog,
-  DialogActions,
-  DialogContent,
-  DialogTitle,
-  Divider,
-  Typography,
-} from "@mui/material";
-import { BaseEmpty } from "@/components/base";
-
-interface Props {
-  open: boolean;
-  logInfo: [string, string][];
-  onClose: () => void;
-}
-
-export const LogViewer = (props: Props) => {
-  const { open, logInfo, onClose } = props;
-
-  const { t } = useTranslation();
-
-  return (
-    <Dialog open={open} onClose={onClose}>
-      <DialogTitle>{t("Script Console")}</DialogTitle>
-
-      <DialogContent
-        sx={{
-          width: 400,
-          height: 300,
-          overflowX: "hidden",
-          userSelect: "text",
-          pb: 1,
-        }}
-      >
-        {logInfo.map(([level, log], index) => (
-          <Fragment key={index.toString()}>
-            <Typography color="text.secondary" component="div">
-              <Chip
-                label={level}
-                size="small"
-                variant="outlined"
-                color={
-                  level === "error" || level === "exception"
-                    ? "error"
-                    : "default"
-                }
-                sx={{ mr: 1 }}
-              />
-              {log}
-            </Typography>
-            <Divider sx={{ my: 0.5 }} />
-          </Fragment>
-        ))}
-
-        {logInfo.length === 0 && <BaseEmpty />}
-      </DialogContent>
-
-      <DialogActions>
-        <Button onClick={onClose} variant="outlined">
-          {t("Back")}
-        </Button>
-      </DialogActions>
-    </Dialog>
-  );
-};
diff --git a/src/components/profile/profile-box.tsx b/src/components/profile/profile-box.tsx
deleted file mode 100644
index 6e15a879ad3622975702cdda50ef24c88cc44b71..0000000000000000000000000000000000000000
--- a/src/components/profile/profile-box.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import { alpha, Box, styled } from "@mui/material";
-
-export const ProfileBox = styled(Box)(
-  ({ theme, "aria-selected": selected }) => {
-    const { mode, primary, text, grey, background } = theme.palette;
-    const key = `${mode}-${!!selected}`;
-
-    const backgroundColor = {
-      "light-true": alpha(primary.main, 0.2),
-      "light-false": alpha(background.paper, 0.75),
-      "dark-true": alpha(primary.main, 0.45),
-      "dark-false": alpha(grey[700], 0.45),
-    }[key]!;
-
-    const color = {
-      "light-true": text.secondary,
-      "light-false": text.secondary,
-      "dark-true": alpha(text.secondary, 0.85),
-      "dark-false": alpha(text.secondary, 0.65),
-    }[key]!;
-
-    const h2color = {
-      "light-true": primary.main,
-      "light-false": text.primary,
-      "dark-true": primary.light,
-      "dark-false": text.primary,
-    }[key]!;
-
-    return {
-      position: "relative",
-      width: "100%",
-      display: "block",
-      cursor: "pointer",
-      textAlign: "left",
-      borderRadius: theme.shape.borderRadius,
-      boxShadow: theme.shadows[2],
-      padding: "8px 16px",
-      boxSizing: "border-box",
-      backgroundColor,
-      color,
-      "& h2": { color: h2color },
-    };
-  }
-);
diff --git a/src/components/profile/profile-item.tsx b/src/components/profile/profile-item.tsx
deleted file mode 100644
index 72fda6f0f074919cb094df86ffdcee3bec4e9945..0000000000000000000000000000000000000000
--- a/src/components/profile/profile-item.tsx
+++ /dev/null
@@ -1,341 +0,0 @@
-import dayjs from "dayjs";
-import { mutate } from "swr";
-import { useEffect, useState } from "react";
-import { useLockFn } from "ahooks";
-import { useRecoilState } from "recoil";
-import { useTranslation } from "react-i18next";
-import {
-  Box,
-  Typography,
-  LinearProgress,
-  IconButton,
-  keyframes,
-  MenuItem,
-  Menu,
-  CircularProgress,
-} from "@mui/material";
-import { RefreshRounded } from "@mui/icons-material";
-import { atomLoadingCache } from "@/services/states";
-import { updateProfile, deleteProfile, viewProfile } from "@/services/cmds";
-import { Notice } from "@/components/base";
-import { EditorViewer } from "./editor-viewer";
-import { ProfileBox } from "./profile-box";
-import parseTraffic from "@/utils/parse-traffic";
-
-const round = keyframes`
-  from { transform: rotate(0deg); }
-  to { transform: rotate(360deg); }
-`;
-
-interface Props {
-  selected: boolean;
-  activating: boolean;
-  itemData: IProfileItem;
-  onSelect: (force: boolean) => void;
-  onEdit: () => void;
-}
-
-export const ProfileItem = (props: Props) => {
-  const { selected, activating, itemData, onSelect, onEdit } = props;
-
-  const { t } = useTranslation();
-  const [anchorEl, setAnchorEl] = useState<any>(null);
-  const [position, setPosition] = useState({ left: 0, top: 0 });
-  const [loadingCache, setLoadingCache] = useRecoilState(atomLoadingCache);
-
-  const { uid, name = "Profile", extra, updated = 0 } = itemData;
-
-  // local file mode
-  // remote file mode
-  const hasUrl = !!itemData.url;
-  const hasExtra = !!extra; // only subscription url has extra info
-
-  const { upload = 0, download = 0, total = 0 } = extra ?? {};
-  const from = parseUrl(itemData.url);
-  const expire = parseExpire(extra?.expire);
-  const progress = Math.round(((download + upload) * 100) / (total + 0.1));
-
-  const loading = loadingCache[itemData.uid] ?? false;
-
-  // interval update fromNow field
-  const [, setRefresh] = useState({});
-  useEffect(() => {
-    if (!hasUrl) return;
-
-    let timer: any = null;
-
-    const handler = () => {
-      const now = Date.now();
-      const lastUpdate = updated * 1000;
-      // 大于一天的不管
-      if (now - lastUpdate >= 24 * 36e5) return;
-
-      const wait = now - lastUpdate >= 36e5 ? 30e5 : 5e4;
-
-      timer = setTimeout(() => {
-        setRefresh({});
-        handler();
-      }, wait);
-    };
-
-    handler();
-
-    return () => {
-      if (timer) clearTimeout(timer);
-    };
-  }, [hasUrl, updated]);
-
-  const [fileOpen, setFileOpen] = useState(false);
-
-  const onEditInfo = () => {
-    setAnchorEl(null);
-    onEdit();
-  };
-
-  const onEditFile = () => {
-    setAnchorEl(null);
-    setFileOpen(true);
-  };
-
-  const onForceSelect = () => {
-    setAnchorEl(null);
-    onSelect(true);
-  };
-
-  const onOpenFile = useLockFn(async () => {
-    setAnchorEl(null);
-    try {
-      await viewProfile(itemData.uid);
-    } catch (err: any) {
-      Notice.error(err?.message || err.toString());
-    }
-  });
-
-  /// 0 不使用任何代理
-  /// 1 使用配置好的代理
-  /// 2 至少使用一个代理,根据配置,如果没配置,默认使用系统代理
-  const onUpdate = useLockFn(async (type: 0 | 1 | 2) => {
-    setAnchorEl(null);
-    setLoadingCache((cache) => ({ ...cache, [itemData.uid]: true }));
-
-    const option: Partial<IProfileOption> = {};
-
-    if (type === 0) {
-      option.with_proxy = false;
-      option.self_proxy = false;
-    } else if (type === 1) {
-      // nothing
-    } else if (type === 2) {
-      if (itemData.option?.self_proxy) {
-        option.with_proxy = false;
-        option.self_proxy = true;
-      } else {
-        option.with_proxy = true;
-        option.self_proxy = false;
-      }
-    }
-
-    try {
-      await updateProfile(itemData.uid, option);
-      mutate("getProfiles");
-    } catch (err: any) {
-      const errmsg = err?.message || err.toString();
-      Notice.error(
-        errmsg.replace(/error sending request for url (\S+?): /, "")
-      );
-    } finally {
-      setLoadingCache((cache) => ({ ...cache, [itemData.uid]: false }));
-    }
-  });
-
-  const onDelete = useLockFn(async () => {
-    setAnchorEl(null);
-    try {
-      await deleteProfile(itemData.uid);
-      mutate("getProfiles");
-    } catch (err: any) {
-      Notice.error(err?.message || err.toString());
-    }
-  });
-
-  const urlModeMenu = [
-    { label: "Select", handler: onForceSelect },
-    { label: "Edit Info", handler: onEditInfo },
-    { label: "Edit File", handler: onEditFile },
-    { label: "Open File", handler: onOpenFile },
-    { label: "Update", handler: () => onUpdate(0) },
-    { label: "Update(Proxy)", handler: () => onUpdate(2) },
-    { label: "Delete", handler: onDelete },
-  ];
-  const fileModeMenu = [
-    { label: "Select", handler: onForceSelect },
-    { label: "Edit Info", handler: onEditInfo },
-    { label: "Edit File", handler: onEditFile },
-    { label: "Open File", handler: onOpenFile },
-    { label: "Delete", handler: onDelete },
-  ];
-
-  const boxStyle = {
-    height: 26,
-    display: "flex",
-    alignItems: "center",
-    justifyContent: "space-between",
-  };
-
-  return (
-    <>
-      <ProfileBox
-        aria-selected={selected}
-        onClick={() => onSelect(false)}
-        onContextMenu={(event) => {
-          const { clientX, clientY } = event;
-          setPosition({ top: clientY, left: clientX });
-          setAnchorEl(event.currentTarget);
-          event.preventDefault();
-        }}
-      >
-        {activating && (
-          <Box
-            sx={{
-              position: "absolute",
-              display: "flex",
-              justifyContent: "center",
-              alignItems: "center",
-              top: 10,
-              left: 10,
-              right: 10,
-              bottom: 2,
-              zIndex: 10,
-              backdropFilter: "blur(2px)",
-            }}
-          >
-            <CircularProgress size={20} />
-          </Box>
-        )}
-
-        <Box position="relative">
-          <Typography
-            width="calc(100% - 36px)"
-            variant="h6"
-            component="h2"
-            noWrap
-            title={name}
-          >
-            {name}
-          </Typography>
-
-          {/* only if has url can it be updated */}
-          {hasUrl && (
-            <IconButton
-              sx={{
-                position: "absolute",
-                p: "3px",
-                top: -1,
-                right: -5,
-                animation: loading ? `1s linear infinite ${round}` : "none",
-              }}
-              size="small"
-              color="inherit"
-              disabled={loading}
-              onClick={(e) => {
-                e.stopPropagation();
-                onUpdate(1);
-              }}
-            >
-              <RefreshRounded color="inherit" />
-            </IconButton>
-          )}
-        </Box>
-
-        {/* the second line show url's info or description */}
-        <Box sx={boxStyle}>
-          {hasUrl ? (
-            <>
-              <Typography noWrap title={`From: ${from}`}>
-                {from}
-              </Typography>
-
-              <Typography
-                noWrap
-                flex="1 0 auto"
-                fontSize={14}
-                textAlign="right"
-                title={`Updated Time: ${parseExpire(updated)}`}
-              >
-                {updated > 0 ? dayjs(updated * 1000).fromNow() : ""}
-              </Typography>
-            </>
-          ) : (
-            <Typography noWrap title={itemData.desc}>
-              {itemData.desc}
-            </Typography>
-          )}
-        </Box>
-
-        {/* the third line show extra info or last updated time */}
-        {hasExtra ? (
-          <Box sx={{ ...boxStyle, fontSize: 14 }}>
-            <span title="Used / Total">
-              {parseTraffic(upload + download)} / {parseTraffic(total)}
-            </span>
-            <span title="Expire Time">{expire}</span>
-          </Box>
-        ) : (
-          <Box sx={{ ...boxStyle, fontSize: 14, justifyContent: "flex-end" }}>
-            <span title="Updated Time">{parseExpire(updated)}</span>
-          </Box>
-        )}
-
-        <LinearProgress
-          variant="determinate"
-          value={progress}
-          color="inherit"
-        />
-      </ProfileBox>
-
-      <Menu
-        open={!!anchorEl}
-        anchorEl={anchorEl}
-        onClose={() => setAnchorEl(null)}
-        anchorPosition={position}
-        anchorReference="anchorPosition"
-        transitionDuration={225}
-        MenuListProps={{ sx: { py: 0.5 } }}
-        onContextMenu={(e) => {
-          setAnchorEl(null);
-          e.preventDefault();
-        }}
-      >
-        {(hasUrl ? urlModeMenu : fileModeMenu).map((item) => (
-          <MenuItem
-            key={item.label}
-            onClick={item.handler}
-            sx={{ minWidth: 120 }}
-            dense
-          >
-            {t(item.label)}
-          </MenuItem>
-        ))}
-      </Menu>
-
-      <EditorViewer
-        uid={uid}
-        open={fileOpen}
-        mode="yaml"
-        onClose={() => setFileOpen(false)}
-      />
-    </>
-  );
-};
-
-function parseUrl(url?: string) {
-  if (!url) return "";
-  const regex = /https?:\/\/(.+?)\//;
-  const result = url.match(regex);
-  return result ? result[1] : "local file";
-}
-
-function parseExpire(expire?: number) {
-  if (!expire) return "-";
-  return dayjs(expire * 1000).format("YYYY-MM-DD");
-}
diff --git a/src/components/profile/profile-more.tsx b/src/components/profile/profile-more.tsx
deleted file mode 100644
index f979665767bd1acb4156053ca624356487d2000f..0000000000000000000000000000000000000000
--- a/src/components/profile/profile-more.tsx
+++ /dev/null
@@ -1,243 +0,0 @@
-import dayjs from "dayjs";
-import { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { useLockFn } from "ahooks";
-import {
-  Box,
-  Badge,
-  Chip,
-  Typography,
-  MenuItem,
-  Menu,
-  IconButton,
-} from "@mui/material";
-import { FeaturedPlayListRounded } from "@mui/icons-material";
-import { viewProfile } from "@/services/cmds";
-import { Notice } from "@/components/base";
-import { EditorViewer } from "./editor-viewer";
-import { ProfileBox } from "./profile-box";
-import { LogViewer } from "./log-viewer";
-
-interface Props {
-  selected: boolean;
-  itemData: IProfileItem;
-  enableNum: number;
-  logInfo?: [string, string][];
-  onEnable: () => void;
-  onDisable: () => void;
-  onMoveTop: () => void;
-  onMoveEnd: () => void;
-  onDelete: () => void;
-  onEdit: () => void;
-}
-
-// profile enhanced item
-export const ProfileMore = (props: Props) => {
-  const {
-    selected,
-    itemData,
-    enableNum,
-    logInfo = [],
-    onEnable,
-    onDisable,
-    onMoveTop,
-    onMoveEnd,
-    onDelete,
-    onEdit,
-  } = props;
-
-  const { uid, type } = itemData;
-  const { t, i18n } = useTranslation();
-  const [anchorEl, setAnchorEl] = useState<any>(null);
-  const [position, setPosition] = useState({ left: 0, top: 0 });
-  const [fileOpen, setFileOpen] = useState(false);
-  const [logOpen, setLogOpen] = useState(false);
-
-  const onEditInfo = () => {
-    setAnchorEl(null);
-    onEdit();
-  };
-
-  const onEditFile = () => {
-    setAnchorEl(null);
-    setFileOpen(true);
-  };
-
-  const onOpenFile = useLockFn(async () => {
-    setAnchorEl(null);
-    try {
-      await viewProfile(itemData.uid);
-    } catch (err: any) {
-      Notice.error(err?.message || err.toString());
-    }
-  });
-
-  const fnWrapper = (fn: () => void) => () => {
-    setAnchorEl(null);
-    return fn();
-  };
-
-  const hasError = !!logInfo.find((e) => e[0] === "exception");
-  const showMove = enableNum > 1 && !hasError;
-
-  const enableMenu = [
-    { label: "Disable", handler: fnWrapper(onDisable) },
-    { label: "Edit Info", handler: onEditInfo },
-    { label: "Edit File", handler: onEditFile },
-    { label: "Open File", handler: onOpenFile },
-    { label: "To Top", show: showMove, handler: fnWrapper(onMoveTop) },
-    { label: "To End", show: showMove, handler: fnWrapper(onMoveEnd) },
-    { label: "Delete", handler: fnWrapper(onDelete) },
-  ];
-
-  const disableMenu = [
-    { label: "Enable", handler: fnWrapper(onEnable) },
-    { label: "Edit Info", handler: onEditInfo },
-    { label: "Edit File", handler: onEditFile },
-    { label: "Open File", handler: onOpenFile },
-    { label: "Delete", handler: fnWrapper(onDelete) },
-  ];
-
-  const boxStyle = {
-    height: 26,
-    display: "flex",
-    alignItems: "center",
-    justifyContent: "space-between",
-    lineHeight: 1,
-  };
-
-  return (
-    <>
-      <ProfileBox
-        aria-selected={selected}
-        onDoubleClick={onEditFile}
-        // onClick={() => onSelect(false)}
-        onContextMenu={(event) => {
-          const { clientX, clientY } = event;
-          setPosition({ top: clientY, left: clientX });
-          setAnchorEl(event.currentTarget);
-          event.preventDefault();
-        }}
-      >
-        <Box
-          display="flex"
-          justifyContent="space-between"
-          alignItems="center"
-          mb={0.5}
-        >
-          <Typography
-            width="calc(100% - 52px)"
-            variant="h6"
-            component="h2"
-            noWrap
-            title={itemData.name}
-          >
-            {itemData.name}
-          </Typography>
-
-          <Chip
-            label={type}
-            color="primary"
-            size="small"
-            variant="outlined"
-            sx={{ height: 20, textTransform: "capitalize" }}
-          />
-        </Box>
-
-        <Box sx={boxStyle}>
-          {selected && type === "script" ? (
-            hasError ? (
-              <Badge color="error" variant="dot" overlap="circular">
-                <IconButton
-                  size="small"
-                  edge="start"
-                  color="error"
-                  title="Console"
-                  onClick={() => setLogOpen(true)}
-                >
-                  <FeaturedPlayListRounded fontSize="inherit" />
-                </IconButton>
-              </Badge>
-            ) : (
-              <IconButton
-                size="small"
-                edge="start"
-                color="inherit"
-                title="Console"
-                onClick={() => setLogOpen(true)}
-              >
-                <FeaturedPlayListRounded fontSize="inherit" />
-              </IconButton>
-            )
-          ) : (
-            <Typography
-              noWrap
-              title={itemData.desc}
-              sx={i18n.language === "zh" ? { width: "calc(100% - 75px)" } : {}}
-            >
-              {itemData.desc}
-            </Typography>
-          )}
-
-          <Typography
-            noWrap
-            component="span"
-            title={`Updated Time: ${parseExpire(itemData.updated)}`}
-            style={{ fontSize: 14 }}
-          >
-            {!!itemData.updated
-              ? dayjs(itemData.updated! * 1000).fromNow()
-              : ""}
-          </Typography>
-        </Box>
-      </ProfileBox>
-
-      <Menu
-        open={!!anchorEl}
-        anchorEl={anchorEl}
-        onClose={() => setAnchorEl(null)}
-        anchorPosition={position}
-        anchorReference="anchorPosition"
-        transitionDuration={225}
-        MenuListProps={{ sx: { py: 0.5 } }}
-        onContextMenu={(e) => {
-          setAnchorEl(null);
-          e.preventDefault();
-        }}
-      >
-        {(selected ? enableMenu : disableMenu)
-          .filter((item: any) => item.show !== false)
-          .map((item) => (
-            <MenuItem
-              key={item.label}
-              onClick={item.handler}
-              sx={{ minWidth: 120 }}
-              dense
-            >
-              {t(item.label)}
-            </MenuItem>
-          ))}
-      </Menu>
-
-      <EditorViewer
-        uid={uid}
-        open={fileOpen}
-        mode={type === "merge" ? "yaml" : "javascript"}
-        onClose={() => setFileOpen(false)}
-      />
-
-      {selected && (
-        <LogViewer
-          open={logOpen}
-          logInfo={logInfo}
-          onClose={() => setLogOpen(false)}
-        />
-      )}
-    </>
-  );
-};
-
-function parseExpire(expire?: number) {
-  if (!expire) return "-";
-  return dayjs(expire * 1000).format("YYYY-MM-DD");
-}
diff --git a/src/components/profile/profile-viewer.tsx b/src/components/profile/profile-viewer.tsx
deleted file mode 100644
index f928053d9039f3f085ec44f76da98720d4f4ab25..0000000000000000000000000000000000000000
--- a/src/components/profile/profile-viewer.tsx
+++ /dev/null
@@ -1,279 +0,0 @@
-import {
-  forwardRef,
-  useEffect,
-  useImperativeHandle,
-  useRef,
-  useState,
-} from "react";
-import { useLockFn } from "ahooks";
-import { useTranslation } from "react-i18next";
-import { useForm, Controller } from "react-hook-form";
-import {
-  Box,
-  FormControl,
-  InputAdornment,
-  InputLabel,
-  MenuItem,
-  Select,
-  Switch,
-  styled,
-  TextField,
-} from "@mui/material";
-import { createProfile, patchProfile } from "@/services/cmds";
-import { BaseDialog, Notice } from "@/components/base";
-import { version } from "@root/package.json";
-import { FileInput } from "./file-input";
-
-interface Props {
-  onChange: () => void;
-}
-
-export interface ProfileViewerRef {
-  create: () => void;
-  edit: (item: IProfileItem) => void;
-}
-
-// create or edit the profile
-// remote / local / merge / script
-export const ProfileViewer = forwardRef<ProfileViewerRef, Props>(
-  (props, ref) => {
-    const { t } = useTranslation();
-    const [open, setOpen] = useState(false);
-    const [openType, setOpenType] = useState<"new" | "edit">("new");
-
-    // file input
-    const fileDataRef = useRef<string | null>(null);
-
-    const { control, watch, register, ...formIns } = useForm<IProfileItem>({
-      defaultValues: {
-        type: "remote",
-        name: "Remote File",
-        desc: "",
-        url: "",
-        option: {
-          // user_agent: "",
-          with_proxy: false,
-          self_proxy: false,
-        },
-      },
-    });
-
-    useImperativeHandle(ref, () => ({
-      create: () => {
-        setOpenType("new");
-        setOpen(true);
-      },
-      edit: (item) => {
-        if (item) {
-          Object.entries(item).forEach(([key, value]) => {
-            formIns.setValue(key as any, value);
-          });
-        }
-        setOpenType("edit");
-        setOpen(true);
-      },
-    }));
-
-    const selfProxy = watch("option.self_proxy");
-    const withProxy = watch("option.with_proxy");
-
-    useEffect(() => {
-      if (selfProxy) formIns.setValue("option.with_proxy", false);
-    }, [selfProxy]);
-
-    useEffect(() => {
-      if (withProxy) formIns.setValue("option.self_proxy", false);
-    }, [withProxy]);
-
-    const handleOk = useLockFn(
-      formIns.handleSubmit(async (form) => {
-        try {
-          if (!form.type) throw new Error("`Type` should not be null");
-          if (form.type === "remote" && !form.url) {
-            throw new Error("The URL should not be null");
-          }
-          if (form.type !== "remote" && form.type !== "local") {
-            delete form.option;
-          }
-          if (form.option?.update_interval) {
-            form.option.update_interval = +form.option.update_interval;
-          }
-          const name = form.name || `${form.type} file`;
-          const item = { ...form, name };
-
-          // 创建
-          if (openType === "new") {
-            await createProfile(item, fileDataRef.current);
-          }
-          // 编辑
-          else {
-            if (!form.uid) throw new Error("UID not found");
-            await patchProfile(form.uid, item);
-          }
-          setOpen(false);
-          setTimeout(() => formIns.reset(), 500);
-          fileDataRef.current = null;
-          props.onChange();
-        } catch (err: any) {
-          Notice.error(err.message || err.toString());
-        }
-      })
-    );
-
-    const handleClose = () => {
-      setOpen(false);
-      fileDataRef.current = null;
-      setTimeout(() => formIns.reset(), 500);
-    };
-
-    const text = {
-      fullWidth: true,
-      size: "small",
-      margin: "normal",
-      variant: "outlined",
-      autoComplete: "off",
-      autoCorrect: "off",
-    } as const;
-
-    const formType = watch("type");
-    const isRemote = formType === "remote";
-    const isLocal = formType === "local";
-
-    return (
-      <BaseDialog
-        open={open}
-        title={openType === "new" ? t("Create Profile") : t("Edit Profile")}
-        contentSx={{ width: 375, pb: 0, maxHeight: "80%" }}
-        okBtn={t("Save")}
-        cancelBtn={t("Cancel")}
-        onClose={handleClose}
-        onCancel={handleClose}
-        onOk={handleOk}
-      >
-        <Controller
-          name="type"
-          control={control}
-          render={({ field }) => (
-            <FormControl size="small" fullWidth sx={{ mt: 1, mb: 1 }}>
-              <InputLabel>{t("Type")}</InputLabel>
-              <Select {...field} autoFocus label={t("Type")}>
-                <MenuItem value="remote">Remote</MenuItem>
-                <MenuItem value="local">Local</MenuItem>
-                <MenuItem value="script">Script</MenuItem>
-                <MenuItem value="merge">Merge</MenuItem>
-              </Select>
-            </FormControl>
-          )}
-        />
-
-        <Controller
-          name="name"
-          control={control}
-          render={({ field }) => (
-            <TextField {...text} {...field} label={t("Name")} />
-          )}
-        />
-
-        <Controller
-          name="desc"
-          control={control}
-          render={({ field }) => (
-            <TextField {...text} {...field} label={t("Descriptions")} />
-          )}
-        />
-
-        {isRemote && (
-          <>
-            <Controller
-              name="url"
-              control={control}
-              render={({ field }) => (
-                <TextField
-                  {...text}
-                  {...field}
-                  multiline
-                  label={t("Subscription URL")}
-                />
-              )}
-            />
-
-            <Controller
-              name="option.user_agent"
-              control={control}
-              render={({ field }) => (
-                <TextField
-                  {...text}
-                  {...field}
-                  placeholder={`clash-verge/v${version}`}
-                  label="User Agent"
-                />
-              )}
-            />
-          </>
-        )}
-
-        {(isRemote || isLocal) && (
-          <Controller
-            name="option.update_interval"
-            control={control}
-            render={({ field }) => (
-              <TextField
-                {...text}
-                {...field}
-                onChange={(e) => {
-                  e.target.value = e.target.value
-                    ?.replace(/\D/, "")
-                    .slice(0, 10);
-                  field.onChange(e);
-                }}
-                label={t("Update Interval")}
-                InputProps={{
-                  endAdornment: (
-                    <InputAdornment position="end">mins</InputAdornment>
-                  ),
-                }}
-              />
-            )}
-          />
-        )}
-
-        {isLocal && openType === "new" && (
-          <FileInput onChange={(val) => (fileDataRef.current = val)} />
-        )}
-
-        {isRemote && (
-          <>
-            <Controller
-              name="option.with_proxy"
-              control={control}
-              render={({ field }) => (
-                <StyledBox>
-                  <InputLabel>{t("Use System Proxy")}</InputLabel>
-                  <Switch checked={field.value} {...field} color="primary" />
-                </StyledBox>
-              )}
-            />
-
-            <Controller
-              name="option.self_proxy"
-              control={control}
-              render={({ field }) => (
-                <StyledBox>
-                  <InputLabel>{t("Use Clash Proxy")}</InputLabel>
-                  <Switch checked={field.value} {...field} color="primary" />
-                </StyledBox>
-              )}
-            />
-          </>
-        )}
-      </BaseDialog>
-    );
-  }
-);
-
-const StyledBox = styled(Box)(() => ({
-  margin: "8px 0 8px 8px",
-  display: "flex",
-  alignItems: "center",
-  justifyContent: "space-between",
-}));
diff --git a/src/components/proxy/provider-button.tsx b/src/components/proxy/provider-button.tsx
deleted file mode 100644
index 5a63072ef45fcca62a7d4722fa565c28960e5379..0000000000000000000000000000000000000000
--- a/src/components/proxy/provider-button.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import dayjs from "dayjs";
-import useSWR, { mutate } from "swr";
-import { useState } from "react";
-import {
-  Button,
-  IconButton,
-  List,
-  ListItem,
-  ListItemText,
-} from "@mui/material";
-import { RefreshRounded } from "@mui/icons-material";
-import { useTranslation } from "react-i18next";
-import { useLockFn } from "ahooks";
-import { getProviders, providerUpdate } from "@/services/api";
-import { BaseDialog } from "../base";
-
-export const ProviderButton = () => {
-  const { t } = useTranslation();
-  const { data } = useSWR("getProviders", getProviders);
-
-  const [open, setOpen] = useState(false);
-
-  const hasProvider = Object.keys(data || {}).length > 0;
-
-  const handleUpdate = useLockFn(async (key: string) => {
-    await providerUpdate(key);
-    await mutate("getProxies");
-    await mutate("getProviders");
-  });
-
-  if (!hasProvider) return null;
-
-  return (
-    <>
-      <Button
-        size="small"
-        variant="outlined"
-        sx={{ textTransform: "capitalize" }}
-        onClick={() => setOpen(true)}
-      >
-        {t("Provider")}
-      </Button>
-
-      <BaseDialog
-        open={open}
-        title={t("Proxy Provider")}
-        contentSx={{ width: 400 }}
-        disableOk
-        cancelBtn={t("Cancel")}
-        onClose={() => setOpen(false)}
-        onCancel={() => setOpen(false)}
-      >
-        <List sx={{ py: 0, minHeight: 250 }}>
-          {Object.entries(data || {}).map(([key, item]) => {
-            const time = dayjs(item.updatedAt);
-            return (
-              <ListItem sx={{ p: 0 }} key={key}>
-                <ListItemText
-                  primary={key}
-                  secondary={
-                    <>
-                      <span style={{ marginRight: "4em" }}>
-                        Type: {item.vehicleType}
-                      </span>
-                      <span title={time.format("YYYY-MM-DD HH:mm:ss")}>
-                        Updated: {time.fromNow()}
-                      </span>
-                    </>
-                  }
-                />
-                <IconButton
-                  size="small"
-                  color="inherit"
-                  title="Update Provider"
-                  onClick={() => handleUpdate(key)}
-                >
-                  <RefreshRounded />
-                </IconButton>
-              </ListItem>
-            );
-          })}
-        </List>
-      </BaseDialog>
-    </>
-  );
-};
diff --git a/src/components/proxy/proxy-groups.tsx b/src/components/proxy/proxy-groups.tsx
deleted file mode 100644
index 4637cb4bcc04de84966ce44b99be73cbe8aa89e5..0000000000000000000000000000000000000000
--- a/src/components/proxy/proxy-groups.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-import { useRef } from "react";
-import { useLockFn } from "ahooks";
-import { Virtuoso, type VirtuosoHandle } from "react-virtuoso";
-import {
-  getConnections,
-  providerHealthCheck,
-  updateProxy,
-  deleteConnection,
-} from "@/services/api";
-import { useProfiles } from "@/hooks/use-profiles";
-import { useVerge } from "@/hooks/use-verge";
-import { BaseEmpty } from "../base";
-import { useRenderList } from "./use-render-list";
-import { ProxyRender } from "./proxy-render";
-import delayManager from "@/services/delay";
-
-interface Props {
-  mode: string;
-}
-
-export const ProxyGroups = (props: Props) => {
-  const { mode } = props;
-
-  const { renderList, onProxies, onHeadState } = useRenderList(mode);
-
-  const { verge } = useVerge();
-  const { current, patchCurrent } = useProfiles();
-
-  const virtuosoRef = useRef<VirtuosoHandle>(null);
-
-  // 切换分组的节点代理
-  const handleChangeProxy = useLockFn(
-    async (group: IProxyGroupItem, proxy: IProxyItem) => {
-      if (group.type !== "Selector" && group.type !== "Fallback") return;
-
-      const { name, now } = group;
-      await updateProxy(name, proxy.name);
-      onProxies();
-
-      // 断开连接
-      if (verge?.auto_close_connection) {
-        getConnections().then(({ connections }) => {
-          connections.forEach((conn) => {
-            if (conn.chains.includes(now!)) {
-              deleteConnection(conn.id);
-            }
-          });
-        });
-      }
-
-      // 保存到selected中
-      if (!current) return;
-      if (!current.selected) current.selected = [];
-
-      const index = current.selected.findIndex(
-        (item) => item.name === group.name
-      );
-
-      if (index < 0) {
-        current.selected.push({ name, now: proxy.name });
-      } else {
-        current.selected[index] = { name, now: proxy.name };
-      }
-      await patchCurrent({ selected: current.selected });
-    }
-  );
-
-  // 测全部延迟
-  const handleCheckAll = useLockFn(async (groupName: string) => {
-    const proxies = renderList
-      .filter(
-        (e) => e.group?.name === groupName && (e.type === 2 || e.type === 4)
-      )
-      .flatMap((e) => e.proxyCol || e.proxy!)
-      .filter(Boolean);
-
-    const providers = new Set(proxies.map((p) => p!.provider!).filter(Boolean));
-
-    if (providers.size) {
-      Promise.allSettled(
-        [...providers].map((p) => providerHealthCheck(p))
-      ).then(() => onProxies());
-    }
-
-    const names = proxies.filter((p) => !p!.provider).map((p) => p!.name);
-    await delayManager.checkListDelay(names, groupName);
-
-    onProxies();
-  });
-
-  // 滚到对应的节点
-  const handleLocation = (group: IProxyGroupItem) => {
-    if (!group) return;
-    const { name, now } = group;
-
-    const index = renderList.findIndex(
-      (e) =>
-        e.group?.name === name &&
-        ((e.type === 2 && e.proxy?.name === now) ||
-          (e.type === 4 && e.proxyCol?.some((p) => p.name === now)))
-    );
-
-    if (index >= 0) {
-      virtuosoRef.current?.scrollToIndex?.({
-        index,
-        align: "center",
-        behavior: "smooth",
-      });
-    }
-  };
-
-  if (mode === "direct") {
-    return <BaseEmpty text="Direct Mode" />;
-  }
-
-  return (
-    <Virtuoso
-      ref={virtuosoRef}
-      style={{ height: "100%" }}
-      totalCount={renderList.length}
-      increaseViewportBy={256}
-      itemContent={(index) => (
-        <ProxyRender
-          key={renderList[index].key}
-          item={renderList[index]}
-          indent={mode === "rule" || mode === "script"}
-          onLocation={handleLocation}
-          onCheckAll={handleCheckAll}
-          onHeadState={onHeadState}
-          onChangeProxy={handleChangeProxy}
-        />
-      )}
-    />
-  );
-};
diff --git a/src/components/proxy/proxy-head.tsx b/src/components/proxy/proxy-head.tsx
deleted file mode 100644
index fe29cb83bffa4b93903398c4869d56e4f92b8642..0000000000000000000000000000000000000000
--- a/src/components/proxy/proxy-head.tsx
+++ /dev/null
@@ -1,162 +0,0 @@
-import { useEffect, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { Box, IconButton, TextField, SxProps } from "@mui/material";
-import {
-  AccessTimeRounded,
-  MyLocationRounded,
-  NetworkCheckRounded,
-  FilterAltRounded,
-  FilterAltOffRounded,
-  VisibilityRounded,
-  VisibilityOffRounded,
-  WifiTetheringRounded,
-  WifiTetheringOffRounded,
-  SortByAlphaRounded,
-  SortRounded,
-} from "@mui/icons-material";
-import { useVerge } from "@/hooks/use-verge";
-import type { HeadState } from "./use-head-state";
-import type { ProxySortType } from "./use-filter-sort";
-import delayManager from "@/services/delay";
-
-interface Props {
-  sx?: SxProps;
-  groupName: string;
-  headState: HeadState;
-  onLocation: () => void;
-  onCheckDelay: () => void;
-  onHeadState: (val: Partial<HeadState>) => void;
-}
-
-export const ProxyHead = (props: Props) => {
-  const { sx = {}, groupName, headState, onHeadState } = props;
-
-  const { showType, sortType, filterText, textState, testUrl } = headState;
-
-  const { t } = useTranslation();
-  const [autoFocus, setAutoFocus] = useState(false);
-
-  useEffect(() => {
-    // fix the focus conflict
-    const timer = setTimeout(() => setAutoFocus(true), 100);
-    return () => clearTimeout(timer);
-  }, []);
-
-  const { verge } = useVerge();
-
-  useEffect(() => {
-    delayManager.setUrl(groupName, testUrl || verge?.default_latency_test!);
-  }, [groupName, testUrl, verge?.default_latency_test]);
-
-  return (
-    <Box sx={{ display: "flex", alignItems: "center", gap: 0.5, ...sx }}>
-      <IconButton
-        size="small"
-        color="inherit"
-        title={t("Location")}
-        onClick={props.onLocation}
-      >
-        <MyLocationRounded />
-      </IconButton>
-
-      <IconButton
-        size="small"
-        color="inherit"
-        title={t("Delay check")}
-        onClick={() => {
-          // Remind the user that it is custom test url
-          if (testUrl?.trim() && textState !== "filter") {
-            onHeadState({ textState: "url" });
-          }
-          props.onCheckDelay();
-        }}
-      >
-        <NetworkCheckRounded />
-      </IconButton>
-
-      <IconButton
-        size="small"
-        color="inherit"
-        title={
-          [t("Sort by default"), t("Sort by delay"), t("Sort by name")][
-            sortType
-          ]
-        }
-        onClick={() =>
-          onHeadState({ sortType: ((sortType + 1) % 3) as ProxySortType })
-        }
-      >
-        {sortType !== 1 && sortType !== 2 && <SortRounded />}
-        {sortType === 1 && <AccessTimeRounded />}
-        {sortType === 2 && <SortByAlphaRounded />}
-      </IconButton>
-
-      <IconButton
-        size="small"
-        color="inherit"
-        title={t("Delay check URL")}
-        onClick={() =>
-          onHeadState({ textState: textState === "url" ? null : "url" })
-        }
-      >
-        {textState === "url" ? (
-          <WifiTetheringRounded />
-        ) : (
-          <WifiTetheringOffRounded />
-        )}
-      </IconButton>
-
-      <IconButton
-        size="small"
-        color="inherit"
-        title={t("Proxy detail")}
-        onClick={() => onHeadState({ showType: !showType })}
-      >
-        {showType ? <VisibilityRounded /> : <VisibilityOffRounded />}
-      </IconButton>
-
-      <IconButton
-        size="small"
-        color="inherit"
-        title={t("Filter")}
-        onClick={() =>
-          onHeadState({ textState: textState === "filter" ? null : "filter" })
-        }
-      >
-        {textState === "filter" ? (
-          <FilterAltRounded />
-        ) : (
-          <FilterAltOffRounded />
-        )}
-      </IconButton>
-
-      {textState === "filter" && (
-        <TextField
-          autoFocus={autoFocus}
-          hiddenLabel
-          value={filterText}
-          size="small"
-          variant="outlined"
-          placeholder={t("Filter conditions")}
-          onChange={(e) => onHeadState({ filterText: e.target.value })}
-          sx={{ ml: 0.5, flex: "1 1 auto", input: { py: 0.65, px: 1 } }}
-        />
-      )}
-
-      {textState === "url" && (
-        <TextField
-          autoFocus={autoFocus}
-          hiddenLabel
-          autoSave="off"
-          autoComplete="off"
-          value={testUrl}
-          size="small"
-          variant="outlined"
-          placeholder={t("Delay check URL")}
-          onChange={(e) => onHeadState({ testUrl: e.target.value })}
-          sx={{ ml: 0.5, flex: "1 1 auto", input: { py: 0.65, px: 1 } }}
-        />
-      )}
-    </Box>
-  );
-};
diff --git a/src/components/proxy/proxy-item-mini.tsx b/src/components/proxy/proxy-item-mini.tsx
deleted file mode 100644
index c7e98bceba79897a7125afe0bc4aa4af9b52c1e0..0000000000000000000000000000000000000000
--- a/src/components/proxy/proxy-item-mini.tsx
+++ /dev/null
@@ -1,181 +0,0 @@
-import { useEffect, useState } from "react";
-import { useLockFn } from "ahooks";
-import { CheckCircleOutlineRounded } from "@mui/icons-material";
-import { alpha, Box, ListItemButton, styled, Typography } from "@mui/material";
-import { BaseLoading } from "@/components/base";
-import delayManager from "@/services/delay";
-
-interface Props {
-  groupName: string;
-  proxy: IProxyItem;
-  selected: boolean;
-  showType?: boolean;
-  onClick?: (name: string) => void;
-}
-
-// 多列布局
-export const ProxyItemMini = (props: Props) => {
-  const { groupName, proxy, selected, showType = true, onClick } = props;
-
-  // -1/<=0 为 不显示
-  // -2 为 loading
-  const [delay, setDelay] = useState(-1);
-
-  useEffect(() => {
-    delayManager.setListener(proxy.name, groupName, setDelay);
-
-    return () => {
-      delayManager.removeListener(proxy.name, groupName);
-    };
-  }, [proxy.name, groupName]);
-
-  useEffect(() => {
-    if (!proxy) return;
-    setDelay(delayManager.getDelayFix(proxy, groupName));
-  }, [proxy]);
-
-  const onDelay = useLockFn(async () => {
-    setDelay(-2);
-    setDelay(await delayManager.checkDelay(proxy.name, groupName));
-  });
-
-  return (
-    <ListItemButton
-      dense
-      selected={selected}
-      onClick={() => onClick?.(proxy.name)}
-      sx={[
-        {
-          height: 56,
-          borderRadius: 1,
-          pl: 1.5,
-          pr: 1,
-          justifyContent: "space-between",
-          alignItems: "center",
-        },
-        ({ palette: { mode, primary } }) => {
-          const bgcolor =
-            mode === "light"
-              ? alpha(primary.main, 0.15)
-              : alpha(primary.main, 0.35);
-          const color = mode === "light" ? primary.main : primary.light;
-          const showDelay = delay > 0;
-
-          const shadowColor =
-            mode === "light" ? "rgba(0,0,0,0.04)" : "rgba(255,255,255,0.08)";
-
-          return {
-            "&:hover .the-check": { display: !showDelay ? "block" : "none" },
-            "&:hover .the-delay": { display: showDelay ? "block" : "none" },
-            "&:hover .the-icon": { display: "none" },
-            "&.Mui-selected": { bgcolor, boxShadow: `0 0 0 1px ${bgcolor}` },
-            "&.Mui-selected .MuiListItemText-secondary": { color },
-            boxShadow: `0 0 0 1px ${shadowColor}`,
-          };
-        },
-      ]}
-    >
-      <Box title={proxy.name} sx={{ overflow: "hidden" }}>
-        <Typography
-          variant="body2"
-          component="div"
-          color="text.secondary"
-          sx={{
-            display: "block",
-            textOverflow: "ellipsis",
-            wordBreak: "break-all",
-            overflow: "hidden",
-            whiteSpace: "nowrap",
-          }}
-        >
-          {proxy.name}
-        </Typography>
-
-        {showType && (
-          <Box sx={{ display: "flex", flexWrap: "nowrap", flex: "none" }}>
-            {!!proxy.provider && (
-              <TypeBox component="span">{proxy.provider}</TypeBox>
-            )}
-            <TypeBox component="span">{proxy.type}</TypeBox>
-            {proxy.udp && <TypeBox component="span">UDP</TypeBox>}
-          </Box>
-        )}
-      </Box>
-
-      <Box sx={{ ml: 0.5, color: "primary.main" }}>
-        {delay === -2 && (
-          <Widget>
-            <BaseLoading />
-          </Widget>
-        )}
-
-        {!proxy.provider && delay !== -2 && (
-          // provider的节点不支持检测
-          <Widget
-            className="the-check"
-            onClick={(e) => {
-              e.preventDefault();
-              e.stopPropagation();
-              onDelay();
-            }}
-            sx={({ palette }) => ({
-              display: "none", // hover才显示
-              ":hover": { bgcolor: alpha(palette.primary.main, 0.15) },
-            })}
-          >
-            Check
-          </Widget>
-        )}
-
-        {delay > 0 && (
-          // 显示延迟
-          <Widget
-            className="the-delay"
-            onClick={(e) => {
-              if (proxy.provider) return;
-              e.preventDefault();
-              e.stopPropagation();
-              onDelay();
-            }}
-            color={delayManager.formatDelayColor(delay)}
-            sx={({ palette }) =>
-              !proxy.provider
-                ? { ":hover": { bgcolor: alpha(palette.primary.main, 0.15) } }
-                : {}
-            }
-          >
-            {delayManager.formatDelay(delay)}
-          </Widget>
-        )}
-
-        {delay !== -2 && delay <= 0 && selected && (
-          // 展示已选择的icon
-          <CheckCircleOutlineRounded
-            className="the-icon"
-            sx={{ fontSize: 16, mr: 0.5, display: "block" }}
-          />
-        )}
-      </Box>
-    </ListItemButton>
-  );
-};
-
-const Widget = styled(Box)(({ theme: { typography } }) => ({
-  padding: "3px 6px",
-  fontSize: 14,
-  fontFamily: typography.fontFamily,
-  borderRadius: "4px",
-}));
-
-const TypeBox = styled(Box)(({ theme: { palette, typography } }) => ({
-  display: "inline-block",
-  border: "1px solid #ccc",
-  borderColor: alpha(palette.text.secondary, 0.36),
-  color: alpha(palette.text.secondary, 0.42),
-  borderRadius: 4,
-  fontSize: 10,
-  fontFamily: typography.fontFamily,
-  marginRight: "4px",
-  padding: "0 2px",
-  lineHeight: 1.25,
-}));
diff --git a/src/components/proxy/proxy-item.tsx b/src/components/proxy/proxy-item.tsx
deleted file mode 100644
index d4c63c4a6ba84071b5b35f98dade9f318a8f7af3..0000000000000000000000000000000000000000
--- a/src/components/proxy/proxy-item.tsx
+++ /dev/null
@@ -1,170 +0,0 @@
-import { useEffect, useState } from "react";
-import { useLockFn } from "ahooks";
-import { CheckCircleOutlineRounded } from "@mui/icons-material";
-import {
-  alpha,
-  Box,
-  ListItem,
-  ListItemButton,
-  ListItemIcon,
-  ListItemText,
-  styled,
-  SxProps,
-  Theme,
-} from "@mui/material";
-import { BaseLoading } from "@/components/base";
-import delayManager from "@/services/delay";
-
-interface Props {
-  groupName: string;
-  proxy: IProxyItem;
-  selected: boolean;
-  showType?: boolean;
-  sx?: SxProps<Theme>;
-  onClick?: (name: string) => void;
-}
-
-const Widget = styled(Box)(() => ({
-  padding: "3px 6px",
-  fontSize: 14,
-  borderRadius: "4px",
-}));
-
-const TypeBox = styled(Box)(({ theme }) => ({
-  display: "inline-block",
-  border: "1px solid #ccc",
-  borderColor: alpha(theme.palette.text.secondary, 0.36),
-  color: alpha(theme.palette.text.secondary, 0.42),
-  borderRadius: 4,
-  fontSize: 10,
-  marginRight: "4px",
-  padding: "0 2px",
-  lineHeight: 1.25,
-}));
-
-export const ProxyItem = (props: Props) => {
-  const { groupName, proxy, selected, showType = true, sx, onClick } = props;
-
-  // -1/<=0 为 不显示
-  // -2 为 loading
-  const [delay, setDelay] = useState(-1);
-
-  useEffect(() => {
-    delayManager.setListener(proxy.name, groupName, setDelay);
-
-    return () => {
-      delayManager.removeListener(proxy.name, groupName);
-    };
-  }, [proxy.name, groupName]);
-
-  useEffect(() => {
-    if (!proxy) return;
-    setDelay(delayManager.getDelayFix(proxy, groupName));
-  }, [proxy]);
-
-  const onDelay = useLockFn(async () => {
-    setDelay(-2);
-    setDelay(await delayManager.checkDelay(proxy.name, groupName));
-  });
-
-  return (
-    <ListItem sx={sx}>
-      <ListItemButton
-        dense
-        selected={selected}
-        onClick={() => onClick?.(proxy.name)}
-        sx={[
-          { borderRadius: 1 },
-          ({ palette: { mode, primary } }) => {
-            const bgcolor =
-              mode === "light"
-                ? alpha(primary.main, 0.15)
-                : alpha(primary.main, 0.35);
-            const color = mode === "light" ? primary.main : primary.light;
-            const showDelay = delay > 0;
-
-            return {
-              "&:hover .the-check": { display: !showDelay ? "block" : "none" },
-              "&:hover .the-delay": { display: showDelay ? "block" : "none" },
-              "&:hover .the-icon": { display: "none" },
-              "&.Mui-selected": { bgcolor },
-              "&.Mui-selected .MuiListItemText-secondary": { color },
-            };
-          },
-        ]}
-      >
-        <ListItemText
-          title={proxy.name}
-          secondary={
-            <>
-              <span style={{ marginRight: 4 }}>{proxy.name}</span>
-
-              {showType && !!proxy.provider && (
-                <TypeBox component="span">{proxy.provider}</TypeBox>
-              )}
-              {showType && <TypeBox component="span">{proxy.type}</TypeBox>}
-              {showType && proxy.udp && <TypeBox component="span">UDP</TypeBox>}
-            </>
-          }
-        />
-
-        <ListItemIcon
-          sx={{ justifyContent: "flex-end", color: "primary.main" }}
-        >
-          {delay === -2 && (
-            <Widget>
-              <BaseLoading />
-            </Widget>
-          )}
-
-          {!proxy.provider && delay !== -2 && (
-            // provider的节点不支持检测
-            <Widget
-              className="the-check"
-              onClick={(e) => {
-                e.preventDefault();
-                e.stopPropagation();
-                onDelay();
-              }}
-              sx={({ palette }) => ({
-                display: "none", // hover才显示
-                ":hover": { bgcolor: alpha(palette.primary.main, 0.15) },
-              })}
-            >
-              Check
-            </Widget>
-          )}
-
-          {delay > 0 && (
-            // 显示延迟
-            <Widget
-              className="the-delay"
-              onClick={(e) => {
-                if (proxy.provider) return;
-                e.preventDefault();
-                e.stopPropagation();
-                onDelay();
-              }}
-              color={delayManager.formatDelayColor(delay)}
-              sx={({ palette }) =>
-                !proxy.provider
-                  ? { ":hover": { bgcolor: alpha(palette.primary.main, 0.15) } }
-                  : {}
-              }
-            >
-              {delayManager.formatDelay(delay)}
-            </Widget>
-          )}
-
-          {delay !== -2 && delay <= 0 && selected && (
-            // 展示已选择的icon
-            <CheckCircleOutlineRounded
-              className="the-icon"
-              sx={{ fontSize: 16 }}
-            />
-          )}
-        </ListItemIcon>
-      </ListItemButton>
-    </ListItem>
-  );
-};
diff --git a/src/components/proxy/proxy-render.tsx b/src/components/proxy/proxy-render.tsx
deleted file mode 100644
index 012064a19d87ad6ca59edb257b7e57ffc5df3c46..0000000000000000000000000000000000000000
--- a/src/components/proxy/proxy-render.tsx
+++ /dev/null
@@ -1,159 +0,0 @@
-import {
-  alpha,
-  Box,
-  ListItemText,
-  ListItemButton,
-  Typography,
-  styled,
-} from "@mui/material";
-import {
-  ExpandLessRounded,
-  ExpandMoreRounded,
-  InboxRounded,
-} from "@mui/icons-material";
-import { HeadState } from "./use-head-state";
-import { ProxyHead } from "./proxy-head";
-import { ProxyItem } from "./proxy-item";
-import { ProxyItemMini } from "./proxy-item-mini";
-import type { IRenderItem } from "./use-render-list";
-
-interface RenderProps {
-  item: IRenderItem;
-  indent: boolean;
-  onLocation: (group: IProxyGroupItem) => void;
-  onCheckAll: (groupName: string) => void;
-  onHeadState: (groupName: string, patch: Partial<HeadState>) => void;
-  onChangeProxy: (group: IProxyGroupItem, proxy: IProxyItem) => void;
-}
-
-export const ProxyRender = (props: RenderProps) => {
-  const { indent, item, onLocation, onCheckAll, onHeadState, onChangeProxy } =
-    props;
-  const { type, group, headState, proxy, proxyCol } = item;
-
-  if (type === 0) {
-    return (
-      <ListItemButton
-        dense
-        onClick={() => onHeadState(group.name, { open: !headState?.open })}
-      >
-        <ListItemText
-          primary={group.name}
-          secondary={
-            <ListItemTextChild
-              sx={{
-                overflow: "hidden",
-                display: "flex",
-                alignItems: "center",
-                pt: "2px",
-              }}
-            >
-              <StyledTypeBox>{group.type}</StyledTypeBox>
-              <StyledSubtitle>{group.now}</StyledSubtitle>
-            </ListItemTextChild>
-          }
-          secondaryTypographyProps={{
-            sx: { display: "flex", alignItems: "center" },
-          }}
-        />
-        {headState?.open ? <ExpandLessRounded /> : <ExpandMoreRounded />}
-      </ListItemButton>
-    );
-  }
-
-  if (type === 1) {
-    return (
-      <ProxyHead
-        sx={{ pl: indent ? 4.5 : 2.5, pr: 3, mt: indent ? 1 : 0.5, mb: 1 }}
-        groupName={group.name}
-        headState={headState!}
-        onLocation={() => onLocation(group)}
-        onCheckDelay={() => onCheckAll(group.name)}
-        onHeadState={(p) => onHeadState(group.name, p)}
-      />
-    );
-  }
-
-  if (type === 2) {
-    return (
-      <ProxyItem
-        groupName={group.name}
-        proxy={proxy!}
-        selected={group.now === proxy?.name}
-        showType={headState?.showType}
-        sx={{ py: 0, pl: indent ? 4 : 2 }}
-        onClick={() => onChangeProxy(group, proxy!)}
-      />
-    );
-  }
-
-  if (type === 3) {
-    return (
-      <Box
-        sx={{
-          py: 2,
-          pl: indent ? 4.5 : 0,
-          display: "flex",
-          flexDirection: "column",
-          alignItems: "center",
-          justifyContent: "center",
-        }}
-      >
-        <InboxRounded sx={{ fontSize: "2.5em", color: "inherit" }} />
-        <Typography sx={{ color: "inherit" }}>No Proxies</Typography>
-      </Box>
-    );
-  }
-
-  if (type === 4) {
-    return (
-      <Box
-        sx={{
-          height: 56,
-          display: "grid",
-          gap: 1,
-          pl: indent ? 4 : 2,
-          pr: 2,
-          pb: 1,
-          gridTemplateColumns: `repeat(${item.col! || 2}, 1fr)`,
-        }}
-      >
-        {proxyCol?.map((proxy) => (
-          <ProxyItemMini
-            key={item.key + proxy.name}
-            groupName={group.name}
-            proxy={proxy!}
-            selected={group.now === proxy.name}
-            showType={headState?.showType}
-            onClick={() => onChangeProxy(group, proxy!)}
-          />
-        ))}
-      </Box>
-    );
-  }
-
-  return null;
-};
-
-const StyledSubtitle = styled("span")`
-  font-size: 0.8rem;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-`;
-
-const ListItemTextChild = styled("span")`
-  display: block;
-`;
-
-const StyledTypeBox = styled(ListItemTextChild)(({ theme }) => ({
-  display: "inline-block",
-  border: "1px solid #ccc",
-  borderColor: alpha(theme.palette.primary.main, 0.5),
-  color: alpha(theme.palette.primary.main, 0.8),
-  borderRadius: 4,
-  fontSize: 10,
-  padding: "0 2px",
-  lineHeight: 1.25,
-  marginRight: "4px",
-}));
diff --git a/src/components/proxy/use-filter-sort.ts b/src/components/proxy/use-filter-sort.ts
deleted file mode 100644
index 3d7b7fd98f2c195c4a91b030e0bc818d940acbea..0000000000000000000000000000000000000000
--- a/src/components/proxy/use-filter-sort.ts
+++ /dev/null
@@ -1,125 +0,0 @@
-import { useEffect, useMemo, useState } from "react";
-import delayManager from "@/services/delay";
-
-// default | delay | alphabet
-export type ProxySortType = 0 | 1 | 2;
-
-export default function useFilterSort(
-  proxies: IProxyItem[],
-  groupName: string,
-  filterText: string,
-  sortType: ProxySortType
-) {
-  const [refresh, setRefresh] = useState({});
-
-  useEffect(() => {
-    let last = 0;
-
-    delayManager.setGroupListener(groupName, () => {
-      // 简单节流
-      const now = Date.now();
-      if (now - last > 666) {
-        last = now;
-        setRefresh({});
-      }
-    });
-
-    return () => {
-      delayManager.removeGroupListener(groupName);
-    };
-  }, [groupName]);
-
-  return useMemo(() => {
-    const fp = filterProxies(proxies, groupName, filterText);
-    const sp = sortProxies(fp, groupName, sortType);
-    return sp;
-  }, [proxies, groupName, filterText, sortType, refresh]);
-}
-
-export function filterSort(
-  proxies: IProxyItem[],
-  groupName: string,
-  filterText: string,
-  sortType: ProxySortType
-) {
-  const fp = filterProxies(proxies, groupName, filterText);
-  const sp = sortProxies(fp, groupName, sortType);
-  return sp;
-}
-
-/**
- * 可以通过延迟数/节点类型 过滤
- */
-const regex1 = /delay([=<>])(\d+|timeout|error)/i;
-const regex2 = /type=(.*)/i;
-
-/**
- * filter the proxy
- * according to the regular conditions
- */
-function filterProxies(
-  proxies: IProxyItem[],
-  groupName: string,
-  filterText: string
-) {
-  if (!filterText) return proxies;
-
-  const res1 = regex1.exec(filterText);
-  if (res1) {
-    const symbol = res1[1];
-    const symbol2 = res1[2].toLowerCase();
-    const value =
-      symbol2 === "error" ? 1e5 : symbol2 === "timeout" ? 3000 : +symbol2;
-
-    return proxies.filter((p) => {
-      const delay = delayManager.getDelayFix(p, groupName);
-
-      if (delay < 0) return false;
-      if (symbol === "=" && symbol2 === "error") return delay >= 1e5;
-      if (symbol === "=" && symbol2 === "timeout")
-        return delay < 1e5 && delay >= 3000;
-      if (symbol === "=") return delay == value;
-      if (symbol === "<") return delay <= value;
-      if (symbol === ">") return delay >= value;
-      return false;
-    });
-  }
-
-  const res2 = regex2.exec(filterText);
-  if (res2) {
-    const type = res2[1].toLowerCase();
-    return proxies.filter((p) => p.type.toLowerCase().includes(type));
-  }
-
-  return proxies.filter((p) => p.name.includes(filterText.trim()));
-}
-
-/**
- * sort the proxy
- */
-function sortProxies(
-  proxies: IProxyItem[],
-  groupName: string,
-  sortType: ProxySortType
-) {
-  if (!proxies) return [];
-  if (sortType === 0) return proxies;
-
-  const list = proxies.slice();
-
-  if (sortType === 1) {
-    list.sort((a, b) => {
-      const ad = delayManager.getDelayFix(a, groupName);
-      const bd = delayManager.getDelayFix(b, groupName);
-
-      if (ad === -1 || ad === -2) return 1;
-      if (bd === -1 || bd === -2) return -1;
-
-      return ad - bd;
-    });
-  } else {
-    list.sort((a, b) => a.name.localeCompare(b.name));
-  }
-
-  return list;
-}
diff --git a/src/components/proxy/use-head-state.ts b/src/components/proxy/use-head-state.ts
deleted file mode 100644
index d1bce2fcf03788bc55ea8de30b912d27a36f38ba..0000000000000000000000000000000000000000
--- a/src/components/proxy/use-head-state.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import { useCallback, useEffect, useState } from "react";
-import { ProxySortType } from "./use-filter-sort";
-import { useProfiles } from "@/hooks/use-profiles";
-
-export interface HeadState {
-  open?: boolean;
-  showType: boolean;
-  sortType: ProxySortType;
-  filterText: string;
-  textState: "url" | "filter" | null;
-  testUrl: string;
-}
-
-type HeadStateStorage = Record<string, Record<string, HeadState>>;
-
-const HEAD_STATE_KEY = "proxy-head-state";
-export const DEFAULT_STATE: HeadState = {
-  open: false,
-  showType: false,
-  sortType: 0,
-  filterText: "",
-  textState: null,
-  testUrl: "",
-};
-
-export function useHeadStateNew() {
-  const { profiles } = useProfiles();
-  const current = profiles?.current || "";
-
-  const [state, setState] = useState<Record<string, HeadState>>({});
-
-  useEffect(() => {
-    if (!current) {
-      setState({});
-      return;
-    }
-
-    try {
-      const data = JSON.parse(
-        localStorage.getItem(HEAD_STATE_KEY)!
-      ) as HeadStateStorage;
-
-      const value = data[current] || {};
-
-      if (value && typeof value === "object") {
-        setState(value);
-      } else {
-        setState({});
-      }
-    } catch {}
-  }, [current]);
-
-  const setHeadState = useCallback(
-    (groupName: string, obj: Partial<HeadState>) => {
-      setState((old) => {
-        const state = old[groupName] || DEFAULT_STATE;
-        const ret = { ...old, [groupName]: { ...state, ...obj } };
-
-        // 保存到存储中
-        setTimeout(() => {
-          try {
-            const item = localStorage.getItem(HEAD_STATE_KEY);
-
-            let data = (item ? JSON.parse(item) : {}) as HeadStateStorage;
-
-            if (!data || typeof data !== "object") data = {};
-
-            data[current] = ret;
-
-            localStorage.setItem(HEAD_STATE_KEY, JSON.stringify(data));
-          } catch {}
-        });
-
-        return ret;
-      });
-    },
-    [current]
-  );
-
-  return [state, setHeadState] as const;
-}
diff --git a/src/components/proxy/use-render-list.ts b/src/components/proxy/use-render-list.ts
deleted file mode 100644
index 9f8bc0a563221e2b9817db59a51944364a9beb3c..0000000000000000000000000000000000000000
--- a/src/components/proxy/use-render-list.ts
+++ /dev/null
@@ -1,141 +0,0 @@
-import useSWR from "swr";
-import { useEffect, useMemo } from "react";
-import { getProxies } from "@/services/api";
-import { useVerge } from "@/hooks/use-verge";
-import { filterSort } from "./use-filter-sort";
-import { useWindowWidth } from "./use-window-width";
-import {
-  useHeadStateNew,
-  DEFAULT_STATE,
-  type HeadState,
-} from "./use-head-state";
-
-export interface IRenderItem {
-  // 组 | head | item | empty | item col
-  type: 0 | 1 | 2 | 3 | 4;
-  key: string;
-  group: IProxyGroupItem;
-  proxy?: IProxyItem;
-  col?: number;
-  proxyCol?: IProxyItem[];
-  headState?: HeadState;
-}
-
-export const useRenderList = (mode: string) => {
-  const { data: proxiesData, mutate: mutateProxies } = useSWR(
-    "getProxies",
-    getProxies,
-    { refreshInterval: 45000 }
-  );
-
-  const { verge } = useVerge();
-  const { width } = useWindowWidth();
-
-  let col = Math.floor(verge?.proxy_layout_column || 6);
-
-  // 自适应
-  if (col >= 6 || col <= 0) {
-    if (width > 1450) col = 5;
-    else if (width > 1024) col = 4;
-    else if (width > 900) col = 3;
-    else if (width >= 600) col = 2;
-    else col = 1;
-  }
-
-  const [headStates, setHeadState] = useHeadStateNew();
-
-  // make sure that fetch the proxies successfully
-  useEffect(() => {
-    if (!proxiesData) return;
-    const { groups, proxies } = proxiesData;
-
-    if (
-      (mode === "rule" && !groups.length) ||
-      (mode === "global" && proxies.length < 2)
-    ) {
-      setTimeout(() => mutateProxies(), 500);
-    }
-  }, [proxiesData, mode]);
-
-  const renderList: IRenderItem[] = useMemo(() => {
-    if (!proxiesData) return [];
-
-    // global 和 direct 使用展开的样式
-    const useRule = mode === "rule" || mode === "script";
-    const renderGroups =
-      (useRule && proxiesData.groups.length
-        ? proxiesData.groups
-        : [proxiesData.global!]) || [];
-
-    const retList = renderGroups.flatMap((group) => {
-      const headState = headStates[group.name] || DEFAULT_STATE;
-      const ret: IRenderItem[] = [
-        { type: 0, key: group.name, group, headState },
-      ];
-
-      if (headState?.open || !useRule) {
-        const proxies = filterSort(
-          group.all,
-          group.name,
-          headState.filterText,
-          headState.sortType
-        );
-
-        ret.push({ type: 1, key: `head-${group.name}`, group, headState });
-
-        if (!proxies.length) {
-          ret.push({ type: 3, key: `empty-${group.name}`, group, headState });
-        }
-
-        // 支持多列布局
-        if (col > 1) {
-          return ret.concat(
-            groupList(proxies, col).map((proxyCol) => ({
-              type: 4,
-              key: `col-${group.name}-${proxyCol[0].name}`,
-              group,
-              headState,
-              col,
-              proxyCol,
-            }))
-          );
-        }
-
-        return ret.concat(
-          proxies.map((proxy) => ({
-            type: 2,
-            key: `${group.name}-${proxy!.name}`,
-            group,
-            proxy,
-            headState,
-          }))
-        );
-      }
-      return ret;
-    });
-
-    if (!useRule) return retList.slice(1);
-    return retList;
-  }, [headStates, proxiesData, mode, col]);
-
-  return {
-    renderList,
-    onProxies: mutateProxies,
-    onHeadState: setHeadState,
-  };
-};
-
-function groupList<T = any>(list: T[], size: number): T[][] {
-  return list.reduce((p, n) => {
-    if (!p.length) return [[n]];
-
-    const i = p.length - 1;
-    if (p[i].length < size) {
-      p[i].push(n);
-      return p;
-    }
-
-    p.push([n]);
-    return p;
-  }, [] as T[][]);
-}
diff --git a/src/components/proxy/use-window-width.ts b/src/components/proxy/use-window-width.ts
deleted file mode 100644
index d1de3c354f683339584c3a82bad06a456262d115..0000000000000000000000000000000000000000
--- a/src/components/proxy/use-window-width.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { useEffect, useState } from "react";
-
-export const useWindowWidth = () => {
-  const [width, setWidth] = useState(() => document.body.clientWidth);
-
-  useEffect(() => {
-    const handleResize = () => setWidth(document.body.clientWidth);
-
-    window.addEventListener("resize", handleResize);
-    return () => {
-      window.removeEventListener("resize", handleResize);
-    };
-  }, []);
-
-  return { width };
-};
diff --git a/src/components/rule/rule-item.tsx b/src/components/rule/rule-item.tsx
deleted file mode 100644
index 3bf2291d3cb562ae33301e240e2faec23587094e..0000000000000000000000000000000000000000
--- a/src/components/rule/rule-item.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-import { styled, Box, Typography } from "@mui/material";
-
-const Item = styled(Box)(({ theme }) => ({
-  display: "flex",
-  padding: "4px 16px",
-  color: theme.palette.text.primary,
-}));
-
-const COLOR = [
-  "primary",
-  "secondary",
-  "info.main",
-  "warning.main",
-  "success.main",
-];
-
-interface Props {
-  index: number;
-  value: IRuleItem;
-}
-
-const parseColor = (text: string) => {
-  if (text === "REJECT") return "error.main";
-  if (text === "DIRECT") return "text.primary";
-
-  let sum = 0;
-  for (let i = 0; i < text.length; i++) {
-    sum += text.charCodeAt(i);
-  }
-  return COLOR[sum % COLOR.length];
-};
-
-const RuleItem = (props: Props) => {
-  const { index, value } = props;
-
-  return (
-    <Item>
-      <Typography
-        color="text.secondary"
-        variant="body2"
-        sx={{ lineHeight: 2, minWidth: 30, mr: 2.25, textAlign: "center" }}
-      >
-        {index}
-      </Typography>
-
-      <Box sx={{ userSelect: "text" }}>
-        <Typography component="h6" variant="subtitle1" color="text.primary">
-          {value.payload || "-"}
-        </Typography>
-
-        <Typography
-          component="span"
-          variant="body2"
-          color="text.secondary"
-          sx={{ mr: 3, minWidth: 120, display: "inline-block" }}
-        >
-          {value.type}
-        </Typography>
-
-        <Typography
-          component="span"
-          variant="body2"
-          color={parseColor(value.proxy)}
-        >
-          {value.proxy}
-        </Typography>
-      </Box>
-    </Item>
-  );
-};
-
-export default RuleItem;
diff --git a/src/components/setting/mods/clash-core-viewer.tsx b/src/components/setting/mods/clash-core-viewer.tsx
deleted file mode 100644
index f0436847acf9cb94983d83a23e82e1a8e5a75e08..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/clash-core-viewer.tsx
+++ /dev/null
@@ -1,132 +0,0 @@
-import { mutate } from "swr";
-import { forwardRef, useImperativeHandle, useState } from "react";
-import { BaseDialog, DialogRef, Notice } from "@/components/base";
-import { useTranslation } from "react-i18next";
-import { useVerge } from "@/hooks/use-verge";
-import { useLockFn } from "ahooks";
-import { Lock } from "@mui/icons-material";
-import {
-  Box,
-  Button,
-  IconButton,
-  List,
-  ListItemButton,
-  ListItemText,
-} from "@mui/material";
-import { changeClashCore, restartSidecar } from "@/services/cmds";
-import { closeAllConnections } from "@/services/api";
-import { grantPermission } from "@/services/cmds";
-import getSystem from "@/utils/get-system";
-
-const VALID_CORE = [
-  { name: "Clash", core: "clash" },
-  { name: "Clash Meta", core: "clash-meta" },
-];
-
-const OS = getSystem();
-
-export const ClashCoreViewer = forwardRef<DialogRef>((props, ref) => {
-  const { t } = useTranslation();
-
-  const { verge, mutateVerge } = useVerge();
-
-  const [open, setOpen] = useState(false);
-
-  useImperativeHandle(ref, () => ({
-    open: () => setOpen(true),
-    close: () => setOpen(false),
-  }));
-
-  const { clash_core = "clash" } = verge ?? {};
-
-  const onCoreChange = useLockFn(async (core: string) => {
-    if (core === clash_core) return;
-
-    try {
-      closeAllConnections();
-      await changeClashCore(core);
-      mutateVerge();
-      setTimeout(() => {
-        mutate("getClashConfig");
-        mutate("getVersion");
-      }, 100);
-      Notice.success(`Successfully switch to ${core}`, 1000);
-    } catch (err: any) {
-      Notice.error(err?.message || err.toString());
-    }
-  });
-
-  const onGrant = useLockFn(async (core: string) => {
-    try {
-      await grantPermission(core);
-      // 自动重启
-      if (core === clash_core) await restartSidecar();
-      Notice.success(`Successfully grant permission to ${core}`, 1000);
-    } catch (err: any) {
-      Notice.error(err?.message || err.toString());
-    }
-  });
-
-  const onRestart = useLockFn(async () => {
-    try {
-      await restartSidecar();
-      Notice.success(`Successfully restart core`, 1000);
-    } catch (err: any) {
-      Notice.error(err?.message || err.toString());
-    }
-  });
-
-  return (
-    <BaseDialog
-      open={open}
-      title={
-        <Box display="flex" justifyContent="space-between">
-          {t("Clash Core")}
-
-          <Button variant="contained" size="small" onClick={onRestart}>
-            {t("Restart")}
-          </Button>
-        </Box>
-      }
-      contentSx={{
-        pb: 0,
-        width: 320,
-        height: 200,
-        overflowY: "auto",
-        userSelect: "text",
-        marginTop: "-8px",
-      }}
-      disableOk
-      cancelBtn={t("Back")}
-      onClose={() => setOpen(false)}
-      onCancel={() => setOpen(false)}
-    >
-      <List component="nav">
-        {VALID_CORE.map((each) => (
-          <ListItemButton
-            key={each.core}
-            selected={each.core === clash_core}
-            onClick={() => onCoreChange(each.core)}
-          >
-            <ListItemText primary={each.name} secondary={`/${each.core}`} />
-
-            {(OS === "macos" || OS === "linux") && (
-              <IconButton
-                color="inherit"
-                size="small"
-                edge="end"
-                onClick={(e) => {
-                  e.preventDefault();
-                  e.stopPropagation();
-                  onGrant(each.core);
-                }}
-              >
-                <Lock fontSize="inherit" />
-              </IconButton>
-            )}
-          </ListItemButton>
-        ))}
-      </List>
-    </BaseDialog>
-  );
-});
diff --git a/src/components/setting/mods/clash-field-viewer.tsx b/src/components/setting/mods/clash-field-viewer.tsx
deleted file mode 100644
index 8185cbaf8ab530694a4feb4b111a3fe7fdff2a55..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/clash-field-viewer.tsx
+++ /dev/null
@@ -1,123 +0,0 @@
-import useSWR from "swr";
-import { forwardRef, useImperativeHandle, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { Checkbox, Divider, Stack, Tooltip, Typography } from "@mui/material";
-import { InfoRounded } from "@mui/icons-material";
-import { getRuntimeExists } from "@/services/cmds";
-import {
-  HANDLE_FIELDS,
-  DEFAULT_FIELDS,
-  OTHERS_FIELDS,
-} from "@/utils/clash-fields";
-import { BaseDialog, DialogRef } from "@/components/base";
-import { useProfiles } from "@/hooks/use-profiles";
-import { Notice } from "@/components/base";
-
-const otherFields = [...OTHERS_FIELDS];
-const handleFields = [...HANDLE_FIELDS, ...DEFAULT_FIELDS];
-
-export const ClashFieldViewer = forwardRef<DialogRef>((props, ref) => {
-  const { t } = useTranslation();
-
-  const { profiles = {}, patchProfiles } = useProfiles();
-  const { data: existsKeys = [], mutate: mutateExists } = useSWR(
-    "getRuntimeExists",
-    getRuntimeExists
-  );
-
-  const [open, setOpen] = useState(false);
-  const [selected, setSelected] = useState<string[]>([]);
-
-  useImperativeHandle(ref, () => ({
-    open: () => {
-      mutateExists();
-      setSelected(profiles.valid || []);
-      setOpen(true);
-    },
-    close: () => setOpen(false),
-  }));
-
-  const handleChange = (item: string) => {
-    if (!item) return;
-
-    setSelected((old) =>
-      old.includes(item) ? old.filter((e) => e !== item) : [...old, item]
-    );
-  };
-
-  const handleSave = async () => {
-    setOpen(false);
-
-    const oldSet = new Set(profiles.valid || []);
-    const curSet = new Set(selected);
-    const joinSet = new Set(selected.concat([...oldSet]));
-
-    if (curSet.size === oldSet.size && curSet.size === joinSet.size) return;
-
-    try {
-      await patchProfiles({ valid: [...curSet] });
-      // Notice.success("Refresh clash config", 1000);
-    } catch (err: any) {
-      Notice.error(err?.message || err.toString());
-    }
-  };
-
-  return (
-    <BaseDialog
-      open={open}
-      title={t("Clash Field")}
-      contentSx={{
-        pb: 0,
-        width: 320,
-        height: 300,
-        overflowY: "auto",
-        userSelect: "text",
-      }}
-      okBtn={t("Save")}
-      cancelBtn={t("Back")}
-      onClose={() => setOpen(false)}
-      onCancel={() => setOpen(false)}
-      onOk={handleSave}
-    >
-      {otherFields.map((item) => {
-        const inSelect = selected.includes(item);
-        const inConfig = existsKeys.includes(item);
-
-        return (
-          <Stack key={item} mb={0.5} direction="row" alignItems="center">
-            <Checkbox
-              checked={inSelect}
-              size="small"
-              sx={{ p: 0.5 }}
-              onChange={() => handleChange(item)}
-            />
-            <Typography width="100%">{item}</Typography>
-
-            {!inSelect && inConfig && <WarnIcon />}
-          </Stack>
-        );
-      })}
-
-      <Divider sx={{ my: 1 }}>
-        <Typography color="text.secondary" fontSize={14}>
-          Clash Verge Control Fields
-        </Typography>
-      </Divider>
-
-      {handleFields.map((item) => (
-        <Stack key={item} mb={0.5} direction="row" alignItems="center">
-          <Checkbox defaultChecked disabled size="small" sx={{ p: 0.5 }} />
-          <Typography>{item}</Typography>
-        </Stack>
-      ))}
-    </BaseDialog>
-  );
-});
-
-function WarnIcon() {
-  return (
-    <Tooltip title="The field exists in the config but not enabled.">
-      <InfoRounded color="warning" sx={{ cursor: "pointer", opacity: 0.5 }} />
-    </Tooltip>
-  );
-}
diff --git a/src/components/setting/mods/clash-port-viewer.tsx b/src/components/setting/mods/clash-port-viewer.tsx
deleted file mode 100644
index 2079740536eed186cd77c707478692efc264eace..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/clash-port-viewer.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import { forwardRef, useImperativeHandle, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { useLockFn } from "ahooks";
-import { List, ListItem, ListItemText, TextField } from "@mui/material";
-import { useClashInfo } from "@/hooks/use-clash";
-import { BaseDialog, DialogRef, Notice } from "@/components/base";
-
-export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
-  const { t } = useTranslation();
-
-  const { clashInfo, patchInfo } = useClashInfo();
-
-  const [open, setOpen] = useState(false);
-  const [port, setPort] = useState(clashInfo?.port ?? 7890);
-
-  useImperativeHandle(ref, () => ({
-    open: () => {
-      if (clashInfo?.port) setPort(clashInfo?.port);
-      setOpen(true);
-    },
-    close: () => setOpen(false),
-  }));
-
-  const onSave = useLockFn(async () => {
-    if (port === clashInfo?.port) {
-      setOpen(false);
-      return;
-    }
-    try {
-      await patchInfo({ "mixed-port": port });
-      setOpen(false);
-      Notice.success("Change Clash port successfully!", 1000);
-    } catch (err: any) {
-      Notice.error(err.message || err.toString(), 4000);
-    }
-  });
-
-  return (
-    <BaseDialog
-      open={open}
-      title={t("Clash Port")}
-      contentSx={{ width: 300 }}
-      okBtn={t("Save")}
-      cancelBtn={t("Cancel")}
-      onClose={() => setOpen(false)}
-      onCancel={() => setOpen(false)}
-      onOk={onSave}
-    >
-      <List>
-        <ListItem sx={{ padding: "5px 2px" }}>
-          <ListItemText primary="Mixed Port" />
-          <TextField
-            size="small"
-            autoComplete="off"
-            sx={{ width: 135 }}
-            value={port}
-            onChange={(e) =>
-              setPort(+e.target.value?.replace(/\D+/, "").slice(0, 5))
-            }
-          />
-        </ListItem>
-      </List>
-    </BaseDialog>
-  );
-});
diff --git a/src/components/setting/mods/config-viewer.tsx b/src/components/setting/mods/config-viewer.tsx
deleted file mode 100644
index 22c169c299d064250e69d6f535ec3620a70f7c1d..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/config-viewer.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-import {
-  forwardRef,
-  useEffect,
-  useImperativeHandle,
-  useRef,
-  useState,
-} from "react";
-import { useTranslation } from "react-i18next";
-import { useRecoilValue } from "recoil";
-import { Chip } from "@mui/material";
-import { atomThemeMode } from "@/services/states";
-import { getRuntimeYaml } from "@/services/cmds";
-import { BaseDialog, DialogRef } from "@/components/base";
-import { editor } from "monaco-editor/esm/vs/editor/editor.api";
-
-import "monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution.js";
-import "monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution.js";
-import "monaco-editor/esm/vs/editor/contrib/folding/browser/folding.js";
-
-export const ConfigViewer = forwardRef<DialogRef>((props, ref) => {
-  const { t } = useTranslation();
-  const [open, setOpen] = useState(false);
-
-  const editorRef = useRef<any>();
-  const instanceRef = useRef<editor.IStandaloneCodeEditor | null>(null);
-  const themeMode = useRecoilValue(atomThemeMode);
-
-  useEffect(() => {
-    return () => {
-      if (instanceRef.current) {
-        instanceRef.current.dispose();
-        instanceRef.current = null;
-      }
-    };
-  }, []);
-
-  useImperativeHandle(ref, () => ({
-    open: () => {
-      setOpen(true);
-
-      getRuntimeYaml().then((data) => {
-        const dom = editorRef.current;
-
-        if (!dom) return;
-        if (instanceRef.current) instanceRef.current.dispose();
-
-        instanceRef.current = editor.create(editorRef.current, {
-          value: data ?? "# Error\n",
-          language: "yaml",
-          theme: themeMode === "light" ? "vs" : "vs-dark",
-          minimap: { enabled: false },
-          readOnly: true,
-        });
-      });
-    },
-    close: () => setOpen(false),
-  }));
-
-  return (
-    <BaseDialog
-      open={open}
-      title={
-        <>
-          {t("Runtime Config")} <Chip label={t("ReadOnly")} size="small" />
-        </>
-      }
-      contentSx={{ width: 520, pb: 1, userSelect: "text" }}
-      cancelBtn={t("Back")}
-      disableOk
-      onClose={() => setOpen(false)}
-      onCancel={() => setOpen(false)}
-    >
-      <div style={{ width: "100%", height: "420px" }} ref={editorRef} />
-    </BaseDialog>
-  );
-});
diff --git a/src/components/setting/mods/controller-viewer.tsx b/src/components/setting/mods/controller-viewer.tsx
deleted file mode 100644
index 17205d9cd8e899b633649c24c3047f596b56ea71..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/controller-viewer.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import { forwardRef, useImperativeHandle, useState } from "react";
-import { useLockFn } from "ahooks";
-import { useTranslation } from "react-i18next";
-import { List, ListItem, ListItemText, TextField } from "@mui/material";
-import { useClashInfo } from "@/hooks/use-clash";
-import { BaseDialog, DialogRef, Notice } from "@/components/base";
-
-export const ControllerViewer = forwardRef<DialogRef>((props, ref) => {
-  const { t } = useTranslation();
-  const [open, setOpen] = useState(false);
-
-  const { clashInfo, patchInfo } = useClashInfo();
-
-  const [controller, setController] = useState(clashInfo?.server || "");
-  const [secret, setSecret] = useState(clashInfo?.secret || "");
-
-  useImperativeHandle(ref, () => ({
-    open: () => {
-      setOpen(true);
-      setController(clashInfo?.server || "");
-      setSecret(clashInfo?.secret || "");
-    },
-    close: () => setOpen(false),
-  }));
-
-  const onSave = useLockFn(async () => {
-    try {
-      await patchInfo({ "external-controller": controller, secret });
-      Notice.success("Change Clash Config successfully!", 1000);
-      setOpen(false);
-    } catch (err: any) {
-      Notice.error(err.message || err.toString(), 4000);
-    }
-  });
-
-  return (
-    <BaseDialog
-      open={open}
-      title={t("Clash Port")}
-      contentSx={{ width: 400 }}
-      okBtn={t("Save")}
-      cancelBtn={t("Cancel")}
-      onClose={() => setOpen(false)}
-      onCancel={() => setOpen(false)}
-      onOk={onSave}
-    >
-      <List>
-        <ListItem sx={{ padding: "5px 2px" }}>
-          <ListItemText primary="External Controller" />
-          <TextField
-            size="small"
-            autoComplete="off"
-            sx={{ width: 175 }}
-            value={controller}
-            placeholder="Required"
-            onChange={(e) => setController(e.target.value)}
-          />
-        </ListItem>
-
-        <ListItem sx={{ padding: "5px 2px" }}>
-          <ListItemText primary="Core Secret" />
-          <TextField
-            size="small"
-            autoComplete="off"
-            sx={{ width: 175 }}
-            value={secret}
-            placeholder="Recommended"
-            onChange={(e) => setSecret(e.target.value)}
-          />
-        </ListItem>
-      </List>
-    </BaseDialog>
-  );
-});
diff --git a/src/components/setting/mods/guard-state.tsx b/src/components/setting/mods/guard-state.tsx
deleted file mode 100644
index 5ab8e99186c7035e2c93ef2e24725da1d399a365..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/guard-state.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import { cloneElement, isValidElement, ReactNode, useRef } from "react";
-import noop from "@/utils/noop";
-
-interface Props<Value> {
-  value?: Value;
-  valueProps?: string;
-  onChangeProps?: string;
-  waitTime?: number;
-  onChange?: (value: Value) => void;
-  onFormat?: (...args: any[]) => Value;
-  onGuard?: (value: Value, oldValue: Value) => Promise<void>;
-  onCatch?: (error: Error) => void;
-  children: ReactNode;
-}
-
-export function GuardState<T>(props: Props<T>) {
-  const {
-    value,
-    children,
-    valueProps = "value",
-    onChangeProps = "onChange",
-    waitTime = 0, // debounce wait time default 0
-    onGuard = noop,
-    onCatch = noop,
-    onChange = noop,
-    onFormat = (v: T) => v,
-  } = props;
-
-  const lockRef = useRef(false);
-  const saveRef = useRef(value);
-  const lastRef = useRef(0);
-  const timeRef = useRef<any>();
-
-  if (!isValidElement(children)) {
-    return children as any;
-  }
-
-  const childProps = { ...children.props };
-
-  childProps[valueProps] = value;
-  childProps[onChangeProps] = async (...args: any[]) => {
-    // 多次操作无效
-    if (lockRef.current) return;
-
-    lockRef.current = true;
-
-    try {
-      const newValue = (onFormat as any)(...args);
-      // 先在ui上响应操作
-      onChange(newValue);
-
-      const now = Date.now();
-
-      // save the old value
-      if (waitTime <= 0 || now - lastRef.current >= waitTime) {
-        saveRef.current = value;
-      }
-
-      lastRef.current = now;
-
-      if (waitTime <= 0) {
-        await onGuard(newValue, value!);
-      } else {
-        // debounce guard
-        clearTimeout(timeRef.current);
-
-        timeRef.current = setTimeout(async () => {
-          try {
-            await onGuard(newValue, saveRef.current!);
-          } catch (err: any) {
-            // 状态回退
-            onChange(saveRef.current!);
-            onCatch(err);
-          }
-        }, waitTime);
-      }
-    } catch (err: any) {
-      // 状态回退
-      onChange(saveRef.current!);
-      onCatch(err);
-    }
-    lockRef.current = false;
-  };
-  return cloneElement(children, childProps);
-}
diff --git a/src/components/setting/mods/hotkey-input.tsx b/src/components/setting/mods/hotkey-input.tsx
deleted file mode 100644
index a14658ac370a42fe8a9bfd6335193212c54295c2..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/hotkey-input.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-import { useRef, useState } from "react";
-import { alpha, Box, IconButton, styled } from "@mui/material";
-import { DeleteRounded } from "@mui/icons-material";
-import { parseHotkey } from "@/utils/parse-hotkey";
-
-const KeyWrapper = styled("div")(({ theme }) => ({
-  position: "relative",
-  width: 165,
-  minHeight: 36,
-
-  "> input": {
-    position: "absolute",
-    top: 0,
-    left: 0,
-    width: "100%",
-    height: "100%",
-    zIndex: 1,
-    opacity: 0,
-  },
-  "> input:focus + .list": {
-    borderColor: alpha(theme.palette.primary.main, 0.75),
-  },
-  ".list": {
-    display: "flex",
-    alignItems: "center",
-    flexWrap: "wrap",
-    width: "100%",
-    height: "100%",
-    minHeight: 36,
-    boxSizing: "border-box",
-    padding: "3px 4px",
-    border: "1px solid",
-    borderRadius: 4,
-    borderColor: alpha(theme.palette.text.secondary, 0.15),
-    "&:last-child": {
-      marginRight: 0,
-    },
-  },
-  ".item": {
-    color: theme.palette.text.primary,
-    border: "1px solid",
-    borderColor: alpha(theme.palette.text.secondary, 0.2),
-    borderRadius: "2px",
-    padding: "1px 1px",
-    margin: "2px 0",
-    marginRight: 8,
-  },
-}));
-
-interface Props {
-  value: string[];
-  onChange: (value: string[]) => void;
-}
-
-export const HotkeyInput = (props: Props) => {
-  const { value, onChange } = props;
-
-  const changeRef = useRef<string[]>([]);
-  const [keys, setKeys] = useState(value);
-
-  return (
-    <Box sx={{ display: "flex", alignItems: "center" }}>
-      <KeyWrapper>
-        <input
-          onKeyUp={() => {
-            const ret = changeRef.current.slice();
-            if (ret.length) {
-              onChange(ret);
-              changeRef.current = [];
-            }
-          }}
-          onKeyDown={(e) => {
-            const evt = e.nativeEvent;
-            e.preventDefault();
-            e.stopPropagation();
-
-            const key = parseHotkey(evt.key);
-            if (key === "UNIDENTIFIED") return;
-
-            changeRef.current = [...new Set([...changeRef.current, key])];
-            setKeys(changeRef.current);
-          }}
-        />
-
-        <div className="list">
-          {keys.map((key) => (
-            <div key={key} className="item">
-              {key}
-            </div>
-          ))}
-        </div>
-      </KeyWrapper>
-
-      <IconButton
-        size="small"
-        title="Delete"
-        color="inherit"
-        onClick={() => {
-          onChange([]);
-          setKeys([]);
-        }}
-      >
-        <DeleteRounded fontSize="inherit" />
-      </IconButton>
-    </Box>
-  );
-};
diff --git a/src/components/setting/mods/hotkey-viewer.tsx b/src/components/setting/mods/hotkey-viewer.tsx
deleted file mode 100644
index a47d30e62d1f60987f9e9e0769c7c9dea4c82712..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/hotkey-viewer.tsx
+++ /dev/null
@@ -1,106 +0,0 @@
-import { forwardRef, useImperativeHandle, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { useLockFn } from "ahooks";
-import { styled, Typography } from "@mui/material";
-import { useVerge } from "@/hooks/use-verge";
-import { BaseDialog, DialogRef, Notice } from "@/components/base";
-import { HotkeyInput } from "./hotkey-input";
-
-const ItemWrapper = styled("div")`
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  margin-bottom: 8px;
-`;
-
-const HOTKEY_FUNC = [
-  "open_dashboard",
-  "clash_mode_rule",
-  "clash_mode_global",
-  "clash_mode_direct",
-  "clash_mode_script",
-  "toggle_system_proxy",
-  "enable_system_proxy",
-  "disable_system_proxy",
-  "toggle_tun_mode",
-  "enable_tun_mode",
-  "disable_tun_mode",
-];
-
-export const HotkeyViewer = forwardRef<DialogRef>((props, ref) => {
-  const { t } = useTranslation();
-  const [open, setOpen] = useState(false);
-
-  const { verge, patchVerge } = useVerge();
-
-  const [hotkeyMap, setHotkeyMap] = useState<Record<string, string[]>>({});
-
-  useImperativeHandle(ref, () => ({
-    open: () => {
-      setOpen(true);
-
-      const map = {} as typeof hotkeyMap;
-
-      verge?.hotkeys?.forEach((text) => {
-        const [func, key] = text.split(",").map((e) => e.trim());
-
-        if (!func || !key) return;
-
-        map[func] = key
-          .split("+")
-          .map((e) => e.trim())
-          .map((k) => (k === "PLUS" ? "+" : k));
-      });
-
-      setHotkeyMap(map);
-    },
-    close: () => setOpen(false),
-  }));
-
-  const onSave = useLockFn(async () => {
-    const hotkeys = Object.entries(hotkeyMap)
-      .map(([func, keys]) => {
-        if (!func || !keys?.length) return "";
-
-        const key = keys
-          .map((k) => k.trim())
-          .filter(Boolean)
-          .map((k) => (k === "+" ? "PLUS" : k))
-          .join("+");
-
-        if (!key) return "";
-        return `${func},${key}`;
-      })
-      .filter(Boolean);
-
-    try {
-      await patchVerge({ hotkeys });
-      setOpen(false);
-    } catch (err: any) {
-      Notice.error(err.message || err.toString());
-    }
-  });
-
-  return (
-    <BaseDialog
-      open={open}
-      title={t("Hotkey Viewer")}
-      contentSx={{ width: 450, maxHeight: 330 }}
-      okBtn={t("Save")}
-      cancelBtn={t("Cancel")}
-      onClose={() => setOpen(false)}
-      onCancel={() => setOpen(false)}
-      onOk={onSave}
-    >
-      {HOTKEY_FUNC.map((func) => (
-        <ItemWrapper key={func}>
-          <Typography>{t(func)}</Typography>
-          <HotkeyInput
-            value={hotkeyMap[func] ?? []}
-            onChange={(v) => setHotkeyMap((m) => ({ ...m, [func]: v }))}
-          />
-        </ItemWrapper>
-      ))}
-    </BaseDialog>
-  );
-});
diff --git a/src/components/setting/mods/layout-viewer.tsx b/src/components/setting/mods/layout-viewer.tsx
deleted file mode 100644
index baeca95ae1f4a456bf53bbef26ab7bb2fad54e39..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/layout-viewer.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import { forwardRef, useImperativeHandle, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { List, Switch } from "@mui/material";
-import { useVerge } from "@/hooks/use-verge";
-import { BaseDialog, DialogRef, Notice } from "@/components/base";
-import { SettingItem } from "./setting-comp";
-import { GuardState } from "./guard-state";
-
-export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
-  const { t } = useTranslation();
-  const { verge, patchVerge, mutateVerge } = useVerge();
-
-  const [open, setOpen] = useState(false);
-
-  useImperativeHandle(ref, () => ({
-    open: () => setOpen(true),
-    close: () => setOpen(false),
-  }));
-
-  const onSwitchFormat = (_e: any, value: boolean) => value;
-  const onError = (err: any) => {
-    Notice.error(err.message || err.toString());
-  };
-  const onChangeData = (patch: Partial<IVergeConfig>) => {
-    mutateVerge({ ...verge, ...patch }, false);
-  };
-
-  return (
-    <BaseDialog
-      open={open}
-      title={t("Layout Setting")}
-      contentSx={{ width: 450 }}
-      disableOk
-      cancelBtn={t("Cancel")}
-      onClose={() => setOpen(false)}
-      onCancel={() => setOpen(false)}
-    >
-      <List>
-        <SettingItem label={t("Theme Blur")}>
-          <GuardState
-            value={verge?.theme_blur ?? false}
-            valueProps="checked"
-            onCatch={onError}
-            onFormat={onSwitchFormat}
-            onChange={(e) => onChangeData({ theme_blur: e })}
-            onGuard={(e) => patchVerge({ theme_blur: e })}
-          >
-            <Switch edge="end" />
-          </GuardState>
-        </SettingItem>
-
-        <SettingItem label={t("Traffic Graph")}>
-          <GuardState
-            value={verge?.traffic_graph ?? true}
-            valueProps="checked"
-            onCatch={onError}
-            onFormat={onSwitchFormat}
-            onChange={(e) => onChangeData({ traffic_graph: e })}
-            onGuard={(e) => patchVerge({ traffic_graph: e })}
-          >
-            <Switch edge="end" />
-          </GuardState>
-        </SettingItem>
-
-        <SettingItem label={t("Memory Usage")}>
-          <GuardState
-            value={verge?.enable_memory_usage ?? true}
-            valueProps="checked"
-            onCatch={onError}
-            onFormat={onSwitchFormat}
-            onChange={(e) => onChangeData({ enable_memory_usage: e })}
-            onGuard={(e) => patchVerge({ enable_memory_usage: e })}
-          >
-            <Switch edge="end" />
-          </GuardState>
-        </SettingItem>
-      </List>
-    </BaseDialog>
-  );
-});
diff --git a/src/components/setting/mods/misc-viewer.tsx b/src/components/setting/mods/misc-viewer.tsx
deleted file mode 100644
index 7d6326471f9157109c62d3bbf16bb90fd5ee56aa..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/misc-viewer.tsx
+++ /dev/null
@@ -1,199 +0,0 @@
-import { forwardRef, useImperativeHandle, useState } from "react";
-import { useLockFn } from "ahooks";
-import { useTranslation } from "react-i18next";
-import {
-  List,
-  ListItem,
-  ListItemText,
-  MenuItem,
-  Select,
-  Switch,
-  TextField,
-} from "@mui/material";
-import { useVerge } from "@/hooks/use-verge";
-import { BaseDialog, DialogRef, Notice } from "@/components/base";
-
-export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
-  const { t } = useTranslation();
-  const { verge, patchVerge } = useVerge();
-
-  const [open, setOpen] = useState(false);
-  const [values, setValues] = useState({
-    appLogLevel: "info",
-    autoCloseConnection: false,
-    enableClashFields: true,
-    enableBuiltinEnhanced: true,
-    proxyLayoutColumn: 6,
-    defaultLatencyTest: "",
-    autoLogClean: 0,
-  });
-
-  useImperativeHandle(ref, () => ({
-    open: () => {
-      setOpen(true);
-      setValues({
-        appLogLevel: verge?.app_log_level ?? "info",
-        autoCloseConnection: verge?.auto_close_connection ?? false,
-        enableClashFields: verge?.enable_clash_fields ?? true,
-        enableBuiltinEnhanced: verge?.enable_builtin_enhanced ?? true,
-        proxyLayoutColumn: verge?.proxy_layout_column || 6,
-        defaultLatencyTest: verge?.default_latency_test || "",
-        autoLogClean: verge?.auto_log_clean || 0,
-      });
-    },
-    close: () => setOpen(false),
-  }));
-
-  const onSave = useLockFn(async () => {
-    try {
-      await patchVerge({
-        app_log_level: values.appLogLevel,
-        auto_close_connection: values.autoCloseConnection,
-        enable_clash_fields: values.enableClashFields,
-        enable_builtin_enhanced: values.enableBuiltinEnhanced,
-        proxy_layout_column: values.proxyLayoutColumn,
-        default_latency_test: values.defaultLatencyTest,
-        auto_log_clean: values.autoLogClean as any,
-      });
-      setOpen(false);
-    } catch (err: any) {
-      Notice.error(err.message || err.toString());
-    }
-  });
-
-  return (
-    <BaseDialog
-      open={open}
-      title={t("Miscellaneous")}
-      contentSx={{ width: 450 }}
-      okBtn={t("Save")}
-      cancelBtn={t("Cancel")}
-      onClose={() => setOpen(false)}
-      onCancel={() => setOpen(false)}
-      onOk={onSave}
-    >
-      <List>
-        <ListItem sx={{ padding: "5px 2px" }}>
-          <ListItemText primary={t("App Log Level")} />
-          <Select
-            size="small"
-            sx={{ width: 100, "> div": { py: "7.5px" } }}
-            value={values.appLogLevel}
-            onChange={(e) => {
-              setValues((v) => ({
-                ...v,
-                appLogLevel: e.target.value as string,
-              }));
-            }}
-          >
-            {["trace", "debug", "info", "warn", "error", "silent"].map((i) => (
-              <MenuItem value={i} key={i}>
-                {i[0].toUpperCase() + i.slice(1).toLowerCase()}
-              </MenuItem>
-            ))}
-          </Select>
-        </ListItem>
-
-        <ListItem sx={{ padding: "5px 2px" }}>
-          <ListItemText primary={t("Auto Close Connections")} />
-          <Switch
-            edge="end"
-            checked={values.autoCloseConnection}
-            onChange={(_, c) =>
-              setValues((v) => ({ ...v, autoCloseConnection: c }))
-            }
-          />
-        </ListItem>
-
-        <ListItem sx={{ padding: "5px 2px" }}>
-          <ListItemText primary={t("Enable Clash Fields Filter")} />
-          <Switch
-            edge="end"
-            checked={values.enableClashFields}
-            onChange={(_, c) =>
-              setValues((v) => ({ ...v, enableClashFields: c }))
-            }
-          />
-        </ListItem>
-
-        <ListItem sx={{ padding: "5px 2px" }}>
-          <ListItemText primary={t("Enable Builtin Enhanced")} />
-          <Switch
-            edge="end"
-            checked={values.enableBuiltinEnhanced}
-            onChange={(_, c) =>
-              setValues((v) => ({ ...v, enableBuiltinEnhanced: c }))
-            }
-          />
-        </ListItem>
-
-        <ListItem sx={{ padding: "5px 2px" }}>
-          <ListItemText primary={t("Proxy Layout Column")} />
-          <Select
-            size="small"
-            sx={{ width: 135, "> div": { py: "7.5px" } }}
-            value={values.proxyLayoutColumn}
-            onChange={(e) => {
-              setValues((v) => ({
-                ...v,
-                proxyLayoutColumn: e.target.value as number,
-              }));
-            }}
-          >
-            <MenuItem value={6} key={6}>
-              Auto
-            </MenuItem>
-            {[1, 2, 3, 4, 5].map((i) => (
-              <MenuItem value={i} key={i}>
-                {i}
-              </MenuItem>
-            ))}
-          </Select>
-        </ListItem>
-
-        <ListItem sx={{ padding: "5px 2px" }}>
-          <ListItemText primary={t("Auto Log Clean")} />
-          <Select
-            size="small"
-            sx={{ width: 135, "> div": { py: "7.5px" } }}
-            value={values.autoLogClean}
-            onChange={(e) => {
-              setValues((v) => ({
-                ...v,
-                autoLogClean: e.target.value as number,
-              }));
-            }}
-          >
-            {[
-              { key: "Never Clean", value: 0 },
-              { key: "Retain 7 Days", value: 1 },
-              { key: "Retain 30 Days", value: 2 },
-              { key: "Retain 90 Days", value: 3 },
-            ].map((i) => (
-              <MenuItem key={i.value} value={i.value}>
-                {t(i.key)}
-              </MenuItem>
-            ))}
-          </Select>
-        </ListItem>
-
-        <ListItem sx={{ padding: "5px 2px" }}>
-          <ListItemText primary={t("Default Latency Test")} />
-          <TextField
-            size="small"
-            autoComplete="off"
-            autoCorrect="off"
-            autoCapitalize="off"
-            spellCheck="false"
-            sx={{ width: 250 }}
-            value={values.defaultLatencyTest}
-            placeholder="http://www.gstatic.com/generate_204"
-            onChange={(e) =>
-              setValues((v) => ({ ...v, defaultLatencyTest: e.target.value }))
-            }
-          />
-        </ListItem>
-      </List>
-    </BaseDialog>
-  );
-});
diff --git a/src/components/setting/mods/service-viewer.tsx b/src/components/setting/mods/service-viewer.tsx
deleted file mode 100644
index 839c8c2d9cc7df6ac031347dc159d48de5e18cb7..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/service-viewer.tsx
+++ /dev/null
@@ -1,123 +0,0 @@
-import useSWR from "swr";
-import { forwardRef, useImperativeHandle, useState } from "react";
-import { useLockFn } from "ahooks";
-import { useTranslation } from "react-i18next";
-import { Button, Stack, Typography } from "@mui/material";
-import {
-  checkService,
-  installService,
-  uninstallService,
-  patchVergeConfig,
-} from "@/services/cmds";
-import { BaseDialog, DialogRef, Notice } from "@/components/base";
-
-interface Props {
-  enable: boolean;
-}
-
-export const ServiceViewer = forwardRef<DialogRef, Props>((props, ref) => {
-  const { enable } = props;
-
-  const { t } = useTranslation();
-  const [open, setOpen] = useState(false);
-
-  const { data: status, mutate: mutateCheck } = useSWR(
-    "checkService",
-    checkService,
-    {
-      revalidateIfStale: false,
-      shouldRetryOnError: false,
-      focusThrottleInterval: 36e5, // 1 hour
-    }
-  );
-
-  useImperativeHandle(ref, () => ({
-    open: () => setOpen(true),
-    close: () => setOpen(false),
-  }));
-
-  const state = status != null ? status : "pending";
-
-  const onInstall = useLockFn(async () => {
-    try {
-      await installService();
-      mutateCheck();
-      setOpen(false);
-      Notice.success("Service installed successfully");
-    } catch (err: any) {
-      mutateCheck();
-      Notice.error(err.message || err.toString());
-    }
-  });
-
-  const onUninstall = useLockFn(async () => {
-    try {
-      if (enable) {
-        await patchVergeConfig({ enable_service_mode: false });
-      }
-
-      await uninstallService();
-      mutateCheck();
-      setOpen(false);
-      Notice.success("Service uninstalled successfully");
-    } catch (err: any) {
-      mutateCheck();
-      Notice.error(err.message || err.toString());
-    }
-  });
-
-  // fix unhandled error of the service mode
-  const onDisable = useLockFn(async () => {
-    try {
-      await patchVergeConfig({ enable_service_mode: false });
-      mutateCheck();
-      setOpen(false);
-    } catch (err: any) {
-      mutateCheck();
-      Notice.error(err.message || err.toString());
-    }
-  });
-
-  return (
-    <BaseDialog
-      open={open}
-      title={t("Service Mode")}
-      contentSx={{ width: 360, userSelect: "text" }}
-      disableFooter
-      onClose={() => setOpen(false)}
-    >
-      <Typography>Current State: {state}</Typography>
-
-      {(state === "unknown" || state === "uninstall") && (
-        <Typography>
-          Information: Please make sure that the Clash Verge Service is
-          installed and enabled
-        </Typography>
-      )}
-
-      <Stack
-        direction="row"
-        spacing={1}
-        sx={{ mt: 4, justifyContent: "flex-end" }}
-      >
-        {state === "uninstall" && enable && (
-          <Button variant="contained" onClick={onDisable}>
-            Disable Service Mode
-          </Button>
-        )}
-
-        {state === "uninstall" && (
-          <Button variant="contained" onClick={onInstall}>
-            Install
-          </Button>
-        )}
-
-        {(state === "active" || state === "installed") && (
-          <Button variant="outlined" onClick={onUninstall}>
-            Uninstall
-          </Button>
-        )}
-      </Stack>
-    </BaseDialog>
-  );
-});
diff --git a/src/components/setting/mods/setting-comp.tsx b/src/components/setting/mods/setting-comp.tsx
deleted file mode 100644
index e0cd181e1fba5eef0945c14047b91a617b52f28d..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/setting-comp.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import React, { ReactNode } from "react";
-import {
-  Box,
-  List,
-  ListItem,
-  ListItemText,
-  ListSubheader,
-} from "@mui/material";
-
-interface ItemProps {
-  label: ReactNode;
-  extra?: ReactNode;
-  children?: ReactNode;
-  secondary?: ReactNode;
-}
-
-export const SettingItem: React.FC<ItemProps> = (props) => {
-  const { label, extra, children, secondary } = props;
-
-  const primary = !extra ? (
-    label
-  ) : (
-    <Box sx={{ display: "flex", alignItems: "center" }}>
-      <span>{label}</span>
-      {extra}
-    </Box>
-  );
-
-  return (
-    <ListItem sx={{ pt: "5px", pb: "5px" }}>
-      <ListItemText primary={primary} secondary={secondary} />
-      {children}
-    </ListItem>
-  );
-};
-
-export const SettingList: React.FC<{
-  title: string;
-  children: ReactNode;
-}> = (props) => (
-  <List>
-    <ListSubheader sx={{ background: "transparent" }} disableSticky>
-      {props.title}
-    </ListSubheader>
-
-    {props.children}
-  </List>
-);
diff --git a/src/components/setting/mods/sysproxy-viewer.tsx b/src/components/setting/mods/sysproxy-viewer.tsx
deleted file mode 100644
index 44682dcf638c8297bbe83e83e1c9a13aee3fe451..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/sysproxy-viewer.tsx
+++ /dev/null
@@ -1,173 +0,0 @@
-import { forwardRef, useImperativeHandle, useState } from "react";
-import { useLockFn } from "ahooks";
-import { useTranslation } from "react-i18next";
-import {
-  Box,
-  InputAdornment,
-  List,
-  ListItem,
-  ListItemText,
-  styled,
-  Switch,
-  TextField,
-  Typography,
-} from "@mui/material";
-import { useVerge } from "@/hooks/use-verge";
-import { getSystemProxy } from "@/services/cmds";
-import { BaseDialog, DialogRef, Notice } from "@/components/base";
-
-export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
-  const { t } = useTranslation();
-
-  const [open, setOpen] = useState(false);
-
-  const { verge, patchVerge } = useVerge();
-
-  type SysProxy = Awaited<ReturnType<typeof getSystemProxy>>;
-  const [sysproxy, setSysproxy] = useState<SysProxy>();
-
-  const {
-    enable_system_proxy: enabled,
-    enable_proxy_guard,
-    system_proxy_bypass,
-    proxy_guard_duration,
-  } = verge ?? {};
-
-  const [value, setValue] = useState({
-    guard: enable_proxy_guard,
-    bypass: system_proxy_bypass,
-    duration: proxy_guard_duration ?? 10,
-  });
-
-  useImperativeHandle(ref, () => ({
-    open: () => {
-      setOpen(true);
-      setValue({
-        guard: enable_proxy_guard,
-        bypass: system_proxy_bypass,
-        duration: proxy_guard_duration ?? 10,
-      });
-      getSystemProxy().then((p) => setSysproxy(p));
-    },
-    close: () => setOpen(false),
-  }));
-
-  const onSave = useLockFn(async () => {
-    if (value.duration < 1) {
-      Notice.error("Proxy guard duration at least 1 seconds");
-      return;
-    }
-
-    const patch: Partial<IVergeConfig> = {};
-
-    if (value.guard !== enable_proxy_guard) {
-      patch.enable_proxy_guard = value.guard;
-    }
-    if (value.duration !== proxy_guard_duration) {
-      patch.proxy_guard_duration = value.duration;
-    }
-    if (value.bypass !== system_proxy_bypass) {
-      patch.system_proxy_bypass = value.bypass;
-    }
-
-    try {
-      await patchVerge(patch);
-      setOpen(false);
-    } catch (err: any) {
-      Notice.error(err.message || err.toString());
-    }
-  });
-
-  return (
-    <BaseDialog
-      open={open}
-      title={t("System Proxy Setting")}
-      contentSx={{ width: 450, maxHeight: 300 }}
-      okBtn={t("Save")}
-      cancelBtn={t("Cancel")}
-      onClose={() => setOpen(false)}
-      onCancel={() => setOpen(false)}
-      onOk={onSave}
-    >
-      <List>
-        <ListItem sx={{ padding: "5px 2px" }}>
-          <ListItemText primary={t("Proxy Guard")} />
-          <Switch
-            edge="end"
-            disabled={!enabled}
-            checked={value.guard}
-            onChange={(_, e) => setValue((v) => ({ ...v, guard: e }))}
-          />
-        </ListItem>
-
-        <ListItem sx={{ padding: "5px 2px" }}>
-          <ListItemText primary={t("Guard Duration")} />
-          <TextField
-            disabled={!enabled}
-            size="small"
-            value={value.duration}
-            sx={{ width: 100 }}
-            InputProps={{
-              endAdornment: <InputAdornment position="end">s</InputAdornment>,
-            }}
-            onChange={(e) => {
-              setValue((v) => ({
-                ...v,
-                duration: +e.target.value.replace(/\D/, ""),
-              }));
-            }}
-          />
-        </ListItem>
-
-        <ListItem sx={{ padding: "5px 2px", alignItems: "start" }}>
-          <ListItemText primary={t("Proxy Bypass")} sx={{ padding: "3px 0" }} />
-          <TextField
-            disabled={!enabled}
-            size="small"
-            autoComplete="off"
-            multiline
-            rows={3}
-            sx={{ width: 280 }}
-            value={value.bypass}
-            onChange={(e) =>
-              setValue((v) => ({ ...v, bypass: e.target.value }))
-            }
-          />
-        </ListItem>
-      </List>
-
-      <Box sx={{ mt: 2.5 }}>
-        <Typography variant="body1" sx={{ fontSize: "18px", mb: 1 }}>
-          {t("Current System Proxy")}
-        </Typography>
-
-        <FlexBox>
-          <Typography className="label">Enable:</Typography>
-          <Typography className="value">
-            {(!!sysproxy?.enable).toString()}
-          </Typography>
-        </FlexBox>
-
-        <FlexBox>
-          <Typography className="label">Server:</Typography>
-          <Typography className="value">{sysproxy?.server || "-"}</Typography>
-        </FlexBox>
-
-        <FlexBox>
-          <Typography className="label">Bypass:</Typography>
-          <Typography className="value">{sysproxy?.bypass || "-"}</Typography>
-        </FlexBox>
-      </Box>
-    </BaseDialog>
-  );
-});
-
-const FlexBox = styled("div")`
-  display: flex;
-  margin-top: 4px;
-
-  .label {
-    flex: none;
-    width: 80px;
-  }
-`;
diff --git a/src/components/setting/mods/theme-mode-switch.tsx b/src/components/setting/mods/theme-mode-switch.tsx
deleted file mode 100644
index 29ae9ef0c633aaef427f9db566d8a5f0a8cba5a4..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/theme-mode-switch.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import { useTranslation } from "react-i18next";
-import { Button, ButtonGroup } from "@mui/material";
-
-type ThemeValue = IVergeConfig["theme_mode"];
-
-interface Props {
-  value?: ThemeValue;
-  onChange?: (value: ThemeValue) => void;
-}
-
-export const ThemeModeSwitch = (props: Props) => {
-  const { value, onChange } = props;
-  const { t } = useTranslation();
-
-  const modes = ["light", "dark", "system"] as const;
-
-  return (
-    <ButtonGroup size="small" sx={{ my: "4px" }}>
-      {modes.map((mode) => (
-        <Button
-          key={mode}
-          variant={mode === value ? "contained" : "outlined"}
-          onClick={() => onChange?.(mode)}
-          sx={{ textTransform: "capitalize" }}
-        >
-          {t(`theme.${mode}`)}
-        </Button>
-      ))}
-    </ButtonGroup>
-  );
-};
diff --git a/src/components/setting/mods/theme-viewer.tsx b/src/components/setting/mods/theme-viewer.tsx
deleted file mode 100644
index c68ada296ccf0761b3625e2ff6f4022892f520cb..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/theme-viewer.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-import { forwardRef, useImperativeHandle, useState } from "react";
-import { useLockFn } from "ahooks";
-import { useTranslation } from "react-i18next";
-import {
-  List,
-  ListItem,
-  ListItemText,
-  styled,
-  TextField,
-  useTheme,
-} from "@mui/material";
-import { useVerge } from "@/hooks/use-verge";
-import { defaultTheme, defaultDarkTheme } from "@/pages/_theme";
-import { BaseDialog, DialogRef, Notice } from "@/components/base";
-
-export const ThemeViewer = forwardRef<DialogRef>((props, ref) => {
-  const { t } = useTranslation();
-
-  const [open, setOpen] = useState(false);
-  const { verge, patchVerge } = useVerge();
-  const { theme_setting } = verge ?? {};
-  const [theme, setTheme] = useState(theme_setting || {});
-
-  useImperativeHandle(ref, () => ({
-    open: () => {
-      setOpen(true);
-      setTheme({ ...theme_setting } || {});
-    },
-    close: () => setOpen(false),
-  }));
-
-  const textProps = {
-    size: "small",
-    autoComplete: "off",
-    sx: { width: 135 },
-  } as const;
-
-  const handleChange = (field: keyof typeof theme) => (e: any) => {
-    setTheme((t) => ({ ...t, [field]: e.target.value }));
-  };
-
-  const onSave = useLockFn(async () => {
-    try {
-      await patchVerge({ theme_setting: theme });
-      setOpen(false);
-    } catch (err: any) {
-      Notice.error(err.message || err.toString());
-    }
-  });
-
-  // default theme
-  const { palette } = useTheme();
-
-  const dt = palette.mode === "light" ? defaultTheme : defaultDarkTheme;
-
-  type ThemeKey = keyof typeof theme & keyof typeof defaultTheme;
-
-  const renderItem = (label: string, key: ThemeKey) => {
-    return (
-      <Item>
-        <ListItemText primary={label} />
-        <Round sx={{ background: theme[key] || dt[key] }} />
-        <TextField
-          {...textProps}
-          value={theme[key] ?? ""}
-          placeholder={dt[key]}
-          onChange={handleChange(key)}
-          onKeyDown={(e) => e.key === "Enter" && onSave()}
-        />
-      </Item>
-    );
-  };
-
-  return (
-    <BaseDialog
-      open={open}
-      title={t("Theme Setting")}
-      okBtn={t("Save")}
-      cancelBtn={t("Cancel")}
-      contentSx={{ width: 400, maxHeight: 300, overflow: "auto", pb: 0 }}
-      onClose={() => setOpen(false)}
-      onCancel={() => setOpen(false)}
-      onOk={onSave}
-    >
-      <List sx={{ pt: 0 }}>
-        {renderItem("Primary Color", "primary_color")}
-
-        {renderItem("Secondary Color", "secondary_color")}
-
-        {renderItem("Primary Text", "primary_text")}
-
-        {renderItem("Secondary Text", "secondary_text")}
-
-        {renderItem("Info Color", "info_color")}
-
-        {renderItem("Error Color", "error_color")}
-
-        {renderItem("Warning Color", "warning_color")}
-
-        {renderItem("Success Color", "success_color")}
-
-        <Item>
-          <ListItemText primary="Font Family" />
-          <TextField
-            {...textProps}
-            value={theme.font_family ?? ""}
-            onChange={handleChange("font_family")}
-            onKeyDown={(e) => e.key === "Enter" && onSave()}
-          />
-        </Item>
-
-        <Item>
-          <ListItemText primary="CSS Injection" />
-          <TextField
-            {...textProps}
-            value={theme.css_injection ?? ""}
-            onChange={handleChange("css_injection")}
-            onKeyDown={(e) => e.key === "Enter" && onSave()}
-          />
-        </Item>
-      </List>
-    </BaseDialog>
-  );
-});
-
-const Item = styled(ListItem)(() => ({
-  padding: "5px 2px",
-}));
-
-const Round = styled("div")(() => ({
-  width: "24px",
-  height: "24px",
-  borderRadius: "18px",
-  display: "inline-block",
-  marginRight: "8px",
-}));
diff --git a/src/components/setting/mods/update-viewer.tsx b/src/components/setting/mods/update-viewer.tsx
deleted file mode 100644
index 8b4e68a279a6279ab8819e1160ad54103d9a58a3..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/update-viewer.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import useSWR from "swr";
-import snarkdown from "snarkdown";
-import { forwardRef, useImperativeHandle, useState, useMemo } from "react";
-import { useLockFn } from "ahooks";
-import { Box, styled } from "@mui/material";
-import { useRecoilState } from "recoil";
-import { useTranslation } from "react-i18next";
-import { relaunch } from "@tauri-apps/api/process";
-import { checkUpdate, installUpdate } from "@tauri-apps/api/updater";
-import { BaseDialog, DialogRef, Notice } from "@/components/base";
-import { atomUpdateState } from "@/services/states";
-
-const UpdateLog = styled(Box)(() => ({
-  "h1,h2,h3,ul,ol,p": { margin: "0.5em 0", color: "inherit" },
-}));
-
-export const UpdateViewer = forwardRef<DialogRef>((props, ref) => {
-  const { t } = useTranslation();
-
-  const [open, setOpen] = useState(false);
-  const [updateState, setUpdateState] = useRecoilState(atomUpdateState);
-
-  const { data: updateInfo } = useSWR("checkUpdate", checkUpdate, {
-    errorRetryCount: 2,
-    revalidateIfStale: false,
-    focusThrottleInterval: 36e5, // 1 hour
-  });
-
-  useImperativeHandle(ref, () => ({
-    open: () => setOpen(true),
-    close: () => setOpen(false),
-  }));
-
-  // markdown parser
-  const parseContent = useMemo(() => {
-    if (!updateInfo?.manifest?.body) {
-      return "New Version is available";
-    }
-    return snarkdown(updateInfo?.manifest?.body);
-  }, [updateInfo]);
-
-  const onUpdate = useLockFn(async () => {
-    if (updateState) return;
-    setUpdateState(true);
-
-    try {
-      await installUpdate();
-      await relaunch();
-    } catch (err: any) {
-      Notice.error(err?.message || err.toString());
-    } finally {
-      setUpdateState(false);
-    }
-  });
-
-  return (
-    <BaseDialog
-      open={open}
-      title={`New Version v${updateInfo?.manifest?.version}`}
-      contentSx={{ minWidth: 360, maxWidth: 400, maxHeight: "50vh" }}
-      okBtn={t("Update")}
-      cancelBtn={t("Cancel")}
-      onClose={() => setOpen(false)}
-      onCancel={() => setOpen(false)}
-      onOk={onUpdate}
-    >
-      <UpdateLog dangerouslySetInnerHTML={{ __html: parseContent }} />
-    </BaseDialog>
-  );
-});
diff --git a/src/components/setting/mods/web-ui-item.tsx b/src/components/setting/mods/web-ui-item.tsx
deleted file mode 100644
index 5d3d84d591edaef936973bcd76d67156852ed2ea..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/web-ui-item.tsx
+++ /dev/null
@@ -1,130 +0,0 @@
-import { useState } from "react";
-import {
-  Divider,
-  IconButton,
-  Stack,
-  TextField,
-  Typography,
-} from "@mui/material";
-import {
-  CheckRounded,
-  CloseRounded,
-  DeleteRounded,
-  EditRounded,
-  OpenInNewRounded,
-} from "@mui/icons-material";
-
-interface Props {
-  value?: string;
-  onlyEdit?: boolean;
-  onChange: (value?: string) => void;
-  onOpenUrl?: (value?: string) => void;
-  onDelete?: () => void;
-  onCancel?: () => void;
-}
-
-export const WebUIItem = (props: Props) => {
-  const {
-    value,
-    onlyEdit = false,
-    onChange,
-    onDelete,
-    onOpenUrl,
-    onCancel,
-  } = props;
-
-  const [editing, setEditing] = useState(false);
-  const [editValue, setEditValue] = useState(value);
-
-  if (editing || onlyEdit) {
-    return (
-      <>
-        <Stack spacing={0.75} direction="row" mt={1} mb={1} alignItems="center">
-          <TextField
-            fullWidth
-            size="small"
-            value={editValue}
-            onChange={(e) => setEditValue(e.target.value)}
-            placeholder={`Support %host %port %secret`}
-            autoComplete="off"
-          />
-          <IconButton
-            size="small"
-            title="Save"
-            color="inherit"
-            onClick={() => {
-              onChange(editValue);
-              setEditing(false);
-            }}
-          >
-            <CheckRounded fontSize="inherit" />
-          </IconButton>
-          <IconButton
-            size="small"
-            title="Cancel"
-            color="inherit"
-            onClick={() => {
-              onCancel?.();
-              setEditing(false);
-            }}
-          >
-            <CloseRounded fontSize="inherit" />
-          </IconButton>
-        </Stack>
-        <Divider />
-      </>
-    );
-  }
-
-  const html = value
-    ?.replace("%host", "<span>%host</span>")
-    .replace("%port", "<span>%port</span>")
-    .replace("%secret", "<span>%secret</span>");
-
-  return (
-    <>
-      <Stack spacing={0.75} direction="row" alignItems="center" mt={1} mb={1}>
-        <Typography
-          component="div"
-          width="100%"
-          title={value}
-          color={value ? "text.primary" : "text.secondary"}
-          sx={({ palette }) => ({
-            "> span": {
-              color: palette.primary.main,
-            },
-          })}
-          dangerouslySetInnerHTML={{ __html: html || "NULL" }}
-        />
-        <IconButton
-          size="small"
-          title="Open URL"
-          color="inherit"
-          onClick={() => onOpenUrl?.(value)}
-        >
-          <OpenInNewRounded fontSize="inherit" />
-        </IconButton>
-        <IconButton
-          size="small"
-          title="Edit"
-          color="inherit"
-          onClick={() => {
-            setEditing(true);
-            setEditValue(value);
-          }}
-        >
-          <EditRounded fontSize="inherit" />
-        </IconButton>
-        <IconButton
-          size="small"
-          title="Delete"
-          color="inherit"
-          onClick={onDelete}
-        >
-          <DeleteRounded fontSize="inherit" />
-        </IconButton>
-      </Stack>
-      <Divider />
-    </>
-  );
-};
diff --git a/src/components/setting/mods/web-ui-viewer.tsx b/src/components/setting/mods/web-ui-viewer.tsx
deleted file mode 100644
index 8588d3d107925647b25fefe60b80d902328ea4a0..0000000000000000000000000000000000000000
--- a/src/components/setting/mods/web-ui-viewer.tsx
+++ /dev/null
@@ -1,137 +0,0 @@
-import { forwardRef, useImperativeHandle, useState } from "react";
-import { useLockFn } from "ahooks";
-import { useTranslation } from "react-i18next";
-import { Button, Box, Typography } from "@mui/material";
-import { useVerge } from "@/hooks/use-verge";
-import { openWebUrl } from "@/services/cmds";
-import { BaseDialog, BaseEmpty, DialogRef, Notice } from "@/components/base";
-import { useClashInfo } from "@/hooks/use-clash";
-import { WebUIItem } from "./web-ui-item";
-
-export const WebUIViewer = forwardRef<DialogRef>((props, ref) => {
-  const { t } = useTranslation();
-
-  const { clashInfo } = useClashInfo();
-  const { verge, patchVerge, mutateVerge } = useVerge();
-
-  const [open, setOpen] = useState(false);
-  const [editing, setEditing] = useState(false);
-
-  useImperativeHandle(ref, () => ({
-    open: () => setOpen(true),
-    close: () => setOpen(false),
-  }));
-
-  const webUIList = verge?.web_ui_list || [];
-
-  const handleAdd = useLockFn(async (value: string) => {
-    const newList = [value, ...webUIList];
-    mutateVerge((old) => (old ? { ...old, web_ui_list: newList } : old), false);
-    await patchVerge({ web_ui_list: newList });
-  });
-
-  const handleChange = useLockFn(async (index: number, value?: string) => {
-    const newList = [...webUIList];
-    newList[index] = value ?? "";
-    mutateVerge((old) => (old ? { ...old, web_ui_list: newList } : old), false);
-    await patchVerge({ web_ui_list: newList });
-  });
-
-  const handleDelete = useLockFn(async (index: number) => {
-    const newList = [...webUIList];
-    newList.splice(index, 1);
-    mutateVerge((old) => (old ? { ...old, web_ui_list: newList } : old), false);
-    await patchVerge({ web_ui_list: newList });
-  });
-
-  const handleOpenUrl = useLockFn(async (value?: string) => {
-    if (!value) return;
-    try {
-      let url = value.trim().replaceAll("%host", "127.0.0.1");
-
-      if (url.includes("%port") || url.includes("%secret")) {
-        if (!clashInfo) throw new Error("failed to get clash info");
-        if (!clashInfo.server?.includes(":")) {
-          throw new Error(`failed to parse the server "${clashInfo.server}"`);
-        }
-
-        const port = clashInfo.server
-          .slice(clashInfo.server.indexOf(":") + 1)
-          .trim();
-
-        url = url.replaceAll("%port", port || "9090");
-        url = url.replaceAll(
-          "%secret",
-          encodeURIComponent(clashInfo.secret || "")
-        );
-      }
-
-      await openWebUrl(url);
-    } catch (e: any) {
-      Notice.error(e.message || e.toString());
-    }
-  });
-
-  return (
-    <BaseDialog
-      open={open}
-      title={
-        <Box display="flex" justifyContent="space-between">
-          {t("Web UI")}
-          <Button
-            variant="contained"
-            size="small"
-            disabled={editing}
-            onClick={() => setEditing(true)}
-          >
-            {t("New")}
-          </Button>
-        </Box>
-      }
-      contentSx={{
-        width: 450,
-        height: 300,
-        pb: 1,
-        overflowY: "auto",
-        userSelect: "text",
-      }}
-      cancelBtn={t("Back")}
-      disableOk
-      onClose={() => setOpen(false)}
-      onCancel={() => setOpen(false)}
-    >
-      {editing && (
-        <WebUIItem
-          value=""
-          onlyEdit
-          onChange={(v) => {
-            setEditing(false);
-            handleAdd(v || "");
-          }}
-          onCancel={() => setEditing(false)}
-        />
-      )}
-
-      {!editing && webUIList.length === 0 && (
-        <BaseEmpty
-          text="Empty List"
-          extra={
-            <Typography mt={2} sx={{ fontSize: "12px" }}>
-              Replace host, port, secret with "%host" "%port" "%secret"
-            </Typography>
-          }
-        />
-      )}
-
-      {webUIList.map((item, index) => (
-        <WebUIItem
-          key={index}
-          value={item}
-          onChange={(v) => handleChange(index, v)}
-          onDelete={() => handleDelete(index)}
-          onOpenUrl={handleOpenUrl}
-        />
-      ))}
-    </BaseDialog>
-  );
-});
diff --git a/src/components/setting/setting-clash.tsx b/src/components/setting/setting-clash.tsx
deleted file mode 100644
index 19f77ca6120cdadd88467d9862ebfd8c17cc1ca9..0000000000000000000000000000000000000000
--- a/src/components/setting/setting-clash.tsx
+++ /dev/null
@@ -1,169 +0,0 @@
-import { useRef } from "react";
-import { useTranslation } from "react-i18next";
-import {
-  TextField,
-  Switch,
-  Select,
-  MenuItem,
-  Typography,
-  IconButton,
-} from "@mui/material";
-import { ArrowForward, Settings } from "@mui/icons-material";
-import { DialogRef } from "@/components/base";
-import { useClash } from "@/hooks/use-clash";
-import { GuardState } from "./mods/guard-state";
-import { WebUIViewer } from "./mods/web-ui-viewer";
-import { ClashFieldViewer } from "./mods/clash-field-viewer";
-import { ClashPortViewer } from "./mods/clash-port-viewer";
-import { ControllerViewer } from "./mods/controller-viewer";
-import { SettingList, SettingItem } from "./mods/setting-comp";
-import { ClashCoreViewer } from "./mods/clash-core-viewer";
-
-interface Props {
-  onError: (err: Error) => void;
-}
-
-const SettingClash = ({ onError }: Props) => {
-  const { t } = useTranslation();
-
-  const { clash, version, mutateClash, patchClash } = useClash();
-
-  const {
-    ipv6,
-    "allow-lan": allowLan,
-    "log-level": logLevel,
-    "mixed-port": mixedPort,
-  } = clash ?? {};
-
-  const webRef = useRef<DialogRef>(null);
-  const fieldRef = useRef<DialogRef>(null);
-  const portRef = useRef<DialogRef>(null);
-  const ctrlRef = useRef<DialogRef>(null);
-  const coreRef = useRef<DialogRef>(null);
-
-  const onSwitchFormat = (_e: any, value: boolean) => value;
-  const onChangeData = (patch: Partial<IConfigData>) => {
-    mutateClash((old) => ({ ...(old! || {}), ...patch }), false);
-  };
-
-  return (
-    <SettingList title={t("Clash Setting")}>
-      <WebUIViewer ref={webRef} />
-      <ClashFieldViewer ref={fieldRef} />
-      <ClashPortViewer ref={portRef} />
-      <ControllerViewer ref={ctrlRef} />
-      <ClashCoreViewer ref={coreRef} />
-
-      <SettingItem label={t("Allow Lan")}>
-        <GuardState
-          value={allowLan ?? false}
-          valueProps="checked"
-          onCatch={onError}
-          onFormat={onSwitchFormat}
-          onChange={(e) => onChangeData({ "allow-lan": e })}
-          onGuard={(e) => patchClash({ "allow-lan": e })}
-        >
-          <Switch edge="end" />
-        </GuardState>
-      </SettingItem>
-
-      <SettingItem label={t("IPv6")}>
-        <GuardState
-          value={ipv6 ?? false}
-          valueProps="checked"
-          onCatch={onError}
-          onFormat={onSwitchFormat}
-          onChange={(e) => onChangeData({ ipv6: e })}
-          onGuard={(e) => patchClash({ ipv6: e })}
-        >
-          <Switch edge="end" />
-        </GuardState>
-      </SettingItem>
-
-      <SettingItem label={t("Log Level")}>
-        <GuardState
-          // clash premium 2022.08.26 值为warn
-          value={logLevel === "warn" ? "warning" : logLevel ?? "info"}
-          onCatch={onError}
-          onFormat={(e: any) => e.target.value}
-          onChange={(e) => onChangeData({ "log-level": e })}
-          onGuard={(e) => patchClash({ "log-level": e })}
-        >
-          <Select size="small" sx={{ width: 100, "> div": { py: "7.5px" } }}>
-            <MenuItem value="debug">Debug</MenuItem>
-            <MenuItem value="info">Info</MenuItem>
-            <MenuItem value="warning">Warn</MenuItem>
-            <MenuItem value="error">Error</MenuItem>
-            <MenuItem value="silent">Silent</MenuItem>
-          </Select>
-        </GuardState>
-      </SettingItem>
-
-      <SettingItem label={t("Mixed Port")}>
-        <TextField
-          autoComplete="off"
-          size="small"
-          value={mixedPort ?? 0}
-          sx={{ width: 100, input: { py: "7.5px", cursor: "pointer" } }}
-          onClick={(e) => {
-            portRef.current?.open();
-            (e.target as any).blur();
-          }}
-        />
-      </SettingItem>
-
-      <SettingItem label={t("External")}>
-        <IconButton
-          color="inherit"
-          size="small"
-          sx={{ my: "2px" }}
-          onClick={() => ctrlRef.current?.open()}
-        >
-          <ArrowForward />
-        </IconButton>
-      </SettingItem>
-
-      <SettingItem label={t("Web UI")}>
-        <IconButton
-          color="inherit"
-          size="small"
-          sx={{ my: "2px" }}
-          onClick={() => webRef.current?.open()}
-        >
-          <ArrowForward />
-        </IconButton>
-      </SettingItem>
-
-      <SettingItem label={t("Clash Field")}>
-        <IconButton
-          color="inherit"
-          size="small"
-          sx={{ my: "2px" }}
-          onClick={() => fieldRef.current?.open()}
-        >
-          <ArrowForward />
-        </IconButton>
-      </SettingItem>
-
-      <SettingItem
-        label={t("Clash Core")}
-        extra={
-          <IconButton
-            color="inherit"
-            size="small"
-            onClick={() => coreRef.current?.open()}
-          >
-            <Settings
-              fontSize="inherit"
-              style={{ cursor: "pointer", opacity: 0.75 }}
-            />
-          </IconButton>
-        }
-      >
-        <Typography sx={{ py: "7px", pr: 1 }}>{version}</Typography>
-      </SettingItem>
-    </SettingList>
-  );
-};
-
-export default SettingClash;
diff --git a/src/components/setting/setting-system.tsx b/src/components/setting/setting-system.tsx
deleted file mode 100644
index 7fdeb8f1e313a31e4dfb60d1aebb4ab570edddf2..0000000000000000000000000000000000000000
--- a/src/components/setting/setting-system.tsx
+++ /dev/null
@@ -1,163 +0,0 @@
-import useSWR from "swr";
-import { useRef } from "react";
-import { useTranslation } from "react-i18next";
-import { IconButton, Switch } from "@mui/material";
-import { ArrowForward, PrivacyTipRounded, Settings } from "@mui/icons-material";
-import { checkService } from "@/services/cmds";
-import { useVerge } from "@/hooks/use-verge";
-import { DialogRef } from "@/components/base";
-import { SettingList, SettingItem } from "./mods/setting-comp";
-import { GuardState } from "./mods/guard-state";
-import { ServiceViewer } from "./mods/service-viewer";
-import { SysproxyViewer } from "./mods/sysproxy-viewer";
-import getSystem from "@/utils/get-system";
-
-interface Props {
-  onError?: (err: Error) => void;
-}
-
-const isWIN = getSystem() === "windows";
-
-const SettingSystem = ({ onError }: Props) => {
-  const { t } = useTranslation();
-
-  const { verge, mutateVerge, patchVerge } = useVerge();
-
-  // service mode
-  const { data: serviceStatus } = useSWR(
-    isWIN ? "checkService" : null,
-    checkService,
-    {
-      revalidateIfStale: false,
-      shouldRetryOnError: false,
-      focusThrottleInterval: 36e5, // 1 hour
-    }
-  );
-
-  const serviceRef = useRef<DialogRef>(null);
-  const sysproxyRef = useRef<DialogRef>(null);
-
-  const {
-    enable_tun_mode,
-    enable_auto_launch,
-    enable_service_mode,
-    enable_silent_start,
-    enable_system_proxy,
-  } = verge ?? {};
-
-  const onSwitchFormat = (_e: any, value: boolean) => value;
-  const onChangeData = (patch: Partial<IVergeConfig>) => {
-    mutateVerge({ ...verge, ...patch }, false);
-  };
-
-  return (
-    <SettingList title={t("System Setting")}>
-      <SysproxyViewer ref={sysproxyRef} />
-      {isWIN && (
-        <ServiceViewer ref={serviceRef} enable={!!enable_service_mode} />
-      )}
-
-      <SettingItem label={t("Tun Mode")}>
-        <GuardState
-          value={enable_tun_mode ?? false}
-          valueProps="checked"
-          onCatch={onError}
-          onFormat={onSwitchFormat}
-          onChange={(e) => onChangeData({ enable_tun_mode: e })}
-          onGuard={(e) => patchVerge({ enable_tun_mode: e })}
-        >
-          <Switch edge="end" />
-        </GuardState>
-      </SettingItem>
-
-      {isWIN && (
-        <SettingItem
-          label={t("Service Mode")}
-          extra={
-            <IconButton
-              color="inherit"
-              size="small"
-              onClick={() => serviceRef.current?.open()}
-            >
-              <PrivacyTipRounded
-                fontSize="inherit"
-                style={{ cursor: "pointer", opacity: 0.75 }}
-              />
-            </IconButton>
-          }
-        >
-          <GuardState
-            value={enable_service_mode ?? false}
-            valueProps="checked"
-            onCatch={onError}
-            onFormat={onSwitchFormat}
-            onChange={(e) => onChangeData({ enable_service_mode: e })}
-            onGuard={(e) => patchVerge({ enable_service_mode: e })}
-          >
-            <Switch
-              edge="end"
-              disabled={
-                serviceStatus !== "active" && serviceStatus !== "installed"
-              }
-            />
-          </GuardState>
-        </SettingItem>
-      )}
-
-      <SettingItem
-        label={t("System Proxy")}
-        extra={
-          <IconButton
-            color="inherit"
-            size="small"
-            onClick={() => sysproxyRef.current?.open()}
-          >
-            <Settings
-              fontSize="inherit"
-              style={{ cursor: "pointer", opacity: 0.75 }}
-            />
-          </IconButton>
-        }
-      >
-        <GuardState
-          value={enable_system_proxy ?? false}
-          valueProps="checked"
-          onCatch={onError}
-          onFormat={onSwitchFormat}
-          onChange={(e) => onChangeData({ enable_system_proxy: e })}
-          onGuard={(e) => patchVerge({ enable_system_proxy: e })}
-        >
-          <Switch edge="end" />
-        </GuardState>
-      </SettingItem>
-
-      <SettingItem label={t("Auto Launch")}>
-        <GuardState
-          value={enable_auto_launch ?? false}
-          valueProps="checked"
-          onCatch={onError}
-          onFormat={onSwitchFormat}
-          onChange={(e) => onChangeData({ enable_auto_launch: e })}
-          onGuard={(e) => patchVerge({ enable_auto_launch: e })}
-        >
-          <Switch edge="end" />
-        </GuardState>
-      </SettingItem>
-
-      <SettingItem label={t("Silent Start")}>
-        <GuardState
-          value={enable_silent_start ?? false}
-          valueProps="checked"
-          onCatch={onError}
-          onFormat={onSwitchFormat}
-          onChange={(e) => onChangeData({ enable_silent_start: e })}
-          onGuard={(e) => patchVerge({ enable_silent_start: e })}
-        >
-          <Switch edge="end" />
-        </GuardState>
-      </SettingItem>
-    </SettingList>
-  );
-};
-
-export default SettingSystem;
diff --git a/src/components/setting/setting-verge.tsx b/src/components/setting/setting-verge.tsx
deleted file mode 100644
index d54094d419b006b04930e47bc9273817f4a25302..0000000000000000000000000000000000000000
--- a/src/components/setting/setting-verge.tsx
+++ /dev/null
@@ -1,202 +0,0 @@
-import { useRef } from "react";
-import { useLockFn } from "ahooks";
-import { useTranslation } from "react-i18next";
-import { IconButton, MenuItem, Select, Typography } from "@mui/material";
-import { openAppDir, openCoreDir, openLogsDir } from "@/services/cmds";
-import { ArrowForward } from "@mui/icons-material";
-import { checkUpdate } from "@tauri-apps/api/updater";
-import { useVerge } from "@/hooks/use-verge";
-import { version } from "@root/package.json";
-import { DialogRef, Notice } from "@/components/base";
-import { SettingList, SettingItem } from "./mods/setting-comp";
-import { ThemeModeSwitch } from "./mods/theme-mode-switch";
-import { ConfigViewer } from "./mods/config-viewer";
-import { HotkeyViewer } from "./mods/hotkey-viewer";
-import { MiscViewer } from "./mods/misc-viewer";
-import { ThemeViewer } from "./mods/theme-viewer";
-import { GuardState } from "./mods/guard-state";
-import { LayoutViewer } from "./mods/layout-viewer";
-import { UpdateViewer } from "./mods/update-viewer";
-import getSystem from "@/utils/get-system";
-
-interface Props {
-  onError?: (err: Error) => void;
-}
-
-const OS = getSystem();
-
-const SettingVerge = ({ onError }: Props) => {
-  const { t } = useTranslation();
-
-  const { verge, patchVerge, mutateVerge } = useVerge();
-  const { theme_mode, language } = verge ?? {};
-
-  const configRef = useRef<DialogRef>(null);
-  const hotkeyRef = useRef<DialogRef>(null);
-  const miscRef = useRef<DialogRef>(null);
-  const themeRef = useRef<DialogRef>(null);
-  const layoutRef = useRef<DialogRef>(null);
-  const updateRef = useRef<DialogRef>(null);
-
-  const onChangeData = (patch: Partial<IVergeConfig>) => {
-    mutateVerge({ ...verge, ...patch }, false);
-  };
-
-  const onCheckUpdate = useLockFn(async () => {
-    try {
-      const info = await checkUpdate();
-      if (!info?.shouldUpdate) {
-        Notice.success("No Updates Available");
-      } else {
-        updateRef.current?.open();
-      }
-    } catch (err: any) {
-      Notice.error(err.message || err.toString());
-    }
-  });
-
-  return (
-    <SettingList title={t("Verge Setting")}>
-      <ThemeViewer ref={themeRef} />
-      <ConfigViewer ref={configRef} />
-      <HotkeyViewer ref={hotkeyRef} />
-      <MiscViewer ref={miscRef} />
-      <LayoutViewer ref={layoutRef} />
-      <UpdateViewer ref={updateRef} />
-
-      <SettingItem label={t("Language")}>
-        <GuardState
-          value={language ?? "en"}
-          onCatch={onError}
-          onFormat={(e: any) => e.target.value}
-          onChange={(e) => onChangeData({ language: e })}
-          onGuard={(e) => patchVerge({ language: e })}
-        >
-          <Select size="small" sx={{ width: 100, "> div": { py: "7.5px" } }}>
-            <MenuItem value="zh">中文</MenuItem>
-            <MenuItem value="en">English</MenuItem>
-            <MenuItem value="ru">Русский</MenuItem>
-          </Select>
-        </GuardState>
-      </SettingItem>
-
-      <SettingItem label={t("Theme Mode")}>
-        <GuardState
-          value={theme_mode}
-          onCatch={onError}
-          onChange={(e) => onChangeData({ theme_mode: e })}
-          onGuard={(e) => patchVerge({ theme_mode: e })}
-        >
-          <ThemeModeSwitch />
-        </GuardState>
-      </SettingItem>
-
-      <SettingItem label={t("Theme Setting")}>
-        <IconButton
-          color="inherit"
-          size="small"
-          sx={{ my: "2px" }}
-          onClick={() => themeRef.current?.open()}
-        >
-          <ArrowForward />
-        </IconButton>
-      </SettingItem>
-
-      <SettingItem label={t("Layout Setting")}>
-        <IconButton
-          color="inherit"
-          size="small"
-          sx={{ my: "2px" }}
-          onClick={() => layoutRef.current?.open()}
-        >
-          <ArrowForward />
-        </IconButton>
-      </SettingItem>
-
-      <SettingItem label={t("Miscellaneous")}>
-        <IconButton
-          color="inherit"
-          size="small"
-          sx={{ my: "2px" }}
-          onClick={() => miscRef.current?.open()}
-        >
-          <ArrowForward />
-        </IconButton>
-      </SettingItem>
-
-      <SettingItem label={t("Hotkey Setting")}>
-        <IconButton
-          color="inherit"
-          size="small"
-          sx={{ my: "2px" }}
-          onClick={() => hotkeyRef.current?.open()}
-        >
-          <ArrowForward />
-        </IconButton>
-      </SettingItem>
-
-      <SettingItem label={t("Runtime Config")}>
-        <IconButton
-          color="inherit"
-          size="small"
-          sx={{ my: "2px" }}
-          onClick={() => configRef.current?.open()}
-        >
-          <ArrowForward />
-        </IconButton>
-      </SettingItem>
-
-      <SettingItem label={t("Open App Dir")}>
-        <IconButton
-          color="inherit"
-          size="small"
-          sx={{ my: "2px" }}
-          onClick={openAppDir}
-        >
-          <ArrowForward />
-        </IconButton>
-      </SettingItem>
-
-      <SettingItem label={t("Open Core Dir")}>
-        <IconButton
-          color="inherit"
-          size="small"
-          sx={{ my: "2px" }}
-          onClick={openCoreDir}
-        >
-          <ArrowForward />
-        </IconButton>
-      </SettingItem>
-
-      <SettingItem label={t("Open Logs Dir")}>
-        <IconButton
-          color="inherit"
-          size="small"
-          sx={{ my: "2px" }}
-          onClick={openLogsDir}
-        >
-          <ArrowForward />
-        </IconButton>
-      </SettingItem>
-
-      {!(OS === "windows" && WIN_PORTABLE) && (
-        <SettingItem label={t("Check for Updates")}>
-          <IconButton
-            color="inherit"
-            size="small"
-            sx={{ my: "2px" }}
-            onClick={onCheckUpdate}
-          >
-            <ArrowForward />
-          </IconButton>
-        </SettingItem>
-      )}
-
-      <SettingItem label={t("Verge Version")}>
-        <Typography sx={{ py: "7px", pr: 1 }}>v{version}</Typography>
-      </SettingItem>
-    </SettingList>
-  );
-};
-
-export default SettingVerge;
diff --git a/src/hooks/use-clash.ts b/src/hooks/use-clash.ts
deleted file mode 100644
index 9804c5fc4de1867e1963f9dc311c75df5eb13bb4..0000000000000000000000000000000000000000
--- a/src/hooks/use-clash.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import useSWR, { mutate } from "swr";
-import { useLockFn } from "ahooks";
-import {
-  getAxios,
-  getClashConfig,
-  getVersion,
-  updateConfigs,
-} from "@/services/api";
-import { getClashInfo, patchClashConfig } from "@/services/cmds";
-
-export const useClash = () => {
-  const { data: clash, mutate: mutateClash } = useSWR(
-    "getClashConfig",
-    getClashConfig
-  );
-
-  const { data: versionData, mutate: mutateVersion } = useSWR(
-    "getVersion",
-    getVersion
-  );
-
-  const patchClash = useLockFn(async (patch: Partial<IConfigData>) => {
-    await updateConfigs(patch);
-    await patchClashConfig(patch);
-    mutateClash();
-  });
-
-  const version = versionData?.premium
-    ? `${versionData.version} Premium`
-    : versionData?.meta
-    ? `${versionData.version} Meta`
-    : versionData?.version || "-";
-
-  return {
-    clash,
-    version,
-    mutateClash,
-    mutateVersion,
-    patchClash,
-  };
-};
-
-export const useClashInfo = () => {
-  const { data: clashInfo, mutate: mutateInfo } = useSWR(
-    "getClashInfo",
-    getClashInfo
-  );
-
-  const patchInfo = async (
-    patch: Partial<
-      Pick<IConfigData, "mixed-port" | "external-controller" | "secret">
-    >
-  ) => {
-    const hasInfo =
-      patch["mixed-port"] != null ||
-      patch["external-controller"] != null ||
-      patch.secret != null;
-
-    if (!hasInfo) return;
-
-    if (patch["mixed-port"]) {
-      const port = patch["mixed-port"];
-      if (port < 1000) {
-        throw new Error("The port should not < 1000");
-      }
-      if (port > 65536) {
-        throw new Error("The port should not > 65536");
-      }
-    }
-
-    await patchClashConfig(patch);
-    mutateInfo();
-    mutate("getClashConfig");
-    // 刷新接口
-    getAxios(true);
-  };
-
-  return {
-    clashInfo,
-    mutateInfo,
-    patchInfo,
-  };
-};
diff --git a/src/hooks/use-profiles.ts b/src/hooks/use-profiles.ts
deleted file mode 100644
index 5faa3cada58f4fcf667006f0aa00b48e1a3adc8d..0000000000000000000000000000000000000000
--- a/src/hooks/use-profiles.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import useSWR, { mutate } from "swr";
-import {
-  getProfiles,
-  patchProfile,
-  patchProfilesConfig,
-} from "@/services/cmds";
-import { getProxies, updateProxy } from "@/services/api";
-
-export const useProfiles = () => {
-  const { data: profiles, mutate: mutateProfiles } = useSWR(
-    "getProfiles",
-    getProfiles
-  );
-
-  const patchProfiles = async (value: Partial<IProfilesConfig>) => {
-    await patchProfilesConfig(value);
-    mutateProfiles();
-  };
-
-  const patchCurrent = async (value: Partial<IProfileItem>) => {
-    if (profiles?.current) {
-      await patchProfile(profiles.current, value);
-      mutateProfiles();
-    }
-  };
-
-  // 根据selected的节点选择
-  const activateSelected = async () => {
-    const proxiesData = await getProxies();
-    const profileData = await getProfiles();
-
-    if (!profileData || !proxiesData) return;
-
-    const current = profileData.items?.find(
-      (e) => e && e.uid === profileData.current
-    );
-
-    if (!current) return;
-
-    // init selected array
-    const { selected = [] } = current;
-    const selectedMap = Object.fromEntries(
-      selected.map((each) => [each.name!, each.now!])
-    );
-
-    let hasChange = false;
-
-    const newSelected: typeof selected = [];
-    const { global, groups } = proxiesData;
-
-    [global, ...groups].forEach(({ type, name, now }) => {
-      if (!now || type !== "Selector") return;
-      if (selectedMap[name] != null && selectedMap[name] !== now) {
-        hasChange = true;
-        updateProxy(name, selectedMap[name]);
-      }
-      newSelected.push({ name, now: selectedMap[name] });
-    });
-
-    if (hasChange) {
-      patchProfile(profileData.current!, { selected: newSelected });
-      mutate("getProxies", getProxies());
-    }
-  };
-
-  return {
-    profiles,
-    current: profiles?.items?.find((p) => p && p.uid === profiles.current),
-    activateSelected,
-    patchProfiles,
-    patchCurrent,
-    mutateProfiles,
-  };
-};
diff --git a/src/hooks/use-verge.ts b/src/hooks/use-verge.ts
deleted file mode 100644
index 6eeebe88508c35033119bd4c99073a107d131474..0000000000000000000000000000000000000000
--- a/src/hooks/use-verge.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import useSWR from "swr";
-import { getVergeConfig, patchVergeConfig } from "@/services/cmds";
-
-export const useVerge = () => {
-  const { data: verge, mutate: mutateVerge } = useSWR(
-    "getVergeConfig",
-    getVergeConfig
-  );
-
-  const patchVerge = async (value: Partial<IVergeConfig>) => {
-    await patchVergeConfig(value);
-    mutateVerge();
-  };
-
-  return {
-    verge,
-    mutateVerge,
-    patchVerge,
-  };
-};
diff --git a/src/hooks/use-visibility.ts b/src/hooks/use-visibility.ts
deleted file mode 100644
index 31d6d3d735937cca060fa779b60e1e1d97f321a2..0000000000000000000000000000000000000000
--- a/src/hooks/use-visibility.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { useEffect, useState } from "react";
-
-export const useVisibility = () => {
-  const [visible, setVisible] = useState(true);
-
-  useEffect(() => {
-    const handleVisibilityChange = () => {
-      setVisible(document.visibilityState === "visible");
-    };
-
-    const handleFocus = () => setVisible(true);
-    const handleClick = () => setVisible(true);
-
-    handleVisibilityChange();
-    document.addEventListener("focus", handleFocus);
-    document.addEventListener("pointerdown", handleClick);
-    document.addEventListener("visibilitychange", handleVisibilityChange);
-
-    return () => {
-      document.removeEventListener("focus", handleFocus);
-      document.removeEventListener("pointerdown", handleClick);
-      document.removeEventListener("visibilitychange", handleVisibilityChange);
-    };
-  }, []);
-
-  return visible;
-};
diff --git a/src/hooks/use-websocket.ts b/src/hooks/use-websocket.ts
deleted file mode 100644
index 810c7b13755d73608caadd952757d77d3be57aab..0000000000000000000000000000000000000000
--- a/src/hooks/use-websocket.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { useRef } from "react";
-
-export type WsMsgFn = (event: MessageEvent<any>) => void;
-
-export interface WsOptions {
-  errorCount?: number; // default is 5
-  retryInterval?: number; // default is 2500
-  onError?: () => void;
-}
-
-export const useWebsocket = (onMessage: WsMsgFn, options?: WsOptions) => {
-  const wsRef = useRef<WebSocket | null>(null);
-  const timerRef = useRef<any>(null);
-
-  const disconnect = () => {
-    if (wsRef.current) {
-      wsRef.current.close();
-      wsRef.current = null;
-    }
-    if (timerRef.current) {
-      clearTimeout(timerRef.current);
-    }
-  };
-
-  const connect = (url: string) => {
-    let errorCount = options?.errorCount ?? 5;
-
-    if (!url) return;
-
-    const connectHelper = () => {
-      disconnect();
-
-      const ws = new WebSocket(url);
-      wsRef.current = ws;
-
-      ws.addEventListener("message", onMessage);
-      ws.addEventListener("error", () => {
-        errorCount -= 1;
-
-        if (errorCount >= 0) {
-          timerRef.current = setTimeout(connectHelper, 2500);
-        } else {
-          disconnect();
-          options?.onError?.();
-        }
-      });
-    };
-
-    connectHelper();
-  };
-
-  return { connect, disconnect };
-};
diff --git a/src/index.html b/src/index.html
deleted file mode 100644
index 90966cbee10347607af7f5b05ab6b53e1228ff13..0000000000000000000000000000000000000000
--- a/src/index.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <link
-      rel="shortcut icon"
-      href="./assets/image/logo.ico"
-      type="image/x-icon"
-    />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Clash Verge</title>
-    <script>
-      (function () {
-        var _matchMedia = window.matchMedia;
-        window.matchMedia = function () {
-          var v = _matchMedia.apply(null, arguments);
-          if (!v.addEventListener) {
-            v.addEventListener = function () {
-              if (arguments.length < 2 || arguments[0] !== "change") {
-                console.error("Cannot proxy addEventListener:", arguments);
-                return;
-              }
-              if (arguments.length > 2) {
-                console.warn("Proxy addEventListener:", arguments);
-              }
-              v.addListener(arguments[1]);
-            };
-          }
-          return v;
-        };
-      })();
-    </script>
-  </head>
-  <body>
-    <div id="root"></div>
-    <script type="module" src="./main.tsx"></script>
-  </body>
-</html>
diff --git a/src/locales/en.json b/src/locales/en.json
deleted file mode 100644
index 10c92eff99aef36d90b02976285bbf213325431b..0000000000000000000000000000000000000000
--- a/src/locales/en.json
+++ /dev/null
@@ -1,135 +0,0 @@
-{
-  "Label-Proxies": "Proxies",
-  "Label-Profiles": "Profiles",
-  "Label-Connections": "Connections",
-  "Label-Logs": "Logs",
-  "Label-Rules": "Rules",
-  "Label-Settings": "Settings",
-
-  "Connections": "Connections",
-  "Logs": "Logs",
-  "Clear": "Clear",
-  "Proxies": "Proxies",
-  "Proxy Groups": "Proxy Groups",
-  "rule": "rule",
-  "global": "global",
-  "direct": "direct",
-  "script": "script",
-
-  "Profiles": "Profiles",
-  "Profile URL": "Profile URL",
-  "Import": "Import",
-  "New": "New",
-  "Create Profile": "Create Profile",
-  "Choose File": "Choose File",
-  "Close All": "Close All",
-  "Select": "Select",
-  "Edit Info": "Edit Info",
-  "Edit File": "Edit File",
-  "Open File": "Open File",
-  "Update": "Update",
-  "Update(Proxy)": "Update(Proxy)",
-  "Delete": "Delete",
-  "Enable": "Enable",
-  "Disable": "Disable",
-  "Refresh": "Refresh",
-  "To Top": "To Top",
-  "To End": "To End",
-  "Update All Profiles": "Update All Profiles",
-  "View Runtime Config": "View Runtime Config",
-  "Reactivate Profiles": "Reactivate Profiles",
-
-  "Location": "Location",
-  "Delay check": "Delay check",
-  "Sort by default": "Sort by default",
-  "Sort by delay": "Sort by delay",
-  "Sort by name": "Sort by name",
-  "Delay check URL": "Delay check URL",
-  "Proxy detail": "Proxy detail",
-  "Filter": "Filter",
-  "Filter conditions": "Filter conditions",
-  "Refresh profiles": "Refresh profiles",
-
-  "Type": "Type",
-  "Name": "Name",
-  "Descriptions": "Descriptions",
-  "Subscription URL": "Subscription URL",
-  "Update Interval": "Update Interval",
-  "Use System Proxy": "Use System Proxy",
-  "Use Clash Proxy": "Use Clash Proxy",
-
-  "Settings": "Settings",
-  "Clash Setting": "Clash Setting",
-  "System Setting": "System Setting",
-  "Verge Setting": "Verge Setting",
-  "Allow Lan": "Allow Lan",
-  "IPv6": "IPv6",
-  "Log Level": "Log Level",
-  "Mixed Port": "Mixed Port",
-  "External": "External",
-  "Clash Core": "Clash Core",
-  "Tun Mode": "Tun Mode",
-  "Service Mode": "Service Mode",
-  "Auto Launch": "Auto Launch",
-  "Silent Start": "Silent Start",
-  "System Proxy": "System Proxy",
-  "System Proxy Setting": "System Proxy Setting",
-  "Proxy Guard": "Proxy Guard",
-  "Guard Duration": "Guard Duration",
-  "Proxy Bypass": "Proxy Bypass",
-  "Current System Proxy": "Current System Proxy",
-  "Theme Mode": "Theme Mode",
-  "Theme Blur": "Theme Blur",
-  "Theme Setting": "Theme Setting",
-  "Layout Setting": "Layout Setting",
-  "Miscellaneous": "Miscellaneous",
-  "Hotkey Setting": "Hotkey Setting",
-  "Traffic Graph": "Traffic Graph",
-  "Memory Usage": "Memory Usage",
-  "Language": "Language",
-  "Open App Dir": "Open App Dir",
-  "Open Core Dir": "Open Core Dir",
-  "Open Logs Dir": "Open Logs Dir",
-  "Check for Updates": "Check for Updates",
-  "Verge Version": "Verge Version",
-  "theme.light": "Light",
-  "theme.dark": "Dark",
-  "theme.system": "System",
-  "Clash Field": "Clash Field",
-  "Runtime Config": "Runtime Config",
-  "ReadOnly": "ReadOnly",
-  "Restart": "Restart",
-
-  "Back": "Back",
-  "Save": "Save",
-  "Cancel": "Cancel",
-
-  "Default": "Default",
-  "Download Speed": "Download Speed",
-  "Upload Speed": "Upload Speed",
-
-  "open_dashboard": "Open Dashboard",
-  "clash_mode_rule": "Rule Mode",
-  "clash_mode_global": "Global Mode",
-  "clash_mode_direct": "Direct Mode",
-  "clash_mode_script": "Script Mode",
-  "toggle_system_proxy": "Toggle System Proxy",
-  "enable_system_proxy": "Enable System Proxy",
-  "disable_system_proxy": "Disable System Proxy",
-  "toggle_tun_mode": "Toggle Tun Mode",
-  "enable_tun_mode": "Enable Tun Mode",
-  "disable_tun_mode": "Disable Tun Mode",
-
-  "App Log Level": "App Log Level",
-  "Auto Close Connections": "Auto Close Connections",
-  "Enable Clash Fields Filter": "Enable Clash Fields Filter",
-  "Enable Builtin Enhanced": "Enable Builtin Enhanced",
-  "Proxy Layout Column": "Proxy Layout Column",
-  "Default Latency Test": "Default Latency Test",
-
-  "Auto Log Clean": "Auto Log Clean",
-  "Never Clean": "Never Clean",
-  "Retain 7 Days": "Retain 7 Days",
-  "Retain 30 Days": "Retain 30 Days",
-  "Retain 90 Days": "Retain 90 Days"
-}
diff --git a/src/locales/ru.json b/src/locales/ru.json
deleted file mode 100644
index f8ea10be28857fe7bd77dd1f98989ecb6ab0fbdf..0000000000000000000000000000000000000000
--- a/src/locales/ru.json
+++ /dev/null
@@ -1,111 +0,0 @@
-{
-  "Label-Proxies": "Прокси",
-  "Label-Profiles": "Профили",
-  "Label-Connections": "Соединения",
-  "Label-Logs": "Логи",
-  "Label-Rules": "Правила",
-  "Label-Settings": "Настройки",
-
-  "Connections": "Соединения",
-  "Logs": "Логи",
-  "Clear": "Очистить",
-  "Proxies": "Прокси",
-  "Proxy Groups": "Группы прокси",
-  "rule": "правила",
-  "global": "глобальный",
-  "direct": "прямой",
-  "script": "скриптовый",
-
-  "Profiles": "Профили",
-  "Profile URL": "URL профиля",
-  "Import": "Импорт",
-  "New": "Новый",
-  "Create Profile": "Создать профиль",
-  "Choose File": "Выбрать файл",
-  "Close All": "Закрыть всё",
-  "Select": "Выбрать",
-  "Edit Info": "Изменить информацию",
-  "Edit File": "Изменить файл",
-  "Open File": "Открыть файл",
-  "Update": "Обновить",
-  "Update(Proxy)": "Обновить (прокси)",
-  "Delete": "Удалить",
-  "Enable": "Включить",
-  "Disable": "Отключить",
-  "Refresh": "Обновить",
-  "To Top": "Наверх",
-  "To End": "Вниз",
-  "Update All Profiles": "Обновить все профили",
-  "View Runtime Config": "Просмотреть используемый конфиг",
-  "Reactivate Profiles": "Реактивировать профили",
-
-  "Location": "Местоположение",
-  "Delay check": "Проверка задержки",
-  "Sort by default": "Сортировать по умолчанию",
-  "Sort by delay": "Сортировать по задержке",
-  "Sort by name": "Сортировать по названию",
-  "Delay check URL": "URL проверки задержки",
-  "Proxy detail": "Подробности о прокси",
-  "Filter": "Фильтр",
-  "Filter conditions": "Условия фильтрации",
-  "Refresh profiles": "Обновить профили",
-
-  "Type": "Тип",
-  "Name": "Название",
-  "Descriptions": "Описания",
-  "Subscription URL": "URL подписки",
-  "Update Interval": "Интервал обновления",
-
-  "Settings": "Настройки",
-  "Clash Setting": "Настройки Clash",
-  "System Setting": "Настройки системы",
-  "Verge Setting": "Настройки Verge",
-  "Allow Lan": "Разрешить локальную сеть",
-  "IPv6": "IPv6",
-  "Log Level": "Уровень логов",
-  "Mixed Port": "Смешанный порт",
-  "Clash Core": "Ядро Clash",
-  "Tun Mode": "Режим туннеля",
-  "Service Mode": "Режим сервиса",
-  "Auto Launch": "Автозапуск",
-  "Silent Start": "Тихий запуск",
-  "System Proxy": "Системный прокси",
-  "System Proxy Setting": "Настройка системного прокси",
-  "Proxy Guard": "Защита прокси",
-  "Guard Duration": "Период защиты",
-  "Proxy Bypass": "Игнорирование прокси",
-  "Current System Proxy": "Текущий системный прокси",
-  "Theme Mode": "Режим темы",
-  "Theme Blur": "Размытие темы",
-  "Theme Setting": "Настройка темы",
-  "Hotkey Setting": "Настройка клавиатурных сокращений",
-  "Traffic Graph": "График трафика",
-  "Language": "Язык",
-  "Open App Dir": "Открыть папку приложения",
-  "Open Core Dir": "Открыть папку ядра",
-  "Open Logs Dir": "Открыть папку логов",
-  "Verge Version": "Версия Verge",
-  "theme.light": "Светлая",
-  "theme.dark": "Тёмная",
-  "theme.system": "Системная",
-  "Clash Field": "Используемые настройки Clash",
-  "Runtime Config": "Используемый конфиг",
-  "ReadOnly": "Только для чтения",
-  "Restart": "Перезапуск",
-
-  "Back": "Назад",
-  "Save": "Сохранить",
-  "Cancel": "Отмена",
-
-  "open_dashboard": "Open Dashboard",
-  "clash_mode_rule": "Режим правил",
-  "clash_mode_global": "Глобальный режим",
-  "clash_mode_direct": "Прямой режим",
-  "clash_mode_script": "Скриптовый режим",
-  "toggle_system_proxy": "Переключить режим системного прокси",
-  "enable_system_proxy": "Включить системный прокси",
-  "disable_system_proxy": "Отключить системный прокси",
-  "toggle_tun_mode": "Переключить режим туннеля",
-  "enable_tun_mode": "Включить режим туннеля",
-  "disable_tun_mode": "Отключить режим туннеля"
-}
diff --git a/src/locales/zh.json b/src/locales/zh.json
deleted file mode 100644
index 27b358ca27450530d6e7fd3bcc14592ab9a31396..0000000000000000000000000000000000000000
--- a/src/locales/zh.json
+++ /dev/null
@@ -1,135 +0,0 @@
-{
-  "Label-Proxies": "代 理",
-  "Label-Profiles": "配 置",
-  "Label-Connections": "连 接",
-  "Label-Logs": "æ—¥ å¿—",
-  "Label-Rules": "规 则",
-  "Label-Settings": "设 置",
-
-  "Connections": "连接",
-  "Logs": "日志",
-  "Clear": "清除",
-  "Proxies": "代理",
-  "Proxy Groups": "代理组",
-  "rule": "规则",
-  "global": "全局",
-  "direct": "直连",
-  "script": "脚本",
-
-  "Profiles": "配置",
-  "Profile URL": "配置文件链接",
-  "Import": "导入",
-  "New": "新建",
-  "Create Profile": "新建配置",
-  "Choose File": "选择文件",
-  "Close All": "关闭全部",
-  "Select": "使用",
-  "Edit Info": "编辑信息",
-  "Edit File": "编辑文件",
-  "Open File": "打开文件",
-  "Update": "æ›´æ–°",
-  "Update(Proxy)": "更新(代理)",
-  "Delete": "删除",
-  "Enable": "启用",
-  "Disable": "禁用",
-  "Refresh": "刷新",
-  "To Top": "移到最前",
-  "To End": "移到末尾",
-  "Update All Profiles": "更新所有配置",
-  "View Runtime Config": "查看运行时配置",
-  "Reactivate Profiles": "重新激活配置",
-
-  "Location": "当前节点",
-  "Delay check": "延迟测试",
-  "Sort by default": "默认排序",
-  "Sort by delay": "按延迟排序",
-  "Sort by name": "按名称排序",
-  "Delay check URL": "延迟测试链接",
-  "Proxy detail": "展示节点细节",
-  "Filter": "过滤节点",
-  "Filter conditions": "过滤条件",
-  "Refresh profiles": "刷新配置",
-
-  "Type": "类型",
-  "Name": "名称",
-  "Descriptions": "描述",
-  "Subscription URL": "订阅链接",
-  "Update Interval": "æ›´æ–°é—´éš”",
-  "Use System Proxy": "使用系统代理更新",
-  "Use Clash Proxy": "使用Clash代理更新",
-
-  "Settings": "设置",
-  "Clash Setting": "Clash 设置",
-  "System Setting": "系统设置",
-  "Verge Setting": "Verge 设置",
-  "Allow Lan": "局域网连接",
-  "IPv6": "IPv6",
-  "Log Level": "日志等级",
-  "Mixed Port": "端口设置",
-  "External": "外部控制",
-  "Clash Core": "Clash 内核",
-  "Tun Mode": "Tun 模式",
-  "Service Mode": "服务模式",
-  "Auto Launch": "开机自启",
-  "Silent Start": "静默启动",
-  "System Proxy": "系统代理",
-  "System Proxy Setting": "系统代理设置",
-  "Proxy Guard": "系统代理守卫",
-  "Guard Duration": "代理守卫间隔",
-  "Proxy Bypass": "Proxy Bypass",
-  "Current System Proxy": "当前系统代理",
-  "Theme Mode": "主题模式",
-  "Theme Blur": "背景模糊",
-  "Theme Setting": "主题设置",
-  "Layout Setting": "界面设置",
-  "Miscellaneous": "杂项设置",
-  "Hotkey Setting": "热键设置",
-  "Traffic Graph": "流量图显",
-  "Memory Usage": "内存使用",
-  "Language": "语言设置",
-  "Open App Dir": "应用目录",
-  "Open Core Dir": "内核目录",
-  "Open Logs Dir": "日志目录",
-  "Check for Updates": "检查更新",
-  "Verge Version": "应用版本",
-  "theme.light": "浅色",
-  "theme.dark": "深色",
-  "theme.system": "系统",
-  "Clash Field": "Clash 字段",
-  "Runtime Config": "运行配置",
-  "ReadOnly": "只读",
-  "Restart": "重启内核",
-
-  "Back": "返回",
-  "Save": "保存",
-  "Cancel": "取消",
-
-  "Default": "默认",
-  "Download Speed": "下载速度",
-  "Upload Speed": "上传速度",
-
-  "open_dashboard": "打开面板",
-  "clash_mode_rule": "规则模式",
-  "clash_mode_global": "全局模式",
-  "clash_mode_direct": "直连模式",
-  "clash_mode_script": "脚本模式",
-  "toggle_system_proxy": "切换系统代理",
-  "enable_system_proxy": "开启系统代理",
-  "disable_system_proxy": "关闭系统代理",
-  "toggle_tun_mode": "切换Tun模式",
-  "enable_tun_mode": "开启Tun模式",
-  "disable_tun_mode": "关闭Tun模式",
-
-  "App Log Level": "App日志等级",
-  "Auto Close Connections": "自动关闭连接",
-  "Enable Clash Fields Filter": "开启Clash字段过滤",
-  "Enable Builtin Enhanced": "开启内建增强功能",
-  "Proxy Layout Column": "代理页布局列数",
-  "Default Latency Test": "默认测试链接",
-
-  "Auto Log Clean": "自动清理日志",
-  "Never Clean": "不清理",
-  "Retain 7 Days": "保留7天",
-  "Retain 30 Days": "保留30天",
-  "Retain 90 Days": "保留90天"
-}
diff --git a/src/main.tsx b/src/main.tsx
deleted file mode 100644
index 8588844ed47934f2cc519a868488447c1f8a2562..0000000000000000000000000000000000000000
--- a/src/main.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/// <reference types="vite/client" />
-/// <reference types="vite-plugin-svgr/client" />
-import "./assets/styles/index.scss";
-
-import { ResizeObserver } from "@juggle/resize-observer";
-if (!window.ResizeObserver) {
-  window.ResizeObserver = ResizeObserver;
-}
-
-import React from "react";
-import { createRoot } from "react-dom/client";
-import { RecoilRoot } from "recoil";
-import { BrowserRouter } from "react-router-dom";
-import { BaseErrorBoundary } from "./components/base";
-import Layout from "./pages/_layout";
-import "./services/i18n";
-
-const mainElementId = "root";
-const container = document.getElementById(mainElementId);
-
-if (!container) {
-  throw new Error(
-    `No container '${mainElementId}' found to render application`
-  );
-}
-
-createRoot(container).render(
-  <React.StrictMode>
-    <RecoilRoot>
-      <BaseErrorBoundary>
-        <BrowserRouter>
-          <Layout />
-        </BrowserRouter>
-      </BaseErrorBoundary>
-    </RecoilRoot>
-  </React.StrictMode>
-);
diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx
deleted file mode 100644
index 27ef9b005a90eaf4364d1e7634f0ce7dc549560b..0000000000000000000000000000000000000000
--- a/src/pages/_layout.tsx
+++ /dev/null
@@ -1,161 +0,0 @@
-import dayjs from "dayjs";
-import i18next from "i18next";
-import relativeTime from "dayjs/plugin/relativeTime";
-import { SWRConfig, mutate } from "swr";
-import { useEffect } from "react";
-import { useTranslation } from "react-i18next";
-import { Route, Routes } from "react-router-dom";
-import { alpha, List, Paper, ThemeProvider } from "@mui/material";
-import { listen } from "@tauri-apps/api/event";
-import { appWindow } from "@tauri-apps/api/window";
-import { routers } from "./_routers";
-import { getAxios } from "@/services/api";
-import { useVerge } from "@/hooks/use-verge";
-import { ReactComponent as LogoSvg } from "@/assets/image/logo.svg";
-import { BaseErrorBoundary, Notice } from "@/components/base";
-import { LayoutItem } from "@/components/layout/layout-item";
-import { LayoutControl } from "@/components/layout/layout-control";
-import { LayoutTraffic } from "@/components/layout/layout-traffic";
-import { UpdateButton } from "@/components/layout/update-button";
-import { useCustomTheme } from "@/components/layout/use-custom-theme";
-import getSystem from "@/utils/get-system";
-import "dayjs/locale/ru";
-import "dayjs/locale/zh-cn";
-
-dayjs.extend(relativeTime);
-
-const OS = getSystem();
-
-const Layout = () => {
-  const { t } = useTranslation();
-
-  const { theme } = useCustomTheme();
-
-  const { verge } = useVerge();
-  const { theme_blur, language } = verge || {};
-
-  useEffect(() => {
-    window.addEventListener("keydown", (e) => {
-      // macOS有cmd+w
-      if (e.key === "Escape" && OS !== "macos") {
-        appWindow.close();
-      }
-    });
-
-    listen("verge://refresh-clash-config", async () => {
-      // the clash info may be updated
-      await getAxios(true);
-      mutate("getProxies");
-      mutate("getVersion");
-      mutate("getClashConfig");
-      mutate("getProviders");
-    });
-
-    // update the verge config
-    listen("verge://refresh-verge-config", () => mutate("getVergeConfig"));
-
-    // 设置提示监听
-    listen("verge://notice-message", ({ payload }) => {
-      const [status, msg] = payload as [string, string];
-      switch (status) {
-        case "set_config::ok":
-          Notice.success("Refresh clash config");
-          break;
-        case "set_config::error":
-          Notice.error(msg);
-          break;
-        default:
-          break;
-      }
-    });
-  }, []);
-
-  useEffect(() => {
-    if (language) {
-      dayjs.locale(language === "zh" ? "zh-cn" : language);
-      i18next.changeLanguage(language);
-    }
-  }, [language]);
-
-  return (
-    <SWRConfig value={{ errorRetryCount: 3 }}>
-      <ThemeProvider theme={theme}>
-        <Paper
-          square
-          elevation={0}
-          className={`${OS} layout`}
-          onPointerDown={(e: any) => {
-            if (e.target?.dataset?.windrag) appWindow.startDragging();
-          }}
-          onContextMenu={(e) => {
-            // only prevent it on Windows
-            const validList = ["input", "textarea"];
-            const target = e.currentTarget;
-            if (
-              OS === "windows" &&
-              !(
-                validList.includes(target.tagName.toLowerCase()) ||
-                target.isContentEditable
-              )
-            ) {
-              e.preventDefault();
-            }
-          }}
-          sx={[
-            ({ palette }) => ({
-              bgcolor: alpha(palette.background.paper, theme_blur ? 0.8 : 1),
-            }),
-          ]}
-        >
-          <div className="layout__left" data-windrag>
-            <div className="the-logo" data-windrag>
-              <LogoSvg />
-
-              {!(OS === "windows" && WIN_PORTABLE) && (
-                <UpdateButton className="the-newbtn" />
-              )}
-            </div>
-
-            <List className="the-menu">
-              {routers.map((router) => (
-                <LayoutItem key={router.label} to={router.link}>
-                  {t(router.label)}
-                </LayoutItem>
-              ))}
-            </List>
-
-            <div className="the-traffic" data-windrag>
-              <LayoutTraffic />
-            </div>
-          </div>
-
-          <div className="layout__right" data-windrag>
-            {OS === "windows" && (
-              <div className="the-bar">
-                <LayoutControl />
-              </div>
-            )}
-
-            <div className="the-content">
-              <Routes>
-                {routers.map(({ label, link, ele: Ele }) => (
-                  <Route
-                    key={label}
-                    path={link}
-                    element={
-                      <BaseErrorBoundary key={label}>
-                        <Ele />
-                      </BaseErrorBoundary>
-                    }
-                  />
-                ))}
-              </Routes>
-            </div>
-          </div>
-        </Paper>
-      </ThemeProvider>
-    </SWRConfig>
-  );
-};
-
-export default Layout;
diff --git a/src/pages/_routers.tsx b/src/pages/_routers.tsx
deleted file mode 100644
index f53ed487a4c93ad7523c344b6ce49e22e014aa9f..0000000000000000000000000000000000000000
--- a/src/pages/_routers.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import LogsPage from "./logs";
-import ProxiesPage from "./proxies";
-import ProfilesPage from "./profiles";
-import SettingsPage from "./settings";
-import ConnectionsPage from "./connections";
-import RulesPage from "./rules";
-
-export const routers = [
-  {
-    label: "Label-Proxies",
-    link: "/",
-    ele: ProxiesPage,
-  },
-  {
-    label: "Label-Profiles",
-    link: "/profile",
-    ele: ProfilesPage,
-  },
-  {
-    label: "Label-Connections",
-    link: "/connections",
-    ele: ConnectionsPage,
-  },
-  {
-    label: "Label-Rules",
-    link: "/rules",
-    ele: RulesPage,
-  },
-  {
-    label: "Label-Logs",
-    link: "/logs",
-    ele: LogsPage,
-  },
-  {
-    label: "Label-Settings",
-    link: "/settings",
-    ele: SettingsPage,
-  },
-];
diff --git a/src/pages/_theme.tsx b/src/pages/_theme.tsx
deleted file mode 100644
index 37ce63e53785de61414e8ea41e24af913bf39fc0..0000000000000000000000000000000000000000
--- a/src/pages/_theme.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-// default theme setting
-export const defaultTheme = {
-  primary_color: "#5b5c9d",
-  secondary_color: "#9c27b0",
-  primary_text: "#637381",
-  secondary_text: "#909399",
-  info_color: "#0288d1",
-  error_color: "#d32f2f",
-  warning_color: "#ed6c02",
-  success_color: "#2e7d32",
-  font_family: `"Roboto", "Helvetica", "Arial", sans-serif`,
-};
-
-// dark mode
-export const defaultDarkTheme = {
-  ...defaultTheme,
-  primary_text: "#757575",
-  secondary_text: "#637381",
-};
diff --git a/src/pages/connections.tsx b/src/pages/connections.tsx
deleted file mode 100644
index 7c53f678716eaa5e200fdee85a4ba3b50d2c208d..0000000000000000000000000000000000000000
--- a/src/pages/connections.tsx
+++ /dev/null
@@ -1,218 +0,0 @@
-import { useEffect, useMemo, useRef, useState } from "react";
-import { useLockFn } from "ahooks";
-import {
-  Box,
-  Button,
-  IconButton,
-  MenuItem,
-  Paper,
-  Select,
-  TextField,
-} from "@mui/material";
-import { useRecoilState } from "recoil";
-import { Virtuoso } from "react-virtuoso";
-import { useTranslation } from "react-i18next";
-import { TableChartRounded, TableRowsRounded } from "@mui/icons-material";
-import { closeAllConnections } from "@/services/api";
-import { atomConnectionSetting } from "@/services/states";
-import { useClashInfo } from "@/hooks/use-clash";
-import { BaseEmpty, BasePage } from "@/components/base";
-import { useWebsocket } from "@/hooks/use-websocket";
-import { ConnectionItem } from "@/components/connection/connection-item";
-import { ConnectionTable } from "@/components/connection/connection-table";
-import {
-  ConnectionDetail,
-  ConnectionDetailRef,
-} from "@/components/connection/connection-detail";
-
-const initConn = { uploadTotal: 0, downloadTotal: 0, connections: [] };
-
-type OrderFunc = (list: IConnectionsItem[]) => IConnectionsItem[];
-
-const ConnectionsPage = () => {
-  const { t, i18n } = useTranslation();
-  const { clashInfo } = useClashInfo();
-
-  const [filterText, setFilterText] = useState("");
-  const [curOrderOpt, setOrderOpt] = useState("Default");
-  const [connData, setConnData] = useState<IConnections>(initConn);
-
-  const [setting, setSetting] = useRecoilState(atomConnectionSetting);
-
-  const isTableLayout = setting.layout === "table";
-
-  const orderOpts: Record<string, OrderFunc> = {
-    Default: (list) => list,
-    "Upload Speed": (list) => list.sort((a, b) => b.curUpload! - a.curUpload!),
-    "Download Speed": (list) =>
-      list.sort((a, b) => b.curDownload! - a.curDownload!),
-  };
-
-  const filterConn = useMemo(() => {
-    const orderFunc = orderOpts[curOrderOpt];
-    const connections = connData.connections.filter((conn) =>
-      (conn.metadata.host || conn.metadata.destinationIP)?.includes(filterText)
-    );
-
-    if (orderFunc) return orderFunc(connections);
-    return connections;
-  }, [connData, filterText, curOrderOpt]);
-
-  const { connect, disconnect } = useWebsocket(
-    (event) => {
-      // meta v1.15.0 出现data.connections为null的情况
-      const data = JSON.parse(event.data) as IConnections;
-      // 尽量与前一次connections的展示顺序保持一致
-      setConnData((old) => {
-        const oldConn = old.connections;
-        const maxLen = data.connections?.length;
-
-        const connections: typeof oldConn = [];
-
-        const rest = (data.connections || []).filter((each) => {
-          const index = oldConn.findIndex((o) => o.id === each.id);
-
-          if (index >= 0 && index < maxLen) {
-            const old = oldConn[index];
-            each.curUpload = each.upload - old.upload;
-            each.curDownload = each.download - old.download;
-
-            connections[index] = each;
-            return false;
-          }
-          return true;
-        });
-
-        for (let i = 0; i < maxLen; ++i) {
-          if (!connections[i] && rest.length > 0) {
-            connections[i] = rest.shift()!;
-            connections[i].curUpload = 0;
-            connections[i].curDownload = 0;
-          }
-        }
-
-        return { ...data, connections };
-      });
-    },
-    { errorCount: 3, retryInterval: 1000 }
-  );
-
-  useEffect(() => {
-    if (!clashInfo) return;
-
-    const { server = "", secret = "" } = clashInfo;
-    connect(`ws://${server}/connections?token=${encodeURIComponent(secret)}`);
-
-    return () => {
-      disconnect();
-    };
-  }, [clashInfo]);
-
-  const onCloseAll = useLockFn(closeAllConnections);
-
-  const detailRef = useRef<ConnectionDetailRef>(null!);
-
-  return (
-    <BasePage
-      title={t("Connections")}
-      contentStyle={{ height: "100%" }}
-      header={
-        <Box sx={{ mt: 1, display: "flex", alignItems: "center", gap: 2 }}>
-          <IconButton
-            color="inherit"
-            size="small"
-            onClick={() =>
-              setSetting((o) =>
-                o.layout === "list"
-                  ? { ...o, layout: "table" }
-                  : { ...o, layout: "list" }
-              )
-            }
-          >
-            {isTableLayout ? (
-              <TableChartRounded fontSize="inherit" />
-            ) : (
-              <TableRowsRounded fontSize="inherit" />
-            )}
-          </IconButton>
-
-          <Button size="small" variant="contained" onClick={onCloseAll}>
-            {t("Close All")}
-          </Button>
-        </Box>
-      }
-    >
-      <Paper sx={{ boxShadow: 2, height: "100%" }}>
-        <Box
-          sx={{
-            pt: 1,
-            mb: 0.5,
-            mx: "12px",
-            height: "36px",
-            display: "flex",
-            alignItems: "center",
-            userSelect: "text",
-          }}
-        >
-          {!isTableLayout && (
-            <Select
-              size="small"
-              autoComplete="off"
-              value={curOrderOpt}
-              onChange={(e) => setOrderOpt(e.target.value)}
-              sx={{
-                mr: 1,
-                width: i18n.language === "en" ? 190 : 120,
-                '[role="button"]': { py: 0.65 },
-              }}
-            >
-              {Object.keys(orderOpts).map((opt) => (
-                <MenuItem key={opt} value={opt}>
-                  <span style={{ fontSize: 14 }}>{t(opt)}</span>
-                </MenuItem>
-              ))}
-            </Select>
-          )}
-
-          <TextField
-            hiddenLabel
-            fullWidth
-            size="small"
-            autoComplete="off"
-            spellCheck="false"
-            variant="outlined"
-            placeholder={t("Filter conditions")}
-            value={filterText}
-            onChange={(e) => setFilterText(e.target.value)}
-            sx={{ input: { py: 0.65, px: 1.25 } }}
-          />
-        </Box>
-
-        <Box height="calc(100% - 50px)" sx={{ userSelect: "text" }}>
-          {filterConn.length === 0 ? (
-            <BaseEmpty text="No Connections" />
-          ) : isTableLayout ? (
-            <ConnectionTable
-              connections={filterConn}
-              onShowDetail={(detail) => detailRef.current?.open(detail)}
-            />
-          ) : (
-            <Virtuoso
-              data={filterConn}
-              itemContent={(index, item) => (
-                <ConnectionItem
-                  value={item}
-                  onShowDetail={() => detailRef.current?.open(item)}
-                />
-              )}
-            />
-          )}
-        </Box>
-
-        <ConnectionDetail ref={detailRef} />
-      </Paper>
-    </BasePage>
-  );
-};
-
-export default ConnectionsPage;
diff --git a/src/pages/logs.tsx b/src/pages/logs.tsx
deleted file mode 100644
index a26b7eb42d23175f140a970a4e2ca2ebf8428e64..0000000000000000000000000000000000000000
--- a/src/pages/logs.tsx
+++ /dev/null
@@ -1,129 +0,0 @@
-import { useMemo, useState } from "react";
-import { useRecoilState } from "recoil";
-import {
-  Box,
-  Button,
-  IconButton,
-  MenuItem,
-  Paper,
-  Select,
-  TextField,
-} from "@mui/material";
-import { Virtuoso } from "react-virtuoso";
-import { useTranslation } from "react-i18next";
-import {
-  PlayCircleOutlineRounded,
-  PauseCircleOutlineRounded,
-} from "@mui/icons-material";
-import { atomEnableLog, atomLogData } from "@/services/states";
-import { BaseEmpty, BasePage } from "@/components/base";
-import LogItem from "@/components/log/log-item";
-
-const LogPage = () => {
-  const { t } = useTranslation();
-  const [logData, setLogData] = useRecoilState(atomLogData);
-  const [enableLog, setEnableLog] = useRecoilState(atomEnableLog);
-
-  const [logState, setLogState] = useState("all");
-  const [filterText, setFilterText] = useState("");
-
-  const filterLogs = useMemo(() => {
-    return logData.filter((data) => {
-      return (
-        data.payload.includes(filterText) &&
-        (logState === "all" ? true : data.type.includes(logState))
-      );
-    });
-  }, [logData, logState, filterText]);
-
-  return (
-    <BasePage
-      title={t("Logs")}
-      contentStyle={{ height: "100%" }}
-      header={
-        <Box sx={{ mt: 1, display: "flex", alignItems: "center", gap: 2 }}>
-          <IconButton
-            size="small"
-            color="inherit"
-            onClick={() => setEnableLog((e) => !e)}
-          >
-            {enableLog ? (
-              <PauseCircleOutlineRounded />
-            ) : (
-              <PlayCircleOutlineRounded />
-            )}
-          </IconButton>
-
-          <Button
-            size="small"
-            variant="contained"
-            onClick={() => setLogData([])}
-          >
-            {t("Clear")}
-          </Button>
-        </Box>
-      }
-    >
-      <Paper
-        sx={{
-          boxSizing: "border-box",
-          boxShadow: 2,
-          height: "100%",
-          userSelect: "text",
-        }}
-      >
-        <Box
-          sx={{
-            pt: 1,
-            mb: 0.5,
-            mx: "12px",
-            height: "36px",
-            display: "flex",
-            alignItems: "center",
-          }}
-        >
-          <Select
-            size="small"
-            autoComplete="off"
-            value={logState}
-            onChange={(e) => setLogState(e.target.value)}
-            sx={{ width: 120, mr: 1, '[role="button"]': { py: 0.65 } }}
-          >
-            <MenuItem value="all">ALL</MenuItem>
-            <MenuItem value="inf">INFO</MenuItem>
-            <MenuItem value="warn">WARN</MenuItem>
-            <MenuItem value="err">ERROR</MenuItem>
-          </Select>
-
-          <TextField
-            hiddenLabel
-            fullWidth
-            size="small"
-            autoComplete="off"
-            spellCheck="false"
-            variant="outlined"
-            placeholder={t("Filter conditions")}
-            value={filterText}
-            onChange={(e) => setFilterText(e.target.value)}
-            sx={{ input: { py: 0.65, px: 1.25 } }}
-          />
-        </Box>
-
-        <Box height="calc(100% - 50px)">
-          {filterLogs.length > 0 ? (
-            <Virtuoso
-              initialTopMostItemIndex={999}
-              data={filterLogs}
-              itemContent={(index, item) => <LogItem value={item} />}
-              followOutput={"smooth"}
-            />
-          ) : (
-            <BaseEmpty text="No Logs" />
-          )}
-        </Box>
-      </Paper>
-    </BasePage>
-  );
-};
-
-export default LogPage;
diff --git a/src/pages/profiles.tsx b/src/pages/profiles.tsx
deleted file mode 100644
index 95a4fc8a15375066f46ac11c6532d585956a2760..0000000000000000000000000000000000000000
--- a/src/pages/profiles.tsx
+++ /dev/null
@@ -1,334 +0,0 @@
-import useSWR, { mutate } from "swr";
-import { useMemo, useRef, useState } from "react";
-import { useLockFn } from "ahooks";
-import { useSetRecoilState } from "recoil";
-import { Box, Button, Grid, IconButton, Stack, TextField } from "@mui/material";
-import {
-  ClearRounded,
-  ContentCopyRounded,
-  LocalFireDepartmentRounded,
-  RefreshRounded,
-  TextSnippetOutlined,
-} from "@mui/icons-material";
-import { useTranslation } from "react-i18next";
-import {
-  getProfiles,
-  importProfile,
-  enhanceProfiles,
-  getRuntimeLogs,
-  deleteProfile,
-  updateProfile,
-} from "@/services/cmds";
-import { atomLoadingCache } from "@/services/states";
-import { closeAllConnections } from "@/services/api";
-import { BasePage, DialogRef, Notice } from "@/components/base";
-import {
-  ProfileViewer,
-  ProfileViewerRef,
-} from "@/components/profile/profile-viewer";
-import { ProfileItem } from "@/components/profile/profile-item";
-import { ProfileMore } from "@/components/profile/profile-more";
-import { useProfiles } from "@/hooks/use-profiles";
-import { ConfigViewer } from "@/components/setting/mods/config-viewer";
-import { throttle } from "lodash-es";
-
-const ProfilePage = () => {
-  const { t } = useTranslation();
-
-  const [url, setUrl] = useState("");
-  const [disabled, setDisabled] = useState(false);
-  const [activating, setActivating] = useState("");
-
-  const {
-    profiles = {},
-    activateSelected,
-    patchProfiles,
-    mutateProfiles,
-  } = useProfiles();
-
-  const { data: chainLogs = {}, mutate: mutateLogs } = useSWR(
-    "getRuntimeLogs",
-    getRuntimeLogs
-  );
-
-  const chain = profiles.chain || [];
-  const viewerRef = useRef<ProfileViewerRef>(null);
-  const configRef = useRef<DialogRef>(null);
-
-  // distinguish type
-  const { regularItems, enhanceItems } = useMemo(() => {
-    const items = profiles.items || [];
-    const chain = profiles.chain || [];
-
-    const type1 = ["local", "remote"];
-    const type2 = ["merge", "script"];
-
-    const regularItems = items.filter((i) => i && type1.includes(i.type!));
-    const restItems = items.filter((i) => i && type2.includes(i.type!));
-    const restMap = Object.fromEntries(restItems.map((i) => [i.uid, i]));
-    const enhanceItems = chain
-      .map((i) => restMap[i]!)
-      .filter(Boolean)
-      .concat(restItems.filter((i) => !chain.includes(i.uid)));
-
-    return { regularItems, enhanceItems };
-  }, [profiles]);
-
-  const onImport = async () => {
-    if (!url) return;
-    setUrl("");
-    setDisabled(true);
-
-    try {
-      await importProfile(url);
-      Notice.success("Successfully import profile.");
-
-      getProfiles().then((newProfiles) => {
-        mutate("getProfiles", newProfiles);
-
-        const remoteItem = newProfiles.items?.find((e) => e.type === "remote");
-        if (!newProfiles.current && remoteItem) {
-          const current = remoteItem.uid;
-          patchProfiles({ current });
-          mutateLogs();
-          setTimeout(() => activateSelected(), 2000);
-        }
-      });
-    } catch (err: any) {
-      Notice.error(err.message || err.toString());
-    } finally {
-      setDisabled(false);
-    }
-  };
-
-  const onSelect = useLockFn(async (current: string, force: boolean) => {
-    if (!force && current === profiles.current) return;
-    // 避免大多数情况下loading态闪烁
-    const reset = setTimeout(() => setActivating(current), 100);
-    try {
-      await patchProfiles({ current });
-      mutateLogs();
-      closeAllConnections();
-      setTimeout(() => activateSelected(), 2000);
-      Notice.success("Refresh clash config", 1000);
-    } catch (err: any) {
-      Notice.error(err?.message || err.toString(), 4000);
-    } finally {
-      clearTimeout(reset);
-      setActivating("");
-    }
-  });
-
-  const onEnhance = useLockFn(async () => {
-    try {
-      await enhanceProfiles();
-      mutateLogs();
-      Notice.success("Refresh clash config", 1000);
-    } catch (err: any) {
-      Notice.error(err.message || err.toString(), 3000);
-    }
-  });
-
-  const onEnable = useLockFn(async (uid: string) => {
-    if (chain.includes(uid)) return;
-    const newChain = [...chain, uid];
-    await patchProfiles({ chain: newChain });
-    mutateLogs();
-  });
-
-  const onDisable = useLockFn(async (uid: string) => {
-    if (!chain.includes(uid)) return;
-    const newChain = chain.filter((i) => i !== uid);
-    await patchProfiles({ chain: newChain });
-    mutateLogs();
-  });
-
-  const onDelete = useLockFn(async (uid: string) => {
-    try {
-      await onDisable(uid);
-      await deleteProfile(uid);
-      mutateProfiles();
-      mutateLogs();
-    } catch (err: any) {
-      Notice.error(err?.message || err.toString());
-    }
-  });
-
-  const onMoveTop = useLockFn(async (uid: string) => {
-    if (!chain.includes(uid)) return;
-    const newChain = [uid].concat(chain.filter((i) => i !== uid));
-    await patchProfiles({ chain: newChain });
-    mutateLogs();
-  });
-
-  const onMoveEnd = useLockFn(async (uid: string) => {
-    if (!chain.includes(uid)) return;
-    const newChain = chain.filter((i) => i !== uid).concat([uid]);
-    await patchProfiles({ chain: newChain });
-    mutateLogs();
-  });
-
-  // 更新所有配置
-  const setLoadingCache = useSetRecoilState(atomLoadingCache);
-  const onUpdateAll = useLockFn(async () => {
-    const throttleMutate = throttle(mutateProfiles, 2000, {
-      trailing: true,
-    });
-    const updateOne = async (uid: string) => {
-      try {
-        await updateProfile(uid);
-        throttleMutate();
-      } finally {
-        setLoadingCache((cache) => ({ ...cache, [uid]: false }));
-      }
-    };
-
-    return new Promise((resolve) => {
-      setLoadingCache((cache) => {
-        // 获取没有正在更新的配置
-        const items = regularItems.filter(
-          (e) => e.type === "remote" && !cache[e.uid]
-        );
-        const change = Object.fromEntries(items.map((e) => [e.uid, true]));
-
-        Promise.allSettled(items.map((e) => updateOne(e.uid))).then(resolve);
-        return { ...cache, ...change };
-      });
-    });
-  });
-
-  const onCopyLink = async () => {
-    const text = await navigator.clipboard.readText();
-    if (text) setUrl(text);
-  };
-
-  return (
-    <BasePage
-      title={t("Profiles")}
-      header={
-        <Box sx={{ mt: 1, display: "flex", alignItems: "center", gap: 1 }}>
-          <IconButton
-            size="small"
-            color="inherit"
-            title={t("Update All Profiles")}
-            onClick={onUpdateAll}
-          >
-            <RefreshRounded />
-          </IconButton>
-
-          <IconButton
-            size="small"
-            color="inherit"
-            title={t("View Runtime Config")}
-            onClick={() => configRef.current?.open()}
-          >
-            <TextSnippetOutlined />
-          </IconButton>
-
-          <IconButton
-            size="small"
-            color="primary"
-            title={t("Reactivate Profiles")}
-            onClick={onEnhance}
-          >
-            <LocalFireDepartmentRounded />
-          </IconButton>
-        </Box>
-      }
-    >
-      <Stack direction="row" spacing={1} sx={{ mb: 2 }}>
-        <TextField
-          hiddenLabel
-          fullWidth
-          size="small"
-          value={url}
-          variant="outlined"
-          autoComplete="off"
-          spellCheck="false"
-          onChange={(e) => setUrl(e.target.value)}
-          sx={{ input: { py: 0.65, px: 1.25 } }}
-          placeholder={t("Profile URL")}
-          InputProps={{
-            sx: { pr: 1 },
-            endAdornment: !url ? (
-              <IconButton
-                size="small"
-                sx={{ p: 0.5 }}
-                title={t("Paste")}
-                onClick={onCopyLink}
-              >
-                <ContentCopyRounded fontSize="inherit" />
-              </IconButton>
-            ) : (
-              <IconButton
-                size="small"
-                sx={{ p: 0.5 }}
-                title={t("Clear")}
-                onClick={() => setUrl("")}
-              >
-                <ClearRounded fontSize="inherit" />
-              </IconButton>
-            ),
-          }}
-        />
-        <Button
-          disabled={!url || disabled}
-          variant="contained"
-          size="small"
-          onClick={onImport}
-        >
-          {t("Import")}
-        </Button>
-        <Button
-          variant="contained"
-          size="small"
-          onClick={() => viewerRef.current?.create()}
-        >
-          {t("New")}
-        </Button>
-      </Stack>
-
-      <Box sx={{ mb: 4.5 }}>
-        <Grid container spacing={{ xs: 2, lg: 3 }}>
-          {regularItems.map((item) => (
-            <Grid item xs={12} sm={6} md={4} lg={3} key={item.file}>
-              <ProfileItem
-                selected={profiles.current === item.uid}
-                activating={activating === item.uid}
-                itemData={item}
-                onSelect={(f) => onSelect(item.uid, f)}
-                onEdit={() => viewerRef.current?.edit(item)}
-              />
-            </Grid>
-          ))}
-        </Grid>
-      </Box>
-
-      {enhanceItems.length > 0 && (
-        <Grid container spacing={{ xs: 2, lg: 3 }}>
-          {enhanceItems.map((item) => (
-            <Grid item xs={12} sm={6} md={4} lg={3} key={item.file}>
-              <ProfileMore
-                selected={!!chain.includes(item.uid)}
-                itemData={item}
-                enableNum={chain.length || 0}
-                logInfo={chainLogs[item.uid]}
-                onEnable={() => onEnable(item.uid)}
-                onDisable={() => onDisable(item.uid)}
-                onDelete={() => onDelete(item.uid)}
-                onMoveTop={() => onMoveTop(item.uid)}
-                onMoveEnd={() => onMoveEnd(item.uid)}
-                onEdit={() => viewerRef.current?.edit(item)}
-              />
-            </Grid>
-          ))}
-        </Grid>
-      )}
-
-      <ProfileViewer ref={viewerRef} onChange={() => mutateProfiles()} />
-      <ConfigViewer ref={configRef} />
-    </BasePage>
-  );
-};
-
-export default ProfilePage;
diff --git a/src/pages/proxies.tsx b/src/pages/proxies.tsx
deleted file mode 100644
index 39c777bdf6c3d82fc122172b0e277f6f931468d3..0000000000000000000000000000000000000000
--- a/src/pages/proxies.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import useSWR from "swr";
-import { useEffect, useMemo } from "react";
-import { useLockFn } from "ahooks";
-import { useTranslation } from "react-i18next";
-import { Box, Button, ButtonGroup, Paper } from "@mui/material";
-import {
-  closeAllConnections,
-  getClashConfig,
-  updateConfigs,
-} from "@/services/api";
-import { patchClashConfig } from "@/services/cmds";
-import { useVerge } from "@/hooks/use-verge";
-import { BasePage } from "@/components/base";
-import { ProxyGroups } from "@/components/proxy/proxy-groups";
-import { ProviderButton } from "@/components/proxy/provider-button";
-
-const ProxyPage = () => {
-  const { t } = useTranslation();
-
-  const { data: clashConfig, mutate: mutateClash } = useSWR(
-    "getClashConfig",
-    getClashConfig
-  );
-
-  const { verge } = useVerge();
-
-  const modeList = useMemo(() => {
-    if (verge?.clash_core === "clash-meta") {
-      return ["rule", "global", "direct"];
-    }
-    return ["rule", "global", "direct", "script"];
-  }, [verge?.clash_core]);
-
-  const curMode = clashConfig?.mode?.toLowerCase();
-
-  const onChangeMode = useLockFn(async (mode: string) => {
-    // 断开连接
-    if (mode !== curMode && verge?.auto_close_connection) {
-      closeAllConnections();
-    }
-    await updateConfigs({ mode });
-    await patchClashConfig({ mode });
-    mutateClash();
-  });
-
-  useEffect(() => {
-    if (curMode && !modeList.includes(curMode)) {
-      onChangeMode("rule");
-    }
-  }, [curMode]);
-
-  return (
-    <BasePage
-      contentStyle={{ height: "100%" }}
-      title={t("Proxy Groups")}
-      header={
-        <Box display="flex" alignItems="center" gap={1}>
-          <ProviderButton />
-
-          <ButtonGroup size="small">
-            {modeList.map((mode) => (
-              <Button
-                key={mode}
-                variant={mode === curMode ? "contained" : "outlined"}
-                onClick={() => onChangeMode(mode)}
-                sx={{ textTransform: "capitalize" }}
-              >
-                {t(mode)}
-              </Button>
-            ))}
-          </ButtonGroup>
-        </Box>
-      }
-    >
-      <Paper
-        sx={{
-          borderRadius: 1,
-          boxShadow: 2,
-          height: "100%",
-          boxSizing: "border-box",
-          py: 1,
-        }}
-      >
-        <ProxyGroups mode={curMode!} />
-      </Paper>
-    </BasePage>
-  );
-};
-
-export default ProxyPage;
diff --git a/src/pages/rules.tsx b/src/pages/rules.tsx
deleted file mode 100644
index 86cbdfa9d6f8f3e7f1f911f9d66dd65d2a5d006d..0000000000000000000000000000000000000000
--- a/src/pages/rules.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import useSWR from "swr";
-import { useState, useMemo } from "react";
-import { useTranslation } from "react-i18next";
-import { Virtuoso } from "react-virtuoso";
-import { Box, Paper, TextField } from "@mui/material";
-import { getRules } from "@/services/api";
-import { BaseEmpty, BasePage } from "@/components/base";
-import RuleItem from "@/components/rule/rule-item";
-
-const RulesPage = () => {
-  const { t } = useTranslation();
-  const { data = [] } = useSWR("getRules", getRules);
-
-  const [filterText, setFilterText] = useState("");
-
-  const rules = useMemo(() => {
-    return data.filter((each) => each.payload.includes(filterText));
-  }, [data, filterText]);
-
-  return (
-    <BasePage title={t("Rules")} contentStyle={{ height: "100%" }}>
-      <Paper sx={{ boxSizing: "border-box", boxShadow: 2, height: "100%" }}>
-        <Box
-          sx={{
-            pt: 1,
-            mb: 0.5,
-            mx: "12px",
-            height: "36px",
-            display: "flex",
-            alignItems: "center",
-          }}
-        >
-          <TextField
-            hiddenLabel
-            fullWidth
-            size="small"
-            autoComplete="off"
-            variant="outlined"
-            spellCheck="false"
-            placeholder={t("Filter conditions")}
-            value={filterText}
-            onChange={(e) => setFilterText(e.target.value)}
-            sx={{ input: { py: 0.65, px: 1.25 } }}
-          />
-        </Box>
-
-        <Box height="calc(100% - 50px)">
-          {rules.length > 0 ? (
-            <Virtuoso
-              data={rules}
-              itemContent={(index, item) => (
-                <RuleItem index={index + 1} value={item} />
-              )}
-              followOutput={"smooth"}
-            />
-          ) : (
-            <BaseEmpty text="No Rules" />
-          )}
-        </Box>
-      </Paper>
-    </BasePage>
-  );
-};
-
-export default RulesPage;
diff --git a/src/pages/settings.tsx b/src/pages/settings.tsx
deleted file mode 100644
index 039513b399177628aeb9a08465175f9a1a3277ef..0000000000000000000000000000000000000000
--- a/src/pages/settings.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import { IconButton, Paper } from "@mui/material";
-import { useLockFn } from "ahooks";
-import { useTranslation } from "react-i18next";
-import { BasePage, Notice } from "@/components/base";
-import { GitHub } from "@mui/icons-material";
-import { openWebUrl } from "@/services/cmds";
-import SettingVerge from "@/components/setting/setting-verge";
-import SettingClash from "@/components/setting/setting-clash";
-import SettingSystem from "@/components/setting/setting-system";
-
-const SettingPage = () => {
-  const { t } = useTranslation();
-
-  const onError = (err: any) => {
-    Notice.error(err?.message || err.toString());
-  };
-
-  const toGithubRepo = useLockFn(() => {
-    return openWebUrl("https://github.com/zzzgydi/clash-verge");
-  });
-
-  return (
-    <BasePage
-      title={t("Settings")}
-      header={
-        <IconButton
-          size="small"
-          color="inherit"
-          title="@zzzgydi/clash-verge"
-          onClick={toGithubRepo}
-        >
-          <GitHub fontSize="inherit" />
-        </IconButton>
-      }
-    >
-      <Paper sx={{ borderRadius: 1, boxShadow: 2, mb: 3 }}>
-        <SettingClash onError={onError} />
-      </Paper>
-
-      <Paper sx={{ borderRadius: 1, boxShadow: 2, mb: 3 }}>
-        <SettingSystem onError={onError} />
-      </Paper>
-
-      <Paper sx={{ borderRadius: 1, boxShadow: 2 }}>
-        <SettingVerge onError={onError} />
-      </Paper>
-    </BasePage>
-  );
-};
-
-export default SettingPage;
diff --git a/src/services/api.ts b/src/services/api.ts
deleted file mode 100644
index c9ded0790ba2da71bdc64321bbd46de4b83c9a15..0000000000000000000000000000000000000000
--- a/src/services/api.ts
+++ /dev/null
@@ -1,193 +0,0 @@
-import axios, { AxiosInstance } from "axios";
-import { getClashInfo } from "./cmds";
-
-let axiosIns: AxiosInstance = null!;
-
-/// initialize some information
-/// enable force update axiosIns
-export const getAxios = async (force: boolean = false) => {
-  if (axiosIns && !force) return axiosIns;
-
-  let server = "";
-  let secret = "";
-
-  try {
-    const info = await getClashInfo();
-
-    if (info?.server) {
-      server = info.server;
-
-      // compatible width `external-controller`
-      if (server.startsWith(":")) server = `127.0.0.1${server}`;
-      else if (/^\d+$/.test(server)) server = `127.0.0.1:${server}`;
-    }
-    if (info?.secret) secret = info?.secret;
-  } catch {}
-
-  axiosIns = axios.create({
-    baseURL: `http://${server}`,
-    headers: secret ? { Authorization: `Bearer ${secret}` } : {},
-    timeout: 15000,
-  });
-  axiosIns.interceptors.response.use((r) => r.data);
-  return axiosIns;
-};
-
-/// Get Version
-export const getVersion = async () => {
-  const instance = await getAxios();
-  return instance.get("/version") as Promise<{
-    premium: boolean;
-    meta?: boolean;
-    version: string;
-  }>;
-};
-
-/// Get current base configs
-export const getClashConfig = async () => {
-  const instance = await getAxios();
-  return instance.get("/configs") as Promise<IConfigData>;
-};
-
-/// Update current configs
-export const updateConfigs = async (config: Partial<IConfigData>) => {
-  const instance = await getAxios();
-  return instance.patch("/configs", config);
-};
-
-/// Get current rules
-export const getRules = async () => {
-  const instance = await getAxios();
-  const response = await instance.get<any, any>("/rules");
-  return response?.rules as IRuleItem[];
-};
-
-/// Get Proxy delay
-export const getProxyDelay = async (name: string, url?: string) => {
-  const params = {
-    timeout: 10000,
-    url: url || "http://www.gstatic.com/generate_204",
-  };
-  const instance = await getAxios();
-  const result = await instance.get(
-    `/proxies/${encodeURIComponent(name)}/delay`,
-    { params }
-  );
-  return result as any as { delay: number };
-};
-
-/// Update the Proxy Choose
-export const updateProxy = async (group: string, proxy: string) => {
-  const instance = await getAxios();
-  return instance.put(`/proxies/${encodeURIComponent(group)}`, { name: proxy });
-};
-
-// get proxy
-export const getProxiesInner = async () => {
-  const instance = await getAxios();
-  const response = await instance.get<any, any>("/proxies");
-  return (response?.proxies || {}) as Record<string, IProxyItem>;
-};
-
-/// Get the Proxy information
-export const getProxies = async () => {
-  const [proxyRecord, providerRecord] = await Promise.all([
-    getProxiesInner(),
-    getProviders(),
-  ]);
-
-  // provider name map
-  const providerMap = Object.fromEntries(
-    Object.entries(providerRecord).flatMap(([provider, item]) =>
-      item.proxies.map((p) => [p.name, { ...p, provider }])
-    )
-  );
-
-  // compatible with proxy-providers
-  const generateItem = (name: string) => {
-    if (proxyRecord[name]) return proxyRecord[name];
-    if (providerMap[name]) return providerMap[name];
-    return { name, type: "unknown", udp: false, history: [] };
-  };
-
-  const { GLOBAL: global, DIRECT: direct, REJECT: reject } = proxyRecord;
-
-  let groups: IProxyGroupItem[] = [];
-
-  if (global?.all) {
-    groups = global.all
-      .filter((name) => proxyRecord[name]?.all)
-      .map((name) => proxyRecord[name])
-      .map((each) => ({
-        ...each,
-        all: each.all!.map((item) => generateItem(item)),
-      }));
-  } else {
-    groups = Object.values(proxyRecord)
-      .filter((each) => each.name !== "GLOBAL" && each.all)
-      .map((each) => ({
-        ...each,
-        all: each.all!.map((item) => generateItem(item)),
-      }))
-      .sort((a, b) => b.name.localeCompare(a.name));
-  }
-
-  const proxies = [direct, reject].concat(
-    Object.values(proxyRecord).filter(
-      (p) => !p.all?.length && p.name !== "DIRECT" && p.name !== "REJECT"
-    )
-  );
-
-  const _global: IProxyGroupItem = {
-    ...global,
-    all: global?.all?.map((item) => generateItem(item)) || [],
-  };
-
-  return { global: _global, direct, groups, records: proxyRecord, proxies };
-};
-
-// get proxy providers
-export const getProviders = async () => {
-  const instance = await getAxios();
-  const response = await instance.get<any, any>("/providers/proxies");
-
-  const providers = (response.providers || {}) as Record<string, IProviderItem>;
-
-  return Object.fromEntries(
-    Object.entries(providers).filter(([key, item]) => {
-      const type = item.vehicleType.toLowerCase();
-      return type === "http" || type === "file";
-    })
-  );
-};
-
-// proxy providers health check
-export const providerHealthCheck = async (name: string) => {
-  const instance = await getAxios();
-  return instance.get(
-    `/providers/proxies/${encodeURIComponent(name)}/healthcheck`
-  );
-};
-
-export const providerUpdate = async (name: string) => {
-  const instance = await getAxios();
-  return instance.put(`/providers/proxies/${encodeURIComponent(name)}`);
-};
-
-export const getConnections = async () => {
-  const instance = await getAxios();
-  const result = await instance.get("/connections");
-  return result as any as IConnections;
-};
-
-// Close specific connection
-export const deleteConnection = async (id: string) => {
-  const instance = await getAxios();
-  await instance.delete<any, any>(`/connections/${encodeURIComponent(id)}`);
-};
-
-// Close all connections
-export const closeAllConnections = async () => {
-  const instance = await getAxios();
-  await instance.delete<any, any>(`/connections`);
-};
diff --git a/src/services/cmds.ts b/src/services/cmds.ts
deleted file mode 100644
index 02ee72a6dba8476e5f73f315317dd99aa9892719..0000000000000000000000000000000000000000
--- a/src/services/cmds.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import dayjs from "dayjs";
-import { invoke } from "@tauri-apps/api/tauri";
-import { Notice } from "@/components/base";
-
-export async function getClashLogs() {
-  const regex = /time="(.+?)"\s+level=(.+?)\s+msg="(.+?)"/;
-  const newRegex = /(.+?)\s+(.+?)\s+(.+)/;
-  const logs = await invoke<string[]>("get_clash_logs");
-
-  return logs
-    .map((log) => {
-      const result = log.match(regex);
-      if (result) {
-        const [_, _time, type, payload] = result;
-        const time = dayjs(_time).format("MM-DD HH:mm:ss");
-        return { time, type, payload };
-      }
-
-      const result2 = log.match(newRegex);
-      if (result2) {
-        const [_, time, type, payload] = result2;
-        return { time, type, payload };
-      }
-      return null;
-    })
-    .filter(Boolean) as ILogItem[];
-}
-
-export async function getProfiles() {
-  return invoke<IProfilesConfig>("get_profiles");
-}
-
-export async function enhanceProfiles() {
-  return invoke<void>("enhance_profiles");
-}
-
-export async function patchProfilesConfig(profiles: IProfilesConfig) {
-  return invoke<void>("patch_profiles_config", { profiles });
-}
-
-export async function createProfile(
-  item: Partial<IProfileItem>,
-  fileData?: string | null
-) {
-  return invoke<void>("create_profile", { item, fileData });
-}
-
-export async function viewProfile(index: string) {
-  return invoke<void>("view_profile", { index });
-}
-
-export async function readProfileFile(index: string) {
-  return invoke<string>("read_profile_file", { index });
-}
-
-export async function saveProfileFile(index: string, fileData: string) {
-  return invoke<void>("save_profile_file", { index, fileData });
-}
-
-export async function importProfile(url: string) {
-  return invoke<void>("import_profile", {
-    url,
-    option: { with_proxy: true },
-  });
-}
-
-export async function updateProfile(index: string, option?: IProfileOption) {
-  return invoke<void>("update_profile", { index, option });
-}
-
-export async function deleteProfile(index: string) {
-  return invoke<void>("delete_profile", { index });
-}
-
-export async function patchProfile(
-  index: string,
-  profile: Partial<IProfileItem>
-) {
-  return invoke<void>("patch_profile", { index, profile });
-}
-
-export async function getClashInfo() {
-  return invoke<IClashInfo | null>("get_clash_info");
-}
-
-export async function getRuntimeConfig() {
-  return invoke<any | null>("get_runtime_config");
-}
-
-export async function getRuntimeYaml() {
-  return invoke<string | null>("get_runtime_yaml");
-}
-
-export async function getRuntimeExists() {
-  return invoke<string[]>("get_runtime_exists");
-}
-
-export async function getRuntimeLogs() {
-  return invoke<Record<string, [string, string][]>>("get_runtime_logs");
-}
-
-export async function patchClashConfig(payload: Partial<IConfigData>) {
-  return invoke<void>("patch_clash_config", { payload });
-}
-
-export async function getVergeConfig() {
-  return invoke<IVergeConfig>("get_verge_config");
-}
-
-export async function patchVergeConfig(payload: IVergeConfig) {
-  return invoke<void>("patch_verge_config", { payload });
-}
-
-export async function getSystemProxy() {
-  return invoke<{
-    enable: boolean;
-    server: string;
-    bypass: string;
-  }>("get_sys_proxy");
-}
-
-export async function changeClashCore(clashCore: string) {
-  return invoke<any>("change_clash_core", { clashCore });
-}
-
-export async function restartSidecar() {
-  return invoke<void>("restart_sidecar");
-}
-
-export async function grantPermission(core: string) {
-  return invoke<void>("grant_permission", { core });
-}
-
-export async function openAppDir() {
-  return invoke<void>("open_app_dir").catch((err) =>
-    Notice.error(err?.message || err.toString(), 1500)
-  );
-}
-
-export async function openCoreDir() {
-  return invoke<void>("open_core_dir").catch((err) =>
-    Notice.error(err?.message || err.toString(), 1500)
-  );
-}
-
-export async function openLogsDir() {
-  return invoke<void>("open_logs_dir").catch((err) =>
-    Notice.error(err?.message || err.toString(), 1500)
-  );
-}
-
-export async function openWebUrl(url: string) {
-  return invoke<void>("open_web_url", { url });
-}
-
-export async function cmdGetProxyDelay(name: string, url?: string) {
-  name = encodeURIComponent(name);
-  return invoke<{ delay: number }>("clash_api_get_proxy_delay", { name, url });
-}
-
-/// service mode
-
-export async function checkService() {
-  try {
-    const result = await invoke<any>("check_service");
-    if (result?.code === 0) return "active";
-    if (result?.code === 400) return "installed";
-    return "unknown";
-  } catch (err: any) {
-    return "uninstall";
-  }
-}
-
-export async function installService() {
-  return invoke<void>("install_service");
-}
-
-export async function uninstallService() {
-  return invoke<void>("uninstall_service");
-}
diff --git a/src/services/delay.ts b/src/services/delay.ts
deleted file mode 100644
index 9b18776083570964f1b740384abb3c18e9fef3bb..0000000000000000000000000000000000000000
--- a/src/services/delay.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-import { cmdGetProxyDelay } from "./cmds";
-
-const hashKey = (name: string, group: string) => `${group ?? ""}::${name}`;
-
-class DelayManager {
-  private cache = new Map<string, [number, number]>();
-  private urlMap = new Map<string, string>();
-
-  // 每个item的监听
-  private listenerMap = new Map<string, (time: number) => void>();
-
-  // 每个分组的监听
-  private groupListenerMap = new Map<string, () => void>();
-
-  setUrl(group: string, url: string) {
-    this.urlMap.set(group, url);
-  }
-
-  getUrl(group: string) {
-    return this.urlMap.get(group);
-  }
-
-  setListener(name: string, group: string, listener: (time: number) => void) {
-    const key = hashKey(name, group);
-    this.listenerMap.set(key, listener);
-  }
-
-  removeListener(name: string, group: string) {
-    const key = hashKey(name, group);
-    this.listenerMap.delete(key);
-  }
-
-  setGroupListener(group: string, listener: () => void) {
-    this.groupListenerMap.set(group, listener);
-  }
-
-  removeGroupListener(group: string) {
-    this.groupListenerMap.delete(group);
-  }
-
-  setDelay(name: string, group: string, delay: number) {
-    const key = hashKey(name, group);
-    this.cache.set(key, [Date.now(), delay]);
-    this.listenerMap.get(key)?.(delay);
-    this.groupListenerMap.get(group)?.();
-  }
-
-  getDelay(name: string, group: string) {
-    if (!name) return -1;
-
-    const result = this.cache.get(hashKey(name, group));
-    if (result && Date.now() - result[0] <= 18e5) {
-      return result[1];
-    }
-    return -1;
-  }
-
-  /// 暂时修复provider的节点延迟排序的问题
-  getDelayFix(proxy: IProxyItem, group: string) {
-    if (!proxy.provider) {
-      const delay = this.getDelay(proxy.name, group);
-      if (delay >= 0 || delay === -2) return delay;
-    }
-
-    if (proxy.history.length > 0) {
-      // 0ms以error显示
-      return proxy.history[proxy.history.length - 1].delay || 1e6;
-    }
-    return -1;
-  }
-
-  async checkDelay(name: string, group: string) {
-    let delay = -1;
-
-    try {
-      const url = this.getUrl(group);
-      const result = await cmdGetProxyDelay(name, url);
-      delay = result.delay;
-    } catch {
-      delay = 1e6; // error
-    }
-
-    this.setDelay(name, group, delay);
-    return delay;
-  }
-
-  async checkListDelay(nameList: string[], group: string, concurrency = 36) {
-    const names = nameList.filter(Boolean);
-    // 设置正在延迟测试中
-    names.forEach((name) => this.setDelay(name, group, -2));
-
-    let total = names.length;
-    let current = 0;
-
-    return new Promise((resolve) => {
-      const help = async (): Promise<void> => {
-        if (current >= concurrency) return;
-        const task = names.shift();
-        if (!task) return;
-        current += 1;
-        await this.checkDelay(task, group);
-        current -= 1;
-        total -= 1;
-        if (total <= 0) resolve(null);
-        else return help();
-      };
-      for (let i = 0; i < concurrency; ++i) help();
-    });
-  }
-
-  formatDelay(delay: number) {
-    if (delay < 0) return "-";
-    if (delay > 1e5) return "Error";
-    if (delay >= 10000) return "Timeout"; // 10s
-    return `${delay}`;
-  }
-
-  formatDelayColor(delay: number) {
-    if (delay <= 0) return "text.secondary";
-    if (delay >= 10000) return "error.main";
-    if (delay > 500) return "warning.main";
-    if (delay > 100) return "text.secondary";
-    return "success.main";
-  }
-}
-
-export default new DelayManager();
diff --git a/src/services/i18n.ts b/src/services/i18n.ts
deleted file mode 100644
index 8d4c14b84e1d233683b64c0f5c404244fcf3fe52..0000000000000000000000000000000000000000
--- a/src/services/i18n.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import i18n from "i18next";
-import { initReactI18next } from "react-i18next";
-import en from "@/locales/en.json";
-import ru from "@/locales/ru.json";
-import zh from "@/locales/zh.json";
-
-const resources = {
-  en: { translation: en },
-  ru: { translation: ru },
-  zh: { translation: zh },
-};
-
-i18n.use(initReactI18next).init({
-  resources,
-  lng: "en",
-  interpolation: {
-    escapeValue: false,
-  },
-});
diff --git a/src/services/states.ts b/src/services/states.ts
deleted file mode 100644
index 6ac6edcf8f9daa36ea65e2d1f49b75634de5fb19..0000000000000000000000000000000000000000
--- a/src/services/states.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-import { atom } from "recoil";
-
-export const atomThemeMode = atom<"light" | "dark">({
-  key: "atomThemeMode",
-  default: "light",
-});
-
-export const atomLogData = atom<ILogItem[]>({
-  key: "atomLogData",
-  default: [],
-});
-
-export const atomEnableLog = atom<boolean>({
-  key: "atomEnableLog",
-  effects: [
-    ({ setSelf, onSet }) => {
-      const key = "enable-log";
-
-      try {
-        setSelf(localStorage.getItem(key) !== "false");
-      } catch {}
-
-      onSet((newValue, _, isReset) => {
-        try {
-          if (isReset) {
-            localStorage.removeItem(key);
-          } else {
-            localStorage.setItem(key, newValue.toString());
-          }
-        } catch {}
-      });
-    },
-  ],
-});
-
-interface IConnectionSetting {
-  layout: "table" | "list";
-}
-
-export const atomConnectionSetting = atom<IConnectionSetting>({
-  key: "atomConnectionSetting",
-  effects: [
-    ({ setSelf, onSet }) => {
-      const key = "connections-setting";
-
-      try {
-        const value = localStorage.getItem(key);
-        const data = value == null ? { layout: "table" } : JSON.parse(value);
-        setSelf(data);
-      } catch {
-        setSelf({ layout: "table" });
-      }
-
-      onSet((newValue) => {
-        try {
-          localStorage.setItem(key, JSON.stringify(newValue));
-        } catch {}
-      });
-    },
-  ],
-});
-
-// save the state of each profile item loading
-export const atomLoadingCache = atom<Record<string, boolean>>({
-  key: "atomLoadingCache",
-  default: {},
-});
-
-// save update state
-export const atomUpdateState = atom<boolean>({
-  key: "atomUpdateState",
-  default: false,
-});
diff --git a/src/services/types.d.ts b/src/services/types.d.ts
deleted file mode 100644
index 3fe2175e736e82aeb1684e3fb8d6b36d014c95dd..0000000000000000000000000000000000000000
--- a/src/services/types.d.ts
+++ /dev/null
@@ -1,263 +0,0 @@
-type Platform =
-  | "aix"
-  | "android"
-  | "darwin"
-  | "freebsd"
-  | "haiku"
-  | "linux"
-  | "openbsd"
-  | "sunos"
-  | "win32"
-  | "cygwin"
-  | "netbsd";
-
-/**
- * defines in `vite.config.ts`
- */
-declare const WIN_PORTABLE: boolean;
-declare const OS_PLATFORM: Platform;
-
-/**
- * Some interface for clash api
- */
-interface IConfigData {
-  port: number;
-  mode: string;
-  ipv6: boolean;
-  "socket-port": number;
-  "allow-lan": boolean;
-  "log-level": string;
-  "mixed-port": number;
-  "redir-port": number;
-  "socks-port": number;
-  "tproxy-port": number;
-  "external-controller": string;
-  secret: string;
-}
-
-interface IRuleItem {
-  type: string;
-  payload: string;
-  proxy: string;
-}
-
-interface IProxyItem {
-  name: string;
-  type: string;
-  udp: boolean;
-  history: {
-    time: string;
-    delay: number;
-  }[];
-  all?: string[];
-  now?: string;
-  provider?: string; // 记录是否来自provider
-}
-
-type IProxyGroupItem = Omit<IProxyItem, "all"> & {
-  all: IProxyItem[];
-};
-
-interface IProviderItem {
-  name: string;
-  type: string;
-  proxies: IProxyItem[];
-  updatedAt: string;
-  vehicleType: string;
-}
-
-interface ITrafficItem {
-  up: number;
-  down: number;
-}
-
-interface ILogItem {
-  type: string;
-  time?: string;
-  payload: string;
-}
-
-interface IConnectionsItem {
-  id: string;
-  metadata: {
-    network: string;
-    type: string;
-    host: string;
-    sourceIP: string;
-    sourcePort: string;
-    destinationPort: string;
-    destinationIP?: string;
-    process?: string;
-    processPath?: string;
-  };
-  upload: number;
-  download: number;
-  start: string;
-  chains: string[];
-  rule: string;
-  rulePayload: string;
-  curUpload?: number; // upload speed, calculate at runtime
-  curDownload?: number; // download speed, calculate at runtime
-}
-
-interface IConnections {
-  downloadTotal: number;
-  uploadTotal: number;
-  connections: IConnectionsItem[];
-}
-
-/**
- * Some interface for command
- */
-
-interface IClashInfo {
-  // status: string;
-  port?: number; // clash mixed port
-  server?: string; // external-controller
-  secret?: string;
-}
-
-interface IProfileItem {
-  uid: string;
-  type?: "local" | "remote" | "merge" | "script";
-  name?: string;
-  desc?: string;
-  file?: string;
-  url?: string;
-  updated?: number;
-  selected?: {
-    name?: string;
-    now?: string;
-  }[];
-  extra?: {
-    upload: number;
-    download: number;
-    total: number;
-    expire: number;
-  };
-  option?: IProfileOption;
-}
-
-interface IProfileOption {
-  user_agent?: string;
-  with_proxy?: boolean;
-  self_proxy?: boolean;
-  update_interval?: number;
-}
-
-interface IProfilesConfig {
-  current?: string;
-  chain?: string[];
-  valid?: string[];
-  items?: IProfileItem[];
-}
-
-interface IVergeConfig {
-  app_log_level?: "trace" | "debug" | "info" | "warn" | "error" | string;
-  language?: string;
-  clash_core?: string;
-  theme_mode?: "light" | "dark" | "system";
-  theme_blur?: boolean;
-  traffic_graph?: boolean;
-  enable_memory_usage?: boolean;
-  enable_tun_mode?: boolean;
-  enable_auto_launch?: boolean;
-  enable_service_mode?: boolean;
-  enable_silent_start?: boolean;
-  enable_system_proxy?: boolean;
-  enable_proxy_guard?: boolean;
-  proxy_guard_duration?: number;
-  system_proxy_bypass?: string;
-  web_ui_list?: string[];
-  hotkeys?: string[];
-  theme_setting?: {
-    primary_color?: string;
-    secondary_color?: string;
-    primary_text?: string;
-    secondary_text?: string;
-    info_color?: string;
-    error_color?: string;
-    warning_color?: string;
-    success_color?: string;
-    font_family?: string;
-    css_injection?: string;
-  };
-  auto_close_connection?: boolean;
-  default_latency_test?: string;
-  enable_clash_fields?: boolean;
-  enable_builtin_enhanced?: boolean;
-  auto_log_clean?: 0 | 1 | 2 | 3;
-  proxy_layout_column?: number;
-}
-
-type IClashConfigValue = any;
-
-interface IProfileMerge {
-  // clash config fields (default supports)
-  rules?: IClashConfigValue;
-  proxies?: IClashConfigValue;
-  "proxy-groups"?: IClashConfigValue;
-  "proxy-providers"?: IClashConfigValue;
-  "rule-providers"?: IClashConfigValue;
-  // clash config fields (use flag)
-  tun?: IClashConfigValue;
-  dns?: IClashConfigValue;
-  hosts?: IClashConfigValue;
-  script?: IClashConfigValue;
-  profile?: IClashConfigValue;
-  payload?: IClashConfigValue;
-  "interface-name"?: IClashConfigValue;
-  "routing-mark"?: IClashConfigValue;
-  // functional fields
-  use?: string[];
-  "prepend-rules"?: any[];
-  "append-rules"?: any[];
-  "prepend-proxies"?: any[];
-  "append-proxies"?: any[];
-  "prepend-proxy-groups"?: any[];
-  "append-proxy-groups"?: any[];
-  // fix
-  ebpf?: any;
-  experimental?: any;
-  iptables?: any;
-  sniffer?: any;
-  authentication?: any;
-  "bind-address"?: any;
-  "external-ui"?: any;
-  "auto-redir"?: any;
-  "socks-port"?: any;
-  "redir-port"?: any;
-  "tproxy-port"?: any;
-  "geodata-mode"?: any;
-  "tcp-concurrent"?: any;
-}
-
-// partial of the clash config
-type IProfileData = Partial<{
-  rules: any[];
-  proxies: any[];
-  "proxy-groups": any[];
-  "proxy-providers": any[];
-  "rule-providers": any[];
-
-  [k: string]: any;
-}>;
-
-interface IChainItem {
-  item: IProfileItem;
-  merge?: IProfileMerge;
-  script?: string;
-}
-
-interface IEnhancedPayload {
-  chain: IChainItem[];
-  valid: string[];
-  current: IProfileData;
-  callback: string;
-}
-
-interface IEnhancedResult {
-  data: IProfileData;
-  status: string;
-  error?: string;
-}
diff --git a/src/utils/clash-fields.ts b/src/utils/clash-fields.ts
deleted file mode 100644
index 86e1b60689a37f169035588e3e0b4033c146bfda..0000000000000000000000000000000000000000
--- a/src/utils/clash-fields.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-export const HANDLE_FIELDS = [
-  "mode",
-  "port",
-  "socks-port",
-  "mixed-port",
-  "allow-lan",
-  "log-level",
-  "ipv6",
-  "secret",
-  "external-controller",
-];
-
-export const DEFAULT_FIELDS = [
-  "proxies",
-  "proxy-groups",
-  "proxy-providers",
-  "rules",
-  "rule-providers",
-] as const;
-
-export const OTHERS_FIELDS = [
-  "dns",
-  "tun",
-  "ebpf",
-  "hosts",
-  "script",
-  "profile",
-  "payload",
-  "tunnels",
-  "auto-redir",
-  "experimental",
-  "interface-name",
-  "routing-mark",
-  "redir-port",
-  "tproxy-port",
-  "iptables",
-  "external-ui",
-  "bind-address",
-  "authentication",
-  "tls", // meta
-  "sniffer", // meta
-  "geox-url", // meta
-  "listeners", // meta
-  "sub-rules", // meta
-  "geodata-mode", // meta
-  "unified-delay", // meta
-  "tcp-concurrent", // meta
-  "enable-process", // meta
-  "find-process-mode", // meta
-  "external-controller-tls", // meta
-  "global-client-fingerprint", // meta
-] as const;
diff --git a/src/utils/get-system.ts b/src/utils/get-system.ts
deleted file mode 100644
index 891770329f6420d78f448199cd5751d796931127..0000000000000000000000000000000000000000
--- a/src/utils/get-system.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-// get the system os
-// according to UA
-export default function getSystem() {
-  const ua = navigator.userAgent;
-  const platform = OS_PLATFORM;
-
-  if (ua.includes("Mac OS X") || platform === "darwin") return "macos";
-
-  if (/win64|win32/i.test(ua) || platform === "win32") return "windows";
-
-  if (/linux/i.test(ua)) return "linux";
-
-  return "unknown";
-}
diff --git a/src/utils/ignore-case.ts b/src/utils/ignore-case.ts
deleted file mode 100644
index f6533f6caa5d826d821e4ffca084c10b6a52b9de..0000000000000000000000000000000000000000
--- a/src/utils/ignore-case.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-// Deep copy and change all keys to lowercase
-type TData = Record<string, any>;
-
-export default function ignoreCase(data: TData): TData {
-  if (!data) return {};
-
-  const newData = {} as TData;
-
-  Object.entries(data).forEach(([key, value]) => {
-    newData[key.toLowerCase()] = JSON.parse(JSON.stringify(value));
-  });
-
-  return newData;
-}
diff --git a/src/utils/noop.ts b/src/utils/noop.ts
deleted file mode 100644
index ca6a744710d3ca4435f577fa0dfff4550d0f893f..0000000000000000000000000000000000000000
--- a/src/utils/noop.ts
+++ /dev/null
@@ -1 +0,0 @@
-export default function noop() {}
diff --git a/src/utils/parse-hotkey.ts b/src/utils/parse-hotkey.ts
deleted file mode 100644
index 864ef4f8923001550d250d57615608e105277613..0000000000000000000000000000000000000000
--- a/src/utils/parse-hotkey.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-const KEY_MAP: Record<string, string> = {
-  '"': "'",
-  ":": ";",
-  "?": "/",
-  ">": ".",
-  "<": ",",
-  "{": "[",
-  "}": "]",
-  "|": "\\",
-  "!": "1",
-  "@": "2",
-  "#": "3",
-  $: "4",
-  "%": "5",
-  "^": "6",
-  "&": "7",
-  "*": "8",
-  "(": "9",
-  ")": "0",
-  "~": "`",
-};
-
-export const parseHotkey = (key: string) => {
-  let temp = key.toUpperCase();
-
-  if (temp.startsWith("ARROW")) {
-    temp = temp.slice(5);
-  } else if (temp.startsWith("DIGIT")) {
-    temp = temp.slice(5);
-  } else if (temp.startsWith("KEY")) {
-    temp = temp.slice(3);
-  } else if (temp.endsWith("LEFT")) {
-    temp = temp.slice(0, -4);
-  } else if (temp.endsWith("RIGHT")) {
-    temp = temp.slice(0, -5);
-  }
-
-  switch (temp) {
-    case "CONTROL":
-      return "CTRL";
-    case "META":
-      return "CMD";
-    case " ":
-      return "SPACE";
-    default:
-      return KEY_MAP[temp] || temp;
-  }
-};
diff --git a/src/utils/parse-traffic.ts b/src/utils/parse-traffic.ts
deleted file mode 100644
index 514d24fe2dc2c56b0c0f764876090bd93ff82df6..0000000000000000000000000000000000000000
--- a/src/utils/parse-traffic.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-const UNITS = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
-
-const parseTraffic = (num?: number) => {
-  if (typeof num !== "number") return ["NaN", ""];
-  if (num < 1000) return [`${Math.round(num)}`, "B"];
-  const exp = Math.min(Math.floor(Math.log2(num) / 10), UNITS.length - 1);
-  const dat = num / Math.pow(1024, exp);
-  const ret = dat >= 1000 ? dat.toFixed(0) : dat.toPrecision(3);
-  const unit = UNITS[exp];
-
-  return [ret, unit];
-};
-
-export default parseTraffic;
diff --git a/src/utils/truncate-str.ts b/src/utils/truncate-str.ts
deleted file mode 100644
index 491fa07aefa74235efbb71b638462d57588e31d3..0000000000000000000000000000000000000000
--- a/src/utils/truncate-str.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export const truncateStr = (str?: string, prefixLen = 16, maxLen = 56) => {
-  if (!str || str.length <= maxLen) return str;
-  return (
-    str.slice(0, prefixLen) + " ... " + str.slice(-(maxLen - prefixLen - 5))
-  );
-};
diff --git a/tsconfig.json b/tsconfig.json
deleted file mode 100644
index a285c97f2eae9d4c3196d23b860dec1f6d563c33..0000000000000000000000000000000000000000
--- a/tsconfig.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-  "compilerOptions": {
-    "baseUrl": ".",
-    "target": "ESNext",
-    "useDefineForClassFields": true,
-    "lib": ["DOM", "DOM.Iterable", "ESNext"],
-    "allowJs": false,
-    "skipLibCheck": false,
-    "esModuleInterop": false,
-    "allowSyntheticDefaultImports": true,
-    "strict": true,
-    "forceConsistentCasingInFileNames": true,
-    "module": "ESNext",
-    "moduleResolution": "Node",
-    "resolveJsonModule": true,
-    "isolatedModules": true,
-    "noEmit": true,
-    "jsx": "react-jsx",
-    "paths": {
-      "@/*": ["src/*"],
-      "@root/*": ["./*"]
-    }
-  },
-  "include": ["./src"]
-}
diff --git a/vite.config.ts b/vite.config.ts
deleted file mode 100644
index 0315d7692561a4c0edf95dc270e83916512aee72..0000000000000000000000000000000000000000
--- a/vite.config.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { defineConfig } from "vite";
-import path from "path";
-import svgr from "vite-plugin-svgr";
-import react from "@vitejs/plugin-react";
-import monaco from "vite-plugin-monaco-editor";
-
-// https://vitejs.dev/config/
-export default defineConfig({
-  root: "src",
-  server: { port: 3000 },
-  plugins: [
-    svgr(),
-    react(),
-    monaco({ languageWorkers: ["editorWorkerService", "typescript"] }),
-  ],
-  build: {
-    outDir: "../dist",
-    emptyOutDir: true,
-  },
-  resolve: {
-    alias: {
-      "@": path.resolve("./src"),
-      "@root": path.resolve("."),
-    },
-  },
-  define: {
-    OS_PLATFORM: `"${process.platform}"`,
-    WIN_PORTABLE: !!process.env.VITE_WIN_PORTABLE,
-  },
-});
diff --git a/yarn.lock b/yarn.lock
deleted file mode 100644
index 895c8bb0c238d4859f133091d60373d0745fb91d..0000000000000000000000000000000000000000
--- a/yarn.lock
+++ /dev/null
@@ -1,2348 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-"@actions/github@^5.0.3":
-  version "5.0.3"
-  resolved "https://registry.yarnpkg.com/@actions/github/-/github-5.0.3.tgz#b305765d6173962d113451ea324ff675aa674f35"
-  integrity sha512-myjA/pdLQfhUGLtRZC/J4L1RXOG4o6aYdiEq+zr5wVVKljzbFld+xv10k1FX6IkIJtNxbAq44BdwSNpQ015P0A==
-  dependencies:
-    "@actions/http-client" "^2.0.1"
-    "@octokit/core" "^3.6.0"
-    "@octokit/plugin-paginate-rest" "^2.17.0"
-    "@octokit/plugin-rest-endpoint-methods" "^5.13.0"
-
-"@actions/http-client@^2.0.1":
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-2.0.1.tgz#873f4ca98fe32f6839462a6f046332677322f99c"
-  integrity sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==
-  dependencies:
-    tunnel "^0.0.6"
-
-"@ampproject/remapping@^2.1.0":
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34"
-  integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==
-  dependencies:
-    "@jridgewell/trace-mapping" "^0.3.0"
-
-"@babel/code-frame@^7.0.0":
-  version "7.16.7"
-  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789"
-  integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==
-  dependencies:
-    "@babel/highlight" "^7.16.7"
-
-"@babel/code-frame@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
-  integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
-  dependencies:
-    "@babel/highlight" "^7.18.6"
-
-"@babel/compat-data@^7.18.8":
-  version "7.18.13"
-  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.13.tgz#6aff7b350a1e8c3e40b029e46cbe78e24a913483"
-  integrity sha512-5yUzC5LqyTFp2HLmDoxGQelcdYgSpP9xsnMWBphAscOdFrHSAVbLNzWiy32sVNDqJRDiJK6klfDnAgu6PAGSHw==
-
-"@babel/core@^7.18.10", "@babel/core@^7.18.5":
-  version "7.18.13"
-  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.13.tgz#9be8c44512751b05094a4d3ab05fc53a47ce00ac"
-  integrity sha512-ZisbOvRRusFktksHSG6pjj1CSvkPkcZq/KHD45LAkVP/oiHJkNBZWfpvlLmX8OtHDG8IuzsFlVRWo08w7Qxn0A==
-  dependencies:
-    "@ampproject/remapping" "^2.1.0"
-    "@babel/code-frame" "^7.18.6"
-    "@babel/generator" "^7.18.13"
-    "@babel/helper-compilation-targets" "^7.18.9"
-    "@babel/helper-module-transforms" "^7.18.9"
-    "@babel/helpers" "^7.18.9"
-    "@babel/parser" "^7.18.13"
-    "@babel/template" "^7.18.10"
-    "@babel/traverse" "^7.18.13"
-    "@babel/types" "^7.18.13"
-    convert-source-map "^1.7.0"
-    debug "^4.1.0"
-    gensync "^1.0.0-beta.2"
-    json5 "^2.2.1"
-    semver "^6.3.0"
-
-"@babel/generator@^7.18.13":
-  version "7.18.13"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.13.tgz#59550cbb9ae79b8def15587bdfbaa388c4abf212"
-  integrity sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ==
-  dependencies:
-    "@babel/types" "^7.18.13"
-    "@jridgewell/gen-mapping" "^0.3.2"
-    jsesc "^2.5.1"
-
-"@babel/helper-annotate-as-pure@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
-  integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-compilation-targets@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf"
-  integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==
-  dependencies:
-    "@babel/compat-data" "^7.18.8"
-    "@babel/helper-validator-option" "^7.18.6"
-    browserslist "^4.20.2"
-    semver "^6.3.0"
-
-"@babel/helper-environment-visitor@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
-  integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
-
-"@babel/helper-function-name@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0"
-  integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==
-  dependencies:
-    "@babel/template" "^7.18.6"
-    "@babel/types" "^7.18.9"
-
-"@babel/helper-hoist-variables@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
-  integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-module-imports@^7.16.7":
-  version "7.16.7"
-  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437"
-  integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==
-  dependencies:
-    "@babel/types" "^7.16.7"
-
-"@babel/helper-module-imports@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
-  integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-module-transforms@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz#5a1079c005135ed627442df31a42887e80fcb712"
-  integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==
-  dependencies:
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-module-imports" "^7.18.6"
-    "@babel/helper-simple-access" "^7.18.6"
-    "@babel/helper-split-export-declaration" "^7.18.6"
-    "@babel/helper-validator-identifier" "^7.18.6"
-    "@babel/template" "^7.18.6"
-    "@babel/traverse" "^7.18.9"
-    "@babel/types" "^7.18.9"
-
-"@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f"
-  integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==
-
-"@babel/helper-simple-access@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea"
-  integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-split-export-declaration@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
-  integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-string-parser@^7.18.10":
-  version "7.18.10"
-  resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56"
-  integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==
-
-"@babel/helper-validator-identifier@^7.16.7":
-  version "7.16.7"
-  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad"
-  integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
-
-"@babel/helper-validator-identifier@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
-  integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
-
-"@babel/helper-validator-option@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
-  integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==
-
-"@babel/helpers@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.9.tgz#4bef3b893f253a1eced04516824ede94dcfe7ff9"
-  integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==
-  dependencies:
-    "@babel/template" "^7.18.6"
-    "@babel/traverse" "^7.18.9"
-    "@babel/types" "^7.18.9"
-
-"@babel/highlight@^7.16.7":
-  version "7.16.10"
-  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88"
-  integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==
-  dependencies:
-    "@babel/helper-validator-identifier" "^7.16.7"
-    chalk "^2.0.0"
-    js-tokens "^4.0.0"
-
-"@babel/highlight@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
-  integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
-  dependencies:
-    "@babel/helper-validator-identifier" "^7.18.6"
-    chalk "^2.0.0"
-    js-tokens "^4.0.0"
-
-"@babel/parser@^7.18.10", "@babel/parser@^7.18.13":
-  version "7.18.13"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.13.tgz#5b2dd21cae4a2c5145f1fbd8ca103f9313d3b7e4"
-  integrity sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==
-
-"@babel/plugin-syntax-jsx@^7.17.12", "@babel/plugin-syntax-jsx@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0"
-  integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-react-jsx-development@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5"
-  integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==
-  dependencies:
-    "@babel/plugin-transform-react-jsx" "^7.18.6"
-
-"@babel/plugin-transform-react-jsx-self@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz#3849401bab7ae8ffa1e3e5687c94a753fc75bda7"
-  integrity sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-react-jsx-source@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.18.6.tgz#06e9ae8a14d2bc19ce6e3c447d842032a50598fc"
-  integrity sha512-utZmlASneDfdaMh0m/WausbjUjEdGrQJz0vFK93d7wD3xf5wBtX219+q6IlCNZeguIcxS2f/CvLZrlLSvSHQXw==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-react-jsx@^7.18.10", "@babel/plugin-transform-react-jsx@^7.18.6":
-  version "7.18.10"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.10.tgz#ea47b2c4197102c196cbd10db9b3bb20daa820f1"
-  integrity sha512-gCy7Iikrpu3IZjYZolFE4M1Sm+nrh1/6za2Ewj77Z+XirT4TsbJcvOFOyF+fRPwU6AKKK136CZxx6L8AbSFG6A==
-  dependencies:
-    "@babel/helper-annotate-as-pure" "^7.18.6"
-    "@babel/helper-module-imports" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.9"
-    "@babel/plugin-syntax-jsx" "^7.18.6"
-    "@babel/types" "^7.18.10"
-
-"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a"
-  integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==
-  dependencies:
-    regenerator-runtime "^0.13.4"
-
-"@babel/runtime@^7.14.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
-  version "7.17.8"
-  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2"
-  integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==
-  dependencies:
-    regenerator-runtime "^0.13.4"
-
-"@babel/runtime@^7.19.0":
-  version "7.20.1"
-  resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.20.1.tgz#1148bb33ab252b165a06698fde7576092a78b4a9"
-  integrity sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==
-  dependencies:
-    regenerator-runtime "^0.13.10"
-
-"@babel/template@^7.18.10", "@babel/template@^7.18.6":
-  version "7.18.10"
-  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
-  integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==
-  dependencies:
-    "@babel/code-frame" "^7.18.6"
-    "@babel/parser" "^7.18.10"
-    "@babel/types" "^7.18.10"
-
-"@babel/traverse@^7.18.13", "@babel/traverse@^7.18.9":
-  version "7.18.13"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.13.tgz#5ab59ef51a997b3f10c4587d648b9696b6cb1a68"
-  integrity sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==
-  dependencies:
-    "@babel/code-frame" "^7.18.6"
-    "@babel/generator" "^7.18.13"
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-function-name" "^7.18.9"
-    "@babel/helper-hoist-variables" "^7.18.6"
-    "@babel/helper-split-export-declaration" "^7.18.6"
-    "@babel/parser" "^7.18.13"
-    "@babel/types" "^7.18.13"
-    debug "^4.1.0"
-    globals "^11.1.0"
-
-"@babel/types@^7.16.7":
-  version "7.17.0"
-  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b"
-  integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==
-  dependencies:
-    "@babel/helper-validator-identifier" "^7.16.7"
-    to-fast-properties "^2.0.0"
-
-"@babel/types@^7.18.10", "@babel/types@^7.18.13", "@babel/types@^7.18.4", "@babel/types@^7.18.6", "@babel/types@^7.18.9":
-  version "7.18.13"
-  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.13.tgz#30aeb9e514f4100f7c1cb6e5ba472b30e48f519a"
-  integrity sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==
-  dependencies:
-    "@babel/helper-string-parser" "^7.18.10"
-    "@babel/helper-validator-identifier" "^7.18.6"
-    to-fast-properties "^2.0.0"
-
-"@emotion/babel-plugin@^11.10.5":
-  version "11.10.5"
-  resolved "https://registry.npmmirror.com/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz#65fa6e1790ddc9e23cc22658a4c5dea423c55c3c"
-  integrity sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA==
-  dependencies:
-    "@babel/helper-module-imports" "^7.16.7"
-    "@babel/plugin-syntax-jsx" "^7.17.12"
-    "@babel/runtime" "^7.18.3"
-    "@emotion/hash" "^0.9.0"
-    "@emotion/memoize" "^0.8.0"
-    "@emotion/serialize" "^1.1.1"
-    babel-plugin-macros "^3.1.0"
-    convert-source-map "^1.5.0"
-    escape-string-regexp "^4.0.0"
-    find-root "^1.1.0"
-    source-map "^0.5.7"
-    stylis "4.1.3"
-
-"@emotion/cache@^11.10.3":
-  version "11.10.3"
-  resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.3.tgz#c4f67904fad10c945fea5165c3a5a0583c164b87"
-  integrity sha512-Psmp/7ovAa8appWh3g51goxu/z3iVms7JXOreq136D8Bbn6dYraPnmL6mdM8GThEx9vwSn92Fz+mGSjBzN8UPQ==
-  dependencies:
-    "@emotion/memoize" "^0.8.0"
-    "@emotion/sheet" "^1.2.0"
-    "@emotion/utils" "^1.2.0"
-    "@emotion/weak-memoize" "^0.3.0"
-    stylis "4.0.13"
-
-"@emotion/cache@^11.10.5":
-  version "11.10.5"
-  resolved "https://registry.npmmirror.com/@emotion/cache/-/cache-11.10.5.tgz#c142da9351f94e47527ed458f7bbbbe40bb13c12"
-  integrity sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==
-  dependencies:
-    "@emotion/memoize" "^0.8.0"
-    "@emotion/sheet" "^1.2.1"
-    "@emotion/utils" "^1.2.0"
-    "@emotion/weak-memoize" "^0.3.0"
-    stylis "4.1.3"
-
-"@emotion/hash@^0.9.0":
-  version "0.9.0"
-  resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7"
-  integrity sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==
-
-"@emotion/is-prop-valid@^1.2.0":
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz#7f2d35c97891669f7e276eb71c83376a5dc44c83"
-  integrity sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==
-  dependencies:
-    "@emotion/memoize" "^0.8.0"
-
-"@emotion/memoize@^0.8.0":
-  version "0.8.0"
-  resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f"
-  integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==
-
-"@emotion/react@^11.10.5":
-  version "11.10.5"
-  resolved "https://registry.npmmirror.com/@emotion/react/-/react-11.10.5.tgz#95fff612a5de1efa9c0d535384d3cfa115fe175d"
-  integrity sha512-TZs6235tCJ/7iF6/rvTaOH4oxQg2gMAcdHemjwLKIjKz4rRuYe1HJ2TQJKnAcRAfOUDdU8XoDadCe1rl72iv8A==
-  dependencies:
-    "@babel/runtime" "^7.18.3"
-    "@emotion/babel-plugin" "^11.10.5"
-    "@emotion/cache" "^11.10.5"
-    "@emotion/serialize" "^1.1.1"
-    "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0"
-    "@emotion/utils" "^1.2.0"
-    "@emotion/weak-memoize" "^0.3.0"
-    hoist-non-react-statics "^3.3.1"
-
-"@emotion/serialize@^1.1.1":
-  version "1.1.1"
-  resolved "https://registry.npmmirror.com/@emotion/serialize/-/serialize-1.1.1.tgz#0595701b1902feded8a96d293b26be3f5c1a5cf0"
-  integrity sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==
-  dependencies:
-    "@emotion/hash" "^0.9.0"
-    "@emotion/memoize" "^0.8.0"
-    "@emotion/unitless" "^0.8.0"
-    "@emotion/utils" "^1.2.0"
-    csstype "^3.0.2"
-
-"@emotion/sheet@^1.2.0":
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.0.tgz#771b1987855839e214fc1741bde43089397f7be5"
-  integrity sha512-OiTkRgpxescko+M51tZsMq7Puu/KP55wMT8BgpcXVG2hqXc0Vo0mfymJ/Uj24Hp0i083ji/o0aLddh08UEjq8w==
-
-"@emotion/sheet@^1.2.1":
-  version "1.2.1"
-  resolved "https://registry.npmmirror.com/@emotion/sheet/-/sheet-1.2.1.tgz#0767e0305230e894897cadb6c8df2c51e61a6c2c"
-  integrity sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==
-
-"@emotion/styled@^11.10.5":
-  version "11.10.5"
-  resolved "https://registry.npmmirror.com/@emotion/styled/-/styled-11.10.5.tgz#1fe7bf941b0909802cb826457e362444e7e96a79"
-  integrity sha512-8EP6dD7dMkdku2foLoruPCNkRevzdcBaY6q0l0OsbyJK+x8D9HWjX27ARiSIKNF634hY9Zdoedh8bJCiva8yZw==
-  dependencies:
-    "@babel/runtime" "^7.18.3"
-    "@emotion/babel-plugin" "^11.10.5"
-    "@emotion/is-prop-valid" "^1.2.0"
-    "@emotion/serialize" "^1.1.1"
-    "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0"
-    "@emotion/utils" "^1.2.0"
-
-"@emotion/unitless@^0.8.0":
-  version "0.8.0"
-  resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db"
-  integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==
-
-"@emotion/use-insertion-effect-with-fallbacks@^1.0.0":
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz#ffadaec35dbb7885bd54de3fa267ab2f860294df"
-  integrity sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==
-
-"@emotion/utils@^1.2.0":
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561"
-  integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==
-
-"@emotion/weak-memoize@^0.3.0":
-  version "0.3.0"
-  resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb"
-  integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==
-
-"@esbuild/android-arm@0.15.18":
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.15.18.tgz#266d40b8fdcf87962df8af05b76219bc786b4f80"
-  integrity sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==
-
-"@esbuild/linux-loong64@0.15.18":
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz#128b76ecb9be48b60cf5cfc1c63a4f00691a3239"
-  integrity sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==
-
-"@jridgewell/gen-mapping@^0.3.2":
-  version "0.3.2"
-  resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
-  integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
-  dependencies:
-    "@jridgewell/set-array" "^1.0.1"
-    "@jridgewell/sourcemap-codec" "^1.4.10"
-    "@jridgewell/trace-mapping" "^0.3.9"
-
-"@jridgewell/resolve-uri@^3.0.3":
-  version "3.0.5"
-  resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c"
-  integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==
-
-"@jridgewell/set-array@^1.0.1":
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
-  integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
-
-"@jridgewell/sourcemap-codec@^1.4.10":
-  version "1.4.11"
-  resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec"
-  integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==
-
-"@jridgewell/trace-mapping@^0.3.0":
-  version "0.3.4"
-  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3"
-  integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==
-  dependencies:
-    "@jridgewell/resolve-uri" "^3.0.3"
-    "@jridgewell/sourcemap-codec" "^1.4.10"
-
-"@jridgewell/trace-mapping@^0.3.9":
-  version "0.3.15"
-  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774"
-  integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==
-  dependencies:
-    "@jridgewell/resolve-uri" "^3.0.3"
-    "@jridgewell/sourcemap-codec" "^1.4.10"
-
-"@juggle/resize-observer@^3.4.0":
-  version "3.4.0"
-  resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
-  integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
-
-"@mui/base@5.0.0-alpha.105":
-  version "5.0.0-alpha.105"
-  resolved "https://registry.npmmirror.com/@mui/base/-/base-5.0.0-alpha.105.tgz#ddf92c86db3355e0fe6886a818be073e2ee9a9f9"
-  integrity sha512-4IPBcJQIgVVXQvN6DQMoCHed52GBtwSqYs0jD0dDcMR3o76AodQtpEeWFz3p7mJoc6f/IHBl9U6jEfL1r/kM4g==
-  dependencies:
-    "@babel/runtime" "^7.19.0"
-    "@emotion/is-prop-valid" "^1.2.0"
-    "@mui/types" "^7.2.0"
-    "@mui/utils" "^5.10.9"
-    "@popperjs/core" "^2.11.6"
-    clsx "^1.2.1"
-    prop-types "^15.8.1"
-    react-is "^18.2.0"
-
-"@mui/core-downloads-tracker@^5.10.13":
-  version "5.10.13"
-  resolved "https://registry.npmmirror.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.13.tgz#34068ede2853392ca4fd82ad16d9c1ca664f69b3"
-  integrity sha512-zWkWPV/SaNdsIdxAWiuVGZ+Ue3BkfSIlU/BFIrJmuUcwiIa7gQsbI/DOpj1KzLvqZhdEe2wC1aG4nCHfzgc1Hg==
-
-"@mui/icons-material@^5.10.9":
-  version "5.10.9"
-  resolved "https://registry.npmmirror.com/@mui/icons-material/-/icons-material-5.10.9.tgz#f9522c49797caf30146acc576e37ecb4f95bbc38"
-  integrity sha512-sqClXdEM39WKQJOQ0ZCPTptaZgqwibhj2EFV9N0v7BU1PO8y4OcX/a2wIQHn4fNuDjIZktJIBrmU23h7aqlGgg==
-  dependencies:
-    "@babel/runtime" "^7.19.0"
-
-"@mui/material@^5.10.13":
-  version "5.10.13"
-  resolved "https://registry.npmmirror.com/@mui/material/-/material-5.10.13.tgz#49c505ed99bc97e573d0cc15bec074b080aacee1"
-  integrity sha512-TkkT1rNc0/hhL4/+zv4gYcA6egNWBH/1Tz+azoTnQIUdZ32fgwFI2pFX2KVJNTt30xnLznxDWtTv7ilmJQ52xw==
-  dependencies:
-    "@babel/runtime" "^7.19.0"
-    "@mui/base" "5.0.0-alpha.105"
-    "@mui/core-downloads-tracker" "^5.10.13"
-    "@mui/system" "^5.10.13"
-    "@mui/types" "^7.2.0"
-    "@mui/utils" "^5.10.9"
-    "@types/react-transition-group" "^4.4.5"
-    clsx "^1.2.1"
-    csstype "^3.1.1"
-    prop-types "^15.8.1"
-    react-is "^18.2.0"
-    react-transition-group "^4.4.5"
-
-"@mui/private-theming@^5.10.9":
-  version "5.10.9"
-  resolved "https://registry.npmmirror.com/@mui/private-theming/-/private-theming-5.10.9.tgz#c427bfa736455703975cdb108dbde6a174ba7971"
-  integrity sha512-BN7/CnsVPVyBaQpDTij4uV2xGYHHHhOgpdxeYLlIu+TqnsVM7wUeF+37kXvHovxM6xmL5qoaVUD98gDC0IZnHg==
-  dependencies:
-    "@babel/runtime" "^7.19.0"
-    "@mui/utils" "^5.10.9"
-    prop-types "^15.8.1"
-
-"@mui/styled-engine@^5.10.8":
-  version "5.10.8"
-  resolved "https://registry.npmmirror.com/@mui/styled-engine/-/styled-engine-5.10.8.tgz#2db411e4278f06f70ccb6b5cd56ace67109513f6"
-  integrity sha512-w+y8WI18EJV6zM/q41ug19cE70JTeO6sWFsQ7tgePQFpy6ToCVPh0YLrtqxUZXSoMStW5FMw0t9fHTFAqPbngw==
-  dependencies:
-    "@babel/runtime" "^7.19.0"
-    "@emotion/cache" "^11.10.3"
-    csstype "^3.1.1"
-    prop-types "^15.8.1"
-
-"@mui/system@^5.10.13":
-  version "5.10.13"
-  resolved "https://registry.npmmirror.com/@mui/system/-/system-5.10.13.tgz#b32a4441f9dd0760724cdbccf0a09728e63e3674"
-  integrity sha512-Xzx26Asu5fVlm0ucm+gnJmeX4Y1isrpVDvqxX4yJaOT7Fzmd8Lfq9ih3QMfZajns5LMtUiOuCQlVFRtUG5IY7A==
-  dependencies:
-    "@babel/runtime" "^7.19.0"
-    "@mui/private-theming" "^5.10.9"
-    "@mui/styled-engine" "^5.10.8"
-    "@mui/types" "^7.2.0"
-    "@mui/utils" "^5.10.9"
-    clsx "^1.2.1"
-    csstype "^3.1.1"
-    prop-types "^15.8.1"
-
-"@mui/types@^7.2.0":
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.0.tgz#91380c2d42420f51f404120f7a9270eadd6f5c23"
-  integrity sha512-lGXtFKe5lp3UxTBGqKI1l7G8sE2xBik8qCfrLHD5olwP/YU0/ReWoWT7Lp1//ri32dK39oPMrJN8TgbkCSbsNA==
-
-"@mui/utils@^5.10.3":
-  version "5.10.3"
-  resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.10.3.tgz#ce2a96f31de2a5e717f507b5383dbabbddbc4dfc"
-  integrity sha512-4jXMDPfx6bpMVuheLaOpKTjpzw39ogAZLeaLj5+RJec3E37/hAZMYjURfblLfTWMMoGoqkY03mNsZaEwNobBow==
-  dependencies:
-    "@babel/runtime" "^7.18.9"
-    "@types/prop-types" "^15.7.5"
-    "@types/react-is" "^16.7.1 || ^17.0.0"
-    prop-types "^15.8.1"
-    react-is "^18.2.0"
-
-"@mui/utils@^5.10.9":
-  version "5.10.9"
-  resolved "https://registry.npmmirror.com/@mui/utils/-/utils-5.10.9.tgz#9dc455f9230f43eeb81d96a9a4bdb3855bb9ea39"
-  integrity sha512-2tdHWrq3+WCy+G6TIIaFx3cg7PorXZ71P375ExuX61od1NOAJP1mK90VxQ8N4aqnj2vmO3AQDkV4oV2Ktvt4bA==
-  dependencies:
-    "@babel/runtime" "^7.19.0"
-    "@types/prop-types" "^15.7.5"
-    "@types/react-is" "^16.7.1 || ^17.0.0"
-    prop-types "^15.8.1"
-    react-is "^18.2.0"
-
-"@mui/x-data-grid@^5.17.11":
-  version "5.17.11"
-  resolved "https://registry.npmmirror.com/@mui/x-data-grid/-/x-data-grid-5.17.11.tgz#3a2a9889fb24030d8f11b03319638392d7df8752"
-  integrity sha512-9KaAsEHKTho/hXXSboxkewBI5HF9NwmgaHCjX7UCg/av3yP2wcWELui9mAWUjI6qm6+8hvKmKclf20ZZ+aPiNg==
-  dependencies:
-    "@babel/runtime" "^7.18.9"
-    "@mui/utils" "^5.10.3"
-    clsx "^1.2.1"
-    prop-types "^15.8.1"
-    reselect "^4.1.6"
-
-"@octokit/auth-token@^2.4.4":
-  version "2.5.0"
-  resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36"
-  integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==
-  dependencies:
-    "@octokit/types" "^6.0.3"
-
-"@octokit/core@^3.6.0":
-  version "3.6.0"
-  resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.6.0.tgz#3376cb9f3008d9b3d110370d90e0a1fcd5fe6085"
-  integrity sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==
-  dependencies:
-    "@octokit/auth-token" "^2.4.4"
-    "@octokit/graphql" "^4.5.8"
-    "@octokit/request" "^5.6.3"
-    "@octokit/request-error" "^2.0.5"
-    "@octokit/types" "^6.0.3"
-    before-after-hook "^2.2.0"
-    universal-user-agent "^6.0.0"
-
-"@octokit/endpoint@^6.0.1":
-  version "6.0.12"
-  resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658"
-  integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==
-  dependencies:
-    "@octokit/types" "^6.0.3"
-    is-plain-object "^5.0.0"
-    universal-user-agent "^6.0.0"
-
-"@octokit/graphql@^4.5.8":
-  version "4.8.0"
-  resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3"
-  integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==
-  dependencies:
-    "@octokit/request" "^5.6.0"
-    "@octokit/types" "^6.0.3"
-    universal-user-agent "^6.0.0"
-
-"@octokit/openapi-types@^11.2.0":
-  version "11.2.0"
-  resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-11.2.0.tgz#b38d7fc3736d52a1e96b230c1ccd4a58a2f400a6"
-  integrity sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==
-
-"@octokit/plugin-paginate-rest@^2.17.0":
-  version "2.17.0"
-  resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz#32e9c7cab2a374421d3d0de239102287d791bce7"
-  integrity sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==
-  dependencies:
-    "@octokit/types" "^6.34.0"
-
-"@octokit/plugin-rest-endpoint-methods@^5.13.0":
-  version "5.13.0"
-  resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz#8c46109021a3412233f6f50d28786f8e552427ba"
-  integrity sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==
-  dependencies:
-    "@octokit/types" "^6.34.0"
-    deprecation "^2.3.1"
-
-"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0":
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677"
-  integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==
-  dependencies:
-    "@octokit/types" "^6.0.3"
-    deprecation "^2.0.0"
-    once "^1.4.0"
-
-"@octokit/request@^5.6.0", "@octokit/request@^5.6.3":
-  version "5.6.3"
-  resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.3.tgz#19a022515a5bba965ac06c9d1334514eb50c48b0"
-  integrity sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==
-  dependencies:
-    "@octokit/endpoint" "^6.0.1"
-    "@octokit/request-error" "^2.1.0"
-    "@octokit/types" "^6.16.1"
-    is-plain-object "^5.0.0"
-    node-fetch "^2.6.7"
-    universal-user-agent "^6.0.0"
-
-"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.34.0":
-  version "6.34.0"
-  resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.34.0.tgz#c6021333334d1ecfb5d370a8798162ddf1ae8218"
-  integrity sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==
-  dependencies:
-    "@octokit/openapi-types" "^11.2.0"
-
-"@popperjs/core@^2.11.6":
-  version "2.11.6"
-  resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
-  integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==
-
-"@remix-run/router@1.0.3":
-  version "1.0.3"
-  resolved "https://registry.npmmirror.com/@remix-run/router/-/router-1.0.3.tgz#953b88c20ea00d0eddaffdc1b115c08474aa295d"
-  integrity sha512-ceuyTSs7PZ/tQqi19YZNBc5X7kj1f8p+4DIyrcIYFY9h+hd1OKm4RqtiWldR9eGEvIiJfsqwM4BsuCtRIuEw6Q==
-
-"@rollup/pluginutils@^4.2.1":
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
-  integrity sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==
-  dependencies:
-    estree-walker "^2.0.1"
-    picomatch "^2.2.2"
-
-"@svgr/babel-plugin-add-jsx-attribute@^6.3.1":
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.3.1.tgz#b9a5d84902be75a05ede92e70b338d28ab63fa74"
-  integrity sha512-jDBKArXYO1u0B1dmd2Nf8Oy6aTF5vLDfLoO9Oon/GLkqZ/NiggYWZA+a2HpUMH4ITwNqS3z43k8LWApB8S583w==
-
-"@svgr/babel-plugin-remove-jsx-attribute@^6.3.1":
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.3.1.tgz#4877995452efc997b36777abe1fde9705ef78e8b"
-  integrity sha512-dQzyJ4prwjcFd929T43Z8vSYiTlTu8eafV40Z2gO7zy/SV5GT+ogxRJRBIKWomPBOiaVXFg3jY4S5hyEN3IBjQ==
-
-"@svgr/babel-plugin-remove-jsx-empty-expression@^6.3.1":
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-6.3.1.tgz#2d67a0e92904c9be149a5b22d3a3797ce4d7b514"
-  integrity sha512-HBOUc1XwSU67fU26V5Sfb8MQsT0HvUyxru7d0oBJ4rA2s4HW3PhyAPC7fV/mdsSGpAvOdd8Wpvkjsr0fWPUO7A==
-
-"@svgr/babel-plugin-replace-jsx-attribute-value@^6.3.1":
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.3.1.tgz#306f5247139c53af70d1778f2719647c747998ee"
-  integrity sha512-C12e6aN4BXAolRrI601gPn5MDFCRHO7C4TM8Kks+rDtl8eEq+NN1sak0eAzJu363x3TmHXdZn7+Efd2nr9I5dA==
-
-"@svgr/babel-plugin-svg-dynamic-title@^6.3.1":
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.3.1.tgz#6ce26d34cbc93eb81737ef528528907c292e7aa2"
-  integrity sha512-6NU55Mmh3M5u2CfCCt6TX29/pPneutrkJnnDCHbKZnjukZmmgUAZLtZ2g6ZoSPdarowaQmAiBRgAHqHmG0vuqA==
-
-"@svgr/babel-plugin-svg-em-dimensions@^6.3.1":
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.3.1.tgz#5ade2a724b290873c30529d1d8cd23523856287a"
-  integrity sha512-HV1NGHYTTe1vCNKlBgq/gKuCSfaRlKcHIADn7P8w8U3Zvujdw1rmusutghJ1pZJV7pDt3Gt8ws+SVrqHnBO/Qw==
-
-"@svgr/babel-plugin-transform-react-native-svg@^6.3.1":
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.3.1.tgz#d654f509d692c3a09dfb475757a44bd9f6ad7ddf"
-  integrity sha512-2wZhSHvTolFNeKDAN/ZmIeSz2O9JSw72XD+o2bNp2QAaWqa8KGpn5Yk5WHso6xqfSAiRzAE+GXlsrBO4UP9LLw==
-
-"@svgr/babel-plugin-transform-svg-component@^6.3.1":
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.3.1.tgz#21a285dbffdce9567c437ebf0d081bf9210807e6"
-  integrity sha512-cZ8Tr6ZAWNUFfDeCKn/pGi976iWSkS8ijmEYKosP+6ktdZ7lW9HVLHojyusPw3w0j8PI4VBeWAXAmi/2G7owxw==
-
-"@svgr/babel-preset@^6.3.1":
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-6.3.1.tgz#8bd1ead79637d395e9362b01dd37cfd59702e152"
-  integrity sha512-tQtWtzuMMQ3opH7je+MpwfuRA1Hf3cKdSgTtAYwOBDfmhabP7rcTfBi3E7V3MuwJNy/Y02/7/RutvwS1W4Qv9g==
-  dependencies:
-    "@svgr/babel-plugin-add-jsx-attribute" "^6.3.1"
-    "@svgr/babel-plugin-remove-jsx-attribute" "^6.3.1"
-    "@svgr/babel-plugin-remove-jsx-empty-expression" "^6.3.1"
-    "@svgr/babel-plugin-replace-jsx-attribute-value" "^6.3.1"
-    "@svgr/babel-plugin-svg-dynamic-title" "^6.3.1"
-    "@svgr/babel-plugin-svg-em-dimensions" "^6.3.1"
-    "@svgr/babel-plugin-transform-react-native-svg" "^6.3.1"
-    "@svgr/babel-plugin-transform-svg-component" "^6.3.1"
-
-"@svgr/core@^6.3.1":
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/@svgr/core/-/core-6.3.1.tgz#752adf49d8d5473b15d76ca741961de093f715bd"
-  integrity sha512-Sm3/7OdXbQreemf9aO25keerZSbnKMpGEfmH90EyYpj1e8wMD4TuwJIb3THDSgRMWk1kYJfSRulELBy4gVgZUA==
-  dependencies:
-    "@svgr/plugin-jsx" "^6.3.1"
-    camelcase "^6.2.0"
-    cosmiconfig "^7.0.1"
-
-"@svgr/hast-util-to-babel-ast@^6.3.1":
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.3.1.tgz#59614e24d2a4a28010e02089213b3448d905769d"
-  integrity sha512-NgyCbiTQIwe3wHe/VWOUjyxmpUmsrBjdoIxKpXt3Nqc3TN30BpJG22OxBvVzsAh9jqep0w0/h8Ywvdk3D9niNQ==
-  dependencies:
-    "@babel/types" "^7.18.4"
-    entities "^4.3.0"
-
-"@svgr/plugin-jsx@^6.3.1":
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-6.3.1.tgz#de7b2de824296b836d6b874d498377896e367f50"
-  integrity sha512-r9+0mYG3hD4nNtUgsTXWGYJomv/bNd7kC16zvsM70I/bGeoCi/3lhTmYqeN6ChWX317OtQCSZZbH4wq9WwoXbw==
-  dependencies:
-    "@babel/core" "^7.18.5"
-    "@svgr/babel-preset" "^6.3.1"
-    "@svgr/hast-util-to-babel-ast" "^6.3.1"
-    svg-parser "^2.0.4"
-
-"@tauri-apps/api@^1.3.0":
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/@tauri-apps/api/-/api-1.3.0.tgz#d0c853ab2cc7506bd826c5f7f260c67c7c15def5"
-  integrity sha512-AH+3FonkKZNtfRtGrObY38PrzEj4d+1emCbwNGu0V2ENbXjlLHMZQlUh+Bhu/CRmjaIwZMGJ3yFvWaZZgTHoog==
-
-"@tauri-apps/cli-darwin-arm64@1.3.1":
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.3.1.tgz#ef0fe290e0a6e3e53fa2cc4f1a72a0c87921427c"
-  integrity sha512-QlepYVPgOgspcwA/u4kGG4ZUijlXfdRtno00zEy+LxinN/IRXtk+6ErVtsmoLi1ZC9WbuMwzAcsRvqsD+RtNAg==
-
-"@tauri-apps/cli-darwin-x64@1.3.1":
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.3.1.tgz#4c84ea0f08a5b636b067943d637a38e091a4aad3"
-  integrity sha512-fKcAUPVFO3jfDKXCSDGY0MhZFF/wDtx3rgFnogWYu4knk38o9RaqRkvMvqJhLYPuWaEM5h6/z1dRrr9KKCbrVg==
-
-"@tauri-apps/cli-linux-arm-gnueabihf@1.3.1":
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.3.1.tgz#a4f1b237189e4f8f89cc890e1dc2eec76d4345be"
-  integrity sha512-+4H0dv8ltJHYu/Ma1h9ixUPUWka9EjaYa8nJfiMsdCI4LJLNE6cPveE7RmhZ59v9GW1XB108/k083JUC/OtGvA==
-
-"@tauri-apps/cli-linux-arm64-gnu@1.3.1":
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.3.1.tgz#e2391326b64dfe13c7442bdcc13c4988ce5e6df9"
-  integrity sha512-Pj3odVO1JAxLjYmoXKxcrpj/tPxcA8UP8N06finhNtBtBaxAjrjjxKjO4968KB0BUH7AASIss9EL4Tr0FGnDuw==
-
-"@tauri-apps/cli-linux-arm64-musl@1.3.1":
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.3.1.tgz#49354349f80f879ffc6950c0c03c0aea1395efa5"
-  integrity sha512-tA0JdDLPFaj42UDIVcF2t8V0tSha40rppcmAR/MfQpTCxih6399iMjwihz9kZE1n4b5O4KTq9GliYo50a8zYlQ==
-
-"@tauri-apps/cli-linux-x64-gnu@1.3.1":
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.3.1.tgz#9a33ffe9e0d9b1b3825db57cbcfcddeb773682c6"
-  integrity sha512-FDU+Mnvk6NLkqQimcNojdKpMN4Y3W51+SQl+NqG9AFCWprCcSg62yRb84751ujZuf2MGT8HQOfmd0i77F4Q3tQ==
-
-"@tauri-apps/cli-linux-x64-musl@1.3.1":
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.3.1.tgz#5283731e894c17bc070c499e73145cfe2633ef21"
-  integrity sha512-MpO3akXFmK8lZYEbyQRDfhdxz1JkTBhonVuz5rRqxwA7gnGWHa1aF1+/2zsy7ahjB2tQ9x8DDFDMdVE20o9HrA==
-
-"@tauri-apps/cli-win32-ia32-msvc@1.3.1":
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.3.1.tgz#f31538abfd94f27ade1f17d01f30da6be1660c6f"
-  integrity sha512-9Boeo3K5sOrSBAZBuYyGkpV2RfnGQz3ZhGJt4hE6P+HxRd62lS6+qDKAiw1GmkZ0l1drc2INWrNeT50gwOKwIQ==
-
-"@tauri-apps/cli-win32-x64-msvc@1.3.1":
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.3.1.tgz#1eb09d55b99916a3cd84cb91c75ef906db67d35d"
-  integrity sha512-wMrTo91hUu5CdpbElrOmcZEoJR4aooTG+fbtcc87SMyPGQy1Ux62b+ZdwLvL1sVTxnIm//7v6QLRIWGiUjCPwA==
-
-"@tauri-apps/cli@^1.3.1":
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/@tauri-apps/cli/-/cli-1.3.1.tgz#4c5259bf1f9c97084dd016e6b34dca53de380e24"
-  integrity sha512-o4I0JujdITsVRm3/0spfJX7FcKYrYV1DXJqzlWIn6IY25/RltjU6qbC1TPgVww3RsRX63jyVUTcWpj5wwFl+EQ==
-  optionalDependencies:
-    "@tauri-apps/cli-darwin-arm64" "1.3.1"
-    "@tauri-apps/cli-darwin-x64" "1.3.1"
-    "@tauri-apps/cli-linux-arm-gnueabihf" "1.3.1"
-    "@tauri-apps/cli-linux-arm64-gnu" "1.3.1"
-    "@tauri-apps/cli-linux-arm64-musl" "1.3.1"
-    "@tauri-apps/cli-linux-x64-gnu" "1.3.1"
-    "@tauri-apps/cli-linux-x64-musl" "1.3.1"
-    "@tauri-apps/cli-win32-ia32-msvc" "1.3.1"
-    "@tauri-apps/cli-win32-x64-msvc" "1.3.1"
-
-"@types/fs-extra@^9.0.13":
-  version "9.0.13"
-  resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.13.tgz#7594fbae04fe7f1918ce8b3d213f74ff44ac1f45"
-  integrity sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==
-  dependencies:
-    "@types/node" "*"
-
-"@types/js-cookie@^2.x.x":
-  version "2.2.7"
-  resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3"
-  integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==
-
-"@types/js-cookie@^3.0.2":
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.2.tgz#451eaeece64c6bdac8b2dde0caab23b085899e0d"
-  integrity sha512-6+0ekgfusHftJNYpihfkMu8BWdeHs9EOJuGcSofErjstGPfPGEu9yTu4t460lTzzAMl2cM5zngQJqPMHbbnvYA==
-
-"@types/lodash-es@^4.17.7":
-  version "4.17.7"
-  resolved "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.7.tgz#22edcae9f44aff08546e71db8925f05b33c7cc40"
-  integrity sha512-z0ptr6UI10VlU6l5MYhGwS4mC8DZyYer2mCoyysZtSF7p26zOX8UpbrV0YpNYLGS8K4PUFIyEr62IMFFjveSiQ==
-  dependencies:
-    "@types/lodash" "*"
-
-"@types/lodash@*":
-  version "4.14.191"
-  resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa"
-  integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==
-
-"@types/lodash@^4.14.180":
-  version "4.14.180"
-  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670"
-  integrity sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g==
-
-"@types/minimatch@^3.0.3":
-  version "3.0.5"
-  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
-  integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
-
-"@types/node@*":
-  version "17.0.23"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da"
-  integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==
-
-"@types/parse-json@^4.0.0":
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
-  integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
-
-"@types/prop-types@*":
-  version "15.7.4"
-  resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
-  integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==
-
-"@types/prop-types@^15.7.5":
-  version "15.7.5"
-  resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
-  integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
-
-"@types/react-dom@^18.0.11":
-  version "18.0.11"
-  resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.11.tgz#321351c1459bc9ca3d216aefc8a167beec334e33"
-  integrity sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==
-  dependencies:
-    "@types/react" "*"
-
-"@types/react-is@^16.7.1 || ^17.0.0":
-  version "17.0.3"
-  resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-17.0.3.tgz#2d855ba575f2fc8d17ef9861f084acc4b90a137a"
-  integrity sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==
-  dependencies:
-    "@types/react" "*"
-
-"@types/react-transition-group@^4.4.5":
-  version "4.4.5"
-  resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.5.tgz#aae20dcf773c5aa275d5b9f7cdbca638abc5e416"
-  integrity sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==
-  dependencies:
-    "@types/react" "*"
-
-"@types/react@*":
-  version "17.0.43"
-  resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55"
-  integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A==
-  dependencies:
-    "@types/prop-types" "*"
-    "@types/scheduler" "*"
-    csstype "^3.0.2"
-
-"@types/scheduler@*":
-  version "0.16.2"
-  resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
-  integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
-
-"@virtuoso.dev/react-urx@^0.2.12":
-  version "0.2.13"
-  resolved "https://registry.yarnpkg.com/@virtuoso.dev/react-urx/-/react-urx-0.2.13.tgz#e2cfc42d259d2a002695e7517d34cb97b64ee9c4"
-  integrity sha512-MY0ugBDjFb5Xt8v2HY7MKcRGqw/3gTpMlLXId2EwQvYJoC8sP7nnXjAxcBtTB50KTZhO0SbzsFimaZ7pSdApwA==
-  dependencies:
-    "@virtuoso.dev/urx" "^0.2.13"
-
-"@virtuoso.dev/urx@^0.2.12", "@virtuoso.dev/urx@^0.2.13":
-  version "0.2.13"
-  resolved "https://registry.yarnpkg.com/@virtuoso.dev/urx/-/urx-0.2.13.tgz#a65e7e8d923cb03397ac876bfdd45c7f71c8edf1"
-  integrity sha512-iirJNv92A1ZWxoOHHDYW/1KPoi83939o83iUBQHIim0i3tMeSKEh+bxhJdTHQ86Mr4uXx9xGUTq69cp52ZP8Xw==
-
-"@vitejs/plugin-react@^2.0.1":
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-2.0.1.tgz#3197c01d8e4a4eb9fed829c7888c467a43aadd4e"
-  integrity sha512-uINzNHmjrbunlFtyVkST6lY1ewSfz/XwLufG0PIqvLGnpk2nOIOa/1CACTDNcKi1/RwaCzJLmsXwm1NsUVV/NA==
-  dependencies:
-    "@babel/core" "^7.18.10"
-    "@babel/plugin-transform-react-jsx" "^7.18.10"
-    "@babel/plugin-transform-react-jsx-development" "^7.18.6"
-    "@babel/plugin-transform-react-jsx-self" "^7.18.6"
-    "@babel/plugin-transform-react-jsx-source" "^7.18.6"
-    magic-string "^0.26.2"
-    react-refresh "^0.14.0"
-
-adm-zip@^0.5.9:
-  version "0.5.9"
-  resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.9.tgz#b33691028333821c0cf95c31374c5462f2905a83"
-  integrity sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==
-
-agent-base@6:
-  version "6.0.2"
-  resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
-  integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
-  dependencies:
-    debug "4"
-
-ahooks-v3-count@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/ahooks-v3-count/-/ahooks-v3-count-1.0.0.tgz#ddeb392e009ad6e748905b3cbf63a9fd8262ca80"
-  integrity sha512-V7uUvAwnimu6eh/PED4mCDjE7tokeZQLKlxg9lCTMPhN+NjsSbtdacByVlR1oluXQzD3MOw55wylDmQo4+S9ZQ==
-
-ahooks@^3.7.2:
-  version "3.7.2"
-  resolved "https://registry.npmmirror.com/ahooks/-/ahooks-3.7.2.tgz#0afa42625e77ae1cc4b60b19c45cf12a8cf29b56"
-  integrity sha512-nJPsQJcmJnGaNXiqgZdfO7UMs+o926LQg6VyDYt2vzKhXU8Ze/U87NsA/FeIvlIZB0rQr/j7uotFb1bGPp627A==
-  dependencies:
-    "@types/js-cookie" "^2.x.x"
-    ahooks-v3-count "^1.0.0"
-    dayjs "^1.9.1"
-    intersection-observer "^0.12.0"
-    js-cookie "^2.x.x"
-    lodash "^4.17.21"
-    resize-observer-polyfill "^1.5.1"
-    screenfull "^5.0.0"
-
-ansi-styles@^3.2.1:
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
-  integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
-  dependencies:
-    color-convert "^1.9.0"
-
-ansi-styles@^4.1.0:
-  version "4.3.0"
-  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
-  integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
-  dependencies:
-    color-convert "^2.0.1"
-
-anymatch@~3.1.2:
-  version "3.1.2"
-  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
-  integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
-  dependencies:
-    normalize-path "^3.0.0"
-    picomatch "^2.0.4"
-
-array-differ@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b"
-  integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==
-
-array-union@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
-  integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
-
-arrify@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
-  integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
-
-asynckit@^0.4.0:
-  version "0.4.0"
-  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
-  integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
-
-axios@^1.1.3:
-  version "1.1.3"
-  resolved "https://registry.npmmirror.com/axios/-/axios-1.1.3.tgz#8274250dada2edf53814ed7db644b9c2866c1e35"
-  integrity sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==
-  dependencies:
-    follow-redirects "^1.15.0"
-    form-data "^4.0.0"
-    proxy-from-env "^1.1.0"
-
-babel-plugin-macros@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1"
-  integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==
-  dependencies:
-    "@babel/runtime" "^7.12.5"
-    cosmiconfig "^7.0.0"
-    resolve "^1.19.0"
-
-balanced-match@^1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
-  integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
-
-before-after-hook@^2.2.0:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e"
-  integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==
-
-binary-extensions@^2.0.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
-  integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
-
-brace-expansion@^1.1.7:
-  version "1.1.11"
-  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
-  integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
-  dependencies:
-    balanced-match "^1.0.0"
-    concat-map "0.0.1"
-
-braces@~3.0.2:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
-  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
-  dependencies:
-    fill-range "^7.0.1"
-
-browserslist@^4.20.2:
-  version "4.20.3"
-  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.3.tgz#eb7572f49ec430e054f56d52ff0ebe9be915f8bf"
-  integrity sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==
-  dependencies:
-    caniuse-lite "^1.0.30001332"
-    electron-to-chromium "^1.4.118"
-    escalade "^3.1.1"
-    node-releases "^2.0.3"
-    picocolors "^1.0.0"
-
-callsites@^3.0.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
-  integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-
-camelcase@^6.2.0:
-  version "6.3.0"
-  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
-  integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
-
-caniuse-lite@^1.0.30001332:
-  version "1.0.30001341"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz#59590c8ffa8b5939cf4161f00827b8873ad72498"
-  integrity sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==
-
-chalk@^2.0.0:
-  version "2.4.2"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
-  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
-  dependencies:
-    ansi-styles "^3.2.1"
-    escape-string-regexp "^1.0.5"
-    supports-color "^5.3.0"
-
-chalk@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
-  integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
-  dependencies:
-    ansi-styles "^4.1.0"
-    supports-color "^7.1.0"
-
-"chokidar@>=3.0.0 <4.0.0":
-  version "3.5.3"
-  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
-  integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
-  dependencies:
-    anymatch "~3.1.2"
-    braces "~3.0.2"
-    glob-parent "~5.1.2"
-    is-binary-path "~2.1.0"
-    is-glob "~4.0.1"
-    normalize-path "~3.0.0"
-    readdirp "~3.6.0"
-  optionalDependencies:
-    fsevents "~2.3.2"
-
-clsx@^1.2.1:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
-  integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
-
-color-convert@^1.9.0:
-  version "1.9.3"
-  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
-  integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
-  dependencies:
-    color-name "1.1.3"
-
-color-convert@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
-  integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
-  dependencies:
-    color-name "~1.1.4"
-
-color-name@1.1.3:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
-  integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
-
-color-name@~1.1.4:
-  version "1.1.4"
-  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
-  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-
-combined-stream@^1.0.8:
-  version "1.0.8"
-  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
-  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
-  dependencies:
-    delayed-stream "~1.0.0"
-
-concat-map@0.0.1:
-  version "0.0.1"
-  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
-  integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
-
-convert-source-map@^1.5.0, convert-source-map@^1.7.0:
-  version "1.8.0"
-  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
-  integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
-  dependencies:
-    safe-buffer "~5.1.1"
-
-cosmiconfig@^7.0.0, cosmiconfig@^7.0.1:
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d"
-  integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==
-  dependencies:
-    "@types/parse-json" "^4.0.0"
-    import-fresh "^3.2.1"
-    parse-json "^5.0.0"
-    path-type "^4.0.0"
-    yaml "^1.10.0"
-
-cross-env@^7.0.3:
-  version "7.0.3"
-  resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
-  integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
-  dependencies:
-    cross-spawn "^7.0.1"
-
-cross-spawn@^7.0.0, cross-spawn@^7.0.1:
-  version "7.0.3"
-  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
-  integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
-  dependencies:
-    path-key "^3.1.0"
-    shebang-command "^2.0.0"
-    which "^2.0.1"
-
-csstype@^3.0.2:
-  version "3.0.11"
-  resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33"
-  integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==
-
-csstype@^3.1.1:
-  version "3.1.1"
-  resolved "https://registry.npmmirror.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9"
-  integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==
-
-data-uri-to-buffer@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b"
-  integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==
-
-dayjs@1.11.5, dayjs@^1.9.1:
-  version "1.11.5"
-  resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.5.tgz#00e8cc627f231f9499c19b38af49f56dc0ac5e93"
-  integrity sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==
-
-debug@4, debug@^4.1.0:
-  version "4.3.4"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
-  integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
-  dependencies:
-    ms "2.1.2"
-
-delayed-stream@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
-  integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
-
-deprecation@^2.0.0, deprecation@^2.3.1:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
-  integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
-
-dom-helpers@^5.0.1:
-  version "5.2.1"
-  resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
-  integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
-  dependencies:
-    "@babel/runtime" "^7.8.7"
-    csstype "^3.0.2"
-
-electron-to-chromium@^1.4.118:
-  version "1.4.137"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz#186180a45617283f1c012284458510cd99d6787f"
-  integrity sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==
-
-end-of-stream@^1.1.0:
-  version "1.4.4"
-  resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
-  integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
-  dependencies:
-    once "^1.4.0"
-
-entities@^4.3.0:
-  version "4.4.0"
-  resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174"
-  integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==
-
-error-ex@^1.3.1:
-  version "1.3.2"
-  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
-  integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
-  dependencies:
-    is-arrayish "^0.2.1"
-
-esbuild-android-64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz#20a7ae1416c8eaade917fb2453c1259302c637a5"
-  integrity sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==
-
-esbuild-android-arm64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz#9cc0ec60581d6ad267568f29cf4895ffdd9f2f04"
-  integrity sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==
-
-esbuild-darwin-64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz#428e1730ea819d500808f220fbc5207aea6d4410"
-  integrity sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==
-
-esbuild-darwin-arm64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz#b6dfc7799115a2917f35970bfbc93ae50256b337"
-  integrity sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==
-
-esbuild-freebsd-64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz#4e190d9c2d1e67164619ae30a438be87d5eedaf2"
-  integrity sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==
-
-esbuild-freebsd-arm64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz#18a4c0344ee23bd5a6d06d18c76e2fd6d3f91635"
-  integrity sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==
-
-esbuild-linux-32@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz#9a329731ee079b12262b793fb84eea762e82e0ce"
-  integrity sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==
-
-esbuild-linux-64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz#532738075397b994467b514e524aeb520c191b6c"
-  integrity sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==
-
-esbuild-linux-arm64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz#5372e7993ac2da8f06b2ba313710d722b7a86e5d"
-  integrity sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==
-
-esbuild-linux-arm@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz#e734aaf259a2e3d109d4886c9e81ec0f2fd9a9cc"
-  integrity sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==
-
-esbuild-linux-mips64le@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz#c0487c14a9371a84eb08fab0e1d7b045a77105eb"
-  integrity sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==
-
-esbuild-linux-ppc64le@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz#af048ad94eed0ce32f6d5a873f7abe9115012507"
-  integrity sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==
-
-esbuild-linux-riscv64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz#423ed4e5927bd77f842bd566972178f424d455e6"
-  integrity sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==
-
-esbuild-linux-s390x@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz#21d21eaa962a183bfb76312e5a01cc5ae48ce8eb"
-  integrity sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==
-
-esbuild-netbsd-64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz#ae75682f60d08560b1fe9482bfe0173e5110b998"
-  integrity sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==
-
-esbuild-openbsd-64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz#79591a90aa3b03e4863f93beec0d2bab2853d0a8"
-  integrity sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==
-
-esbuild-sunos-64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz#fd528aa5da5374b7e1e93d36ef9b07c3dfed2971"
-  integrity sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==
-
-esbuild-windows-32@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz#0e92b66ecdf5435a76813c4bc5ccda0696f4efc3"
-  integrity sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==
-
-esbuild-windows-64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz#0fc761d785414284fc408e7914226d33f82420d0"
-  integrity sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==
-
-esbuild-windows-arm64@0.15.18:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz#5b5bdc56d341d0922ee94965c89ee120a6a86eb7"
-  integrity sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==
-
-esbuild@^0.15.9:
-  version "0.15.18"
-  resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.18.tgz#ea894adaf3fbc036d32320a00d4d6e4978a2f36d"
-  integrity sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==
-  optionalDependencies:
-    "@esbuild/android-arm" "0.15.18"
-    "@esbuild/linux-loong64" "0.15.18"
-    esbuild-android-64 "0.15.18"
-    esbuild-android-arm64 "0.15.18"
-    esbuild-darwin-64 "0.15.18"
-    esbuild-darwin-arm64 "0.15.18"
-    esbuild-freebsd-64 "0.15.18"
-    esbuild-freebsd-arm64 "0.15.18"
-    esbuild-linux-32 "0.15.18"
-    esbuild-linux-64 "0.15.18"
-    esbuild-linux-arm "0.15.18"
-    esbuild-linux-arm64 "0.15.18"
-    esbuild-linux-mips64le "0.15.18"
-    esbuild-linux-ppc64le "0.15.18"
-    esbuild-linux-riscv64 "0.15.18"
-    esbuild-linux-s390x "0.15.18"
-    esbuild-netbsd-64 "0.15.18"
-    esbuild-openbsd-64 "0.15.18"
-    esbuild-sunos-64 "0.15.18"
-    esbuild-windows-32 "0.15.18"
-    esbuild-windows-64 "0.15.18"
-    esbuild-windows-arm64 "0.15.18"
-
-escalade@^3.1.1:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
-  integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
-
-escape-string-regexp@^1.0.5:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
-  integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
-
-escape-string-regexp@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
-  integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
-
-estree-walker@^2.0.1:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
-  integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
-
-execa@^4.0.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a"
-  integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==
-  dependencies:
-    cross-spawn "^7.0.0"
-    get-stream "^5.0.0"
-    human-signals "^1.1.1"
-    is-stream "^2.0.0"
-    merge-stream "^2.0.0"
-    npm-run-path "^4.0.0"
-    onetime "^5.1.0"
-    signal-exit "^3.0.2"
-    strip-final-newline "^2.0.0"
-
-fetch-blob@^3.1.2, fetch-blob@^3.1.4:
-  version "3.1.5"
-  resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.1.5.tgz#0077bf5f3fcdbd9d75a0b5362f77dbb743489863"
-  integrity sha512-N64ZpKqoLejlrwkIAnb9iLSA3Vx/kjgzpcDhygcqJ2KKjky8nCgUQ+dzXtbrLaWZGZNmNfQTsiQ0weZ1svglHg==
-  dependencies:
-    node-domexception "^1.0.0"
-    web-streams-polyfill "^3.0.3"
-
-fill-range@^7.0.1:
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
-  integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
-  dependencies:
-    to-regex-range "^5.0.1"
-
-find-root@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
-  integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
-
-find-up@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
-  integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
-  dependencies:
-    locate-path "^5.0.0"
-    path-exists "^4.0.0"
-
-follow-redirects@^1.15.0:
-  version "1.15.2"
-  resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
-  integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
-
-form-data@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
-  integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
-  dependencies:
-    asynckit "^0.4.0"
-    combined-stream "^1.0.8"
-    mime-types "^2.1.12"
-
-formdata-polyfill@^4.0.10:
-  version "4.0.10"
-  resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423"
-  integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==
-  dependencies:
-    fetch-blob "^3.1.2"
-
-fs-extra@^10.0.0:
-  version "10.0.1"
-  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.1.tgz#27de43b4320e833f6867cc044bfce29fdf0ef3b8"
-  integrity sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==
-  dependencies:
-    graceful-fs "^4.2.0"
-    jsonfile "^6.0.1"
-    universalify "^2.0.0"
-
-fsevents@~2.3.2:
-  version "2.3.2"
-  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
-  integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
-
-function-bind@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
-  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
-
-gensync@^1.0.0-beta.2:
-  version "1.0.0-beta.2"
-  resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
-  integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
-
-get-stream@^5.0.0:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
-  integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
-  dependencies:
-    pump "^3.0.0"
-
-glob-parent@~5.1.2:
-  version "5.1.2"
-  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
-  integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
-  dependencies:
-    is-glob "^4.0.1"
-
-globals@^11.1.0:
-  version "11.12.0"
-  resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
-  integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
-
-graceful-fs@^4.1.6, graceful-fs@^4.2.0:
-  version "4.2.9"
-  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96"
-  integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
-
-hamt_plus@1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/hamt_plus/-/hamt_plus-1.0.2.tgz#e21c252968c7e33b20f6a1b094cd85787a265601"
-  integrity sha1-4hwlKWjH4zsg9qGwlM2FeHomVgE=
-
-has-flag@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
-  integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
-
-has-flag@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
-  integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-
-has@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
-  integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
-  dependencies:
-    function-bind "^1.1.1"
-
-hoist-non-react-statics@^3.3.1:
-  version "3.3.2"
-  resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
-  integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
-  dependencies:
-    react-is "^16.7.0"
-
-html-parse-stringify@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
-  integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==
-  dependencies:
-    void-elements "3.1.0"
-
-https-proxy-agent@^5.0.1:
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
-  integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
-  dependencies:
-    agent-base "6"
-    debug "4"
-
-human-signals@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
-  integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
-
-husky@^7.0.0:
-  version "7.0.4"
-  resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.4.tgz#242048245dc49c8fb1bf0cc7cfb98dd722531535"
-  integrity sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==
-
-i18next@^22.0.4:
-  version "22.0.4"
-  resolved "https://registry.npmmirror.com/i18next/-/i18next-22.0.4.tgz#77d8871687b0ab072b38991e3887187823667e30"
-  integrity sha512-TOp7BTMKDbUkOHMzDlVsCYWpyaFkKakrrO3HNXfSz4EeJaWwnBScRmgQSTaWHScXVHBUFXTvShrCW8uryBYFcg==
-  dependencies:
-    "@babel/runtime" "^7.17.2"
-
-ignore@^5.1.4:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
-  integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
-
-immutable@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23"
-  integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==
-
-import-fresh@^3.2.1:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
-  integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
-  dependencies:
-    parent-module "^1.0.0"
-    resolve-from "^4.0.0"
-
-intersection-observer@^0.12.0:
-  version "0.12.0"
-  resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.12.0.tgz#6c84628f67ce8698e5f9ccf857d97718745837aa"
-  integrity sha512-2Vkz8z46Dv401zTWudDGwO7KiGHNDkMv417T5ItcNYfmvHR/1qCTVBO9vwH8zZmQ0WkA/1ARwpysR9bsnop4NQ==
-
-is-arrayish@^0.2.1:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
-  integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
-
-is-binary-path@~2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
-  integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
-  dependencies:
-    binary-extensions "^2.0.0"
-
-is-core-module@^2.9.0:
-  version "2.10.0"
-  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed"
-  integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==
-  dependencies:
-    has "^1.0.3"
-
-is-extglob@^2.1.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
-  integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
-
-is-glob@^4.0.1, is-glob@~4.0.1:
-  version "4.0.3"
-  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
-  integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
-  dependencies:
-    is-extglob "^2.1.1"
-
-is-number@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
-  integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
-
-is-plain-object@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
-  integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
-
-is-stream@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
-  integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
-
-isexe@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
-  integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
-
-js-cookie@^2.x.x:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
-  integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
-
-"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
-  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-
-jsesc@^2.5.1:
-  version "2.5.2"
-  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
-  integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
-
-json-parse-even-better-errors@^2.3.0:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
-  integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
-
-json5@^2.2.1:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
-  integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
-
-jsonfile@^6.0.1:
-  version "6.1.0"
-  resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
-  integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
-  dependencies:
-    universalify "^2.0.0"
-  optionalDependencies:
-    graceful-fs "^4.1.6"
-
-lines-and-columns@^1.1.6:
-  version "1.2.4"
-  resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
-  integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
-
-locate-path@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
-  integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
-  dependencies:
-    p-locate "^4.1.0"
-
-lodash-es@^4.17.21:
-  version "4.17.21"
-  resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
-  integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
-
-lodash@^4.17.21:
-  version "4.17.21"
-  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
-  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-
-loose-envify@^1.1.0, loose-envify@^1.4.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
-  integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
-  dependencies:
-    js-tokens "^3.0.0 || ^4.0.0"
-
-magic-string@^0.26.2:
-  version "0.26.3"
-  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.26.3.tgz#25840b875140f7b4785ab06bddc384270b7dd452"
-  integrity sha512-u1Po0NDyFcwdg2nzHT88wSK0+Rih0N1M+Ph1Sp08k8yvFFU3KR72wryS7e1qMPJypt99WB7fIFVCA92mQrMjrg==
-  dependencies:
-    sourcemap-codec "^1.4.8"
-
-merge-stream@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
-  integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
-
-mime-db@1.52.0:
-  version "1.52.0"
-  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
-  integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
-
-mime-types@^2.1.12:
-  version "2.1.35"
-  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
-  integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
-  dependencies:
-    mime-db "1.52.0"
-
-mimic-fn@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
-  integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
-
-minimatch@^3.0.4:
-  version "3.1.2"
-  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
-  integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
-  dependencies:
-    brace-expansion "^1.1.7"
-
-monaco-editor@^0.34.1:
-  version "0.34.1"
-  resolved "https://registry.npmmirror.com/monaco-editor/-/monaco-editor-0.34.1.tgz#1b75c4ad6bc4c1f9da656d740d98e0b850a22f87"
-  integrity sha512-FKc80TyiMaruhJKKPz5SpJPIjL+dflGvz4CpuThaPMc94AyN7SeC9HQ8hrvaxX7EyHdJcUY5i4D0gNyJj1vSZQ==
-
-mri@^1.1.5:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
-  integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==
-
-ms@2.1.2:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
-  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-
-multimatch@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3"
-  integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==
-  dependencies:
-    "@types/minimatch" "^3.0.3"
-    array-differ "^3.0.0"
-    array-union "^2.1.0"
-    arrify "^2.0.1"
-    minimatch "^3.0.4"
-
-nanoid@^3.3.4:
-  version "3.3.4"
-  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
-  integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
-
-node-domexception@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
-  integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
-
-node-fetch@^2.6.7:
-  version "2.6.7"
-  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
-  integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
-  dependencies:
-    whatwg-url "^5.0.0"
-
-node-fetch@^3.2.6:
-  version "3.2.6"
-  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.6.tgz#6d4627181697a9d9674aae0d61548e0d629b31b9"
-  integrity sha512-LAy/HZnLADOVkVPubaxHDft29booGglPFDr2Hw0J1AercRh01UiVFm++KMDnJeH9sHgNB4hsXPii7Sgym/sTbw==
-  dependencies:
-    data-uri-to-buffer "^4.0.0"
-    fetch-blob "^3.1.4"
-    formdata-polyfill "^4.0.10"
-
-node-releases@^2.0.3:
-  version "2.0.4"
-  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.4.tgz#f38252370c43854dc48aa431c766c6c398f40476"
-  integrity sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==
-
-normalize-path@^3.0.0, normalize-path@~3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
-  integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
-
-npm-run-path@^4.0.0:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
-  integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
-  dependencies:
-    path-key "^3.0.0"
-
-object-assign@^4.1.1:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
-  integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
-
-once@^1.3.1, once@^1.4.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
-  integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
-  dependencies:
-    wrappy "1"
-
-onetime@^5.1.0:
-  version "5.1.2"
-  resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
-  integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
-  dependencies:
-    mimic-fn "^2.1.0"
-
-p-limit@^2.2.0:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
-  integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
-  dependencies:
-    p-try "^2.0.0"
-
-p-locate@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
-  integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
-  dependencies:
-    p-limit "^2.2.0"
-
-p-try@^2.0.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
-  integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
-
-parent-module@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
-  integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
-  dependencies:
-    callsites "^3.0.0"
-
-parse-json@^5.0.0:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
-  integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
-  dependencies:
-    "@babel/code-frame" "^7.0.0"
-    error-ex "^1.3.1"
-    json-parse-even-better-errors "^2.3.0"
-    lines-and-columns "^1.1.6"
-
-path-exists@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
-  integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
-
-path-key@^3.0.0, path-key@^3.1.0:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
-  integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
-
-path-parse@^1.0.7:
-  version "1.0.7"
-  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
-  integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
-
-path-type@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
-  integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
-
-picocolors@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
-  integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
-
-picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
-  integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
-
-postcss@^8.4.18:
-  version "8.4.21"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4"
-  integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==
-  dependencies:
-    nanoid "^3.3.4"
-    picocolors "^1.0.0"
-    source-map-js "^1.0.2"
-
-prettier@^2.7.1:
-  version "2.7.1"
-  resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
-  integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
-
-pretty-quick@^3.1.3:
-  version "3.1.3"
-  resolved "https://registry.yarnpkg.com/pretty-quick/-/pretty-quick-3.1.3.tgz#15281108c0ddf446675157ca40240099157b638e"
-  integrity sha512-kOCi2FJabvuh1as9enxYmrnBC6tVMoVOenMaBqRfsvBHB0cbpYHjdQEpSglpASDFEXVwplpcGR4CLEaisYAFcA==
-  dependencies:
-    chalk "^3.0.0"
-    execa "^4.0.0"
-    find-up "^4.1.0"
-    ignore "^5.1.4"
-    mri "^1.1.5"
-    multimatch "^4.0.0"
-
-prop-types@^15.6.2, prop-types@^15.8.1:
-  version "15.8.1"
-  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
-  integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
-  dependencies:
-    loose-envify "^1.4.0"
-    object-assign "^4.1.1"
-    react-is "^16.13.1"
-
-proxy-from-env@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
-  integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
-
-pump@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
-  integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
-  dependencies:
-    end-of-stream "^1.1.0"
-    once "^1.3.1"
-
-react-dom@^18.2.0:
-  version "18.2.0"
-  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
-  integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
-  dependencies:
-    loose-envify "^1.1.0"
-    scheduler "^0.23.0"
-
-react-error-boundary@^3.1.4:
-  version "3.1.4"
-  resolved "https://registry.npmmirror.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz#255db92b23197108757a888b01e5b729919abde0"
-  integrity sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==
-  dependencies:
-    "@babel/runtime" "^7.12.5"
-
-react-hook-form@^7.39.5:
-  version "7.39.5"
-  resolved "https://registry.npmmirror.com/react-hook-form/-/react-hook-form-7.39.5.tgz#a4272b60288ef5e1bb42bbb6ba3b36d243ab2879"
-  integrity sha512-OE0HKyz5IPc6svN2wd+e+evidZrw4O4WZWAWYzQVZuHi+hYnHFSLnxOq0ddjbdmaLIsLHut/ab7j72y2QT3+KA==
-
-react-i18next@^12.0.0:
-  version "12.0.0"
-  resolved "https://registry.npmmirror.com/react-i18next/-/react-i18next-12.0.0.tgz#634015a2c035779c5736ae4c2e5c34c1659753b1"
-  integrity sha512-/O7N6aIEAl1FaWZBNvhdIo9itvF/MO/nRKr9pYqRc9LhuC1u21SlfwpiYQqvaeNSEW3g3qUXLREOWMt+gxrWbg==
-  dependencies:
-    "@babel/runtime" "^7.14.5"
-    html-parse-stringify "^3.0.1"
-
-react-is@^16.13.1, react-is@^16.7.0:
-  version "16.13.1"
-  resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
-  integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
-
-react-is@^18.2.0:
-  version "18.2.0"
-  resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
-  integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
-
-react-refresh@^0.14.0:
-  version "0.14.0"
-  resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
-  integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
-
-react-router-dom@^6.4.3:
-  version "6.4.3"
-  resolved "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-6.4.3.tgz#70093b5f65f85f1df9e5d4182eb7ff3a08299275"
-  integrity sha512-MiaYQU8CwVCaOfJdYvt84KQNjT78VF0TJrA17SIQgNHRvLnXDJO6qsFqq8F/zzB1BWZjCFIrQpu4QxcshitziQ==
-  dependencies:
-    "@remix-run/router" "1.0.3"
-    react-router "6.4.3"
-
-react-router@6.4.3:
-  version "6.4.3"
-  resolved "https://registry.npmmirror.com/react-router/-/react-router-6.4.3.tgz#9ed3ee4d6e95889e9b075a5d63e29acc7def0d49"
-  integrity sha512-BT6DoGn6aV1FVP5yfODMOiieakp3z46P1Fk0RNzJMACzE7C339sFuHebfvWtnB4pzBvXXkHP2vscJzWRuUjTtA==
-  dependencies:
-    "@remix-run/router" "1.0.3"
-
-react-transition-group@^4.4.5:
-  version "4.4.5"
-  resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
-  integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
-  dependencies:
-    "@babel/runtime" "^7.5.5"
-    dom-helpers "^5.0.1"
-    loose-envify "^1.4.0"
-    prop-types "^15.6.2"
-
-react-virtuoso@^3.1.3:
-  version "3.1.3"
-  resolved "https://registry.npmmirror.com/react-virtuoso/-/react-virtuoso-3.1.3.tgz#db811ff6fdd4749cfe9348f6d0b1333a348e65c4"
-  integrity sha512-sc4WICEZkyT+XdVc7gA/61UT43ZnMSX0ugh+xBG2cX+EDWs31wP1dSKQ2HSQ0YFLhZXRJ+Jqndqa8MTu4NE4CQ==
-  dependencies:
-    "@virtuoso.dev/react-urx" "^0.2.12"
-    "@virtuoso.dev/urx" "^0.2.12"
-
-react@^18.2.0:
-  version "18.2.0"
-  resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
-  integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
-  dependencies:
-    loose-envify "^1.1.0"
-
-readdirp@~3.6.0:
-  version "3.6.0"
-  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
-  integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
-  dependencies:
-    picomatch "^2.2.1"
-
-recoil@^0.7.6:
-  version "0.7.6"
-  resolved "https://registry.npmmirror.com/recoil/-/recoil-0.7.6.tgz#75297ecd70bbfeeb72e861aa6141a86bb6dfcd5e"
-  integrity sha512-hsBEw7jFdpBCY/tu2GweiyaqHKxVj6EqF2/SfrglbKvJHhpN57SANWvPW+gE90i3Awi+A5gssOd3u+vWlT+g7g==
-  dependencies:
-    hamt_plus "1.0.2"
-
-regenerator-runtime@^0.13.10:
-  version "0.13.10"
-  resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz#ed07b19616bcbec5da6274ebc75ae95634bfc2ee"
-  integrity sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==
-
-regenerator-runtime@^0.13.4:
-  version "0.13.9"
-  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
-  integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
-
-reselect@^4.1.6:
-  version "4.1.6"
-  resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.6.tgz#19ca2d3d0b35373a74dc1c98692cdaffb6602656"
-  integrity sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ==
-
-resize-observer-polyfill@^1.5.1:
-  version "1.5.1"
-  resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
-  integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
-
-resolve-from@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
-  integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
-
-resolve@^1.19.0, resolve@^1.22.1:
-  version "1.22.1"
-  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
-  integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
-  dependencies:
-    is-core-module "^2.9.0"
-    path-parse "^1.0.7"
-    supports-preserve-symlinks-flag "^1.0.0"
-
-rollup@^2.79.1:
-  version "2.79.1"
-  resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7"
-  integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
-  optionalDependencies:
-    fsevents "~2.3.2"
-
-safe-buffer@~5.1.1:
-  version "5.1.2"
-  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
-  integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-
-sass@^1.54.0:
-  version "1.54.8"
-  resolved "https://registry.yarnpkg.com/sass/-/sass-1.54.8.tgz#4adef0dd86ea2b1e4074f551eeda4fc5f812a996"
-  integrity sha512-ib4JhLRRgbg6QVy6bsv5uJxnJMTS2soVcCp9Y88Extyy13A8vV0G1fAwujOzmNkFQbR3LvedudAMbtuNRPbQww==
-  dependencies:
-    chokidar ">=3.0.0 <4.0.0"
-    immutable "^4.0.0"
-    source-map-js ">=0.6.2 <2.0.0"
-
-scheduler@^0.23.0:
-  version "0.23.0"
-  resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
-  integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
-  dependencies:
-    loose-envify "^1.1.0"
-
-screenfull@^5.0.0:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba"
-  integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==
-
-semver@^6.3.0:
-  version "6.3.0"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
-  integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-
-shebang-command@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
-  integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
-  dependencies:
-    shebang-regex "^3.0.0"
-
-shebang-regex@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
-  integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
-
-signal-exit@^3.0.2:
-  version "3.0.7"
-  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
-  integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
-
-snarkdown@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/snarkdown/-/snarkdown-2.0.0.tgz#b1feb4db91b9f94a8ebbd7a50f3e99aee18b1e03"
-  integrity sha512-MgL/7k/AZdXCTJiNgrO7chgDqaB9FGM/1Tvlcenenb7div6obaDATzs16JhFyHHBGodHT3B7RzRc5qk8pFhg3A==
-
-"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
-  integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
-
-source-map@^0.5.7:
-  version "0.5.7"
-  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
-  integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
-
-sourcemap-codec@^1.4.8:
-  version "1.4.8"
-  resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
-  integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
-
-strip-final-newline@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
-  integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
-
-stylis@4.0.13:
-  version "4.0.13"
-  resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91"
-  integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==
-
-stylis@4.1.3:
-  version "4.1.3"
-  resolved "https://registry.npmmirror.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7"
-  integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==
-
-supports-color@^5.3.0:
-  version "5.5.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
-  integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
-  dependencies:
-    has-flag "^3.0.0"
-
-supports-color@^7.1.0:
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
-  integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
-  dependencies:
-    has-flag "^4.0.0"
-
-supports-preserve-symlinks-flag@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
-  integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-
-svg-parser@^2.0.4:
-  version "2.0.4"
-  resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5"
-  integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==
-
-swr@^1.3.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/swr/-/swr-1.3.0.tgz#c6531866a35b4db37b38b72c45a63171faf9f4e8"
-  integrity sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==
-
-to-fast-properties@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
-  integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
-
-to-regex-range@^5.0.1:
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
-  integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
-  dependencies:
-    is-number "^7.0.0"
-
-tr46@~0.0.3:
-  version "0.0.3"
-  resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
-  integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
-
-tunnel@^0.0.6:
-  version "0.0.6"
-  resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
-  integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
-
-typescript@^4.7.4:
-  version "4.7.4"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
-  integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
-
-universal-user-agent@^6.0.0:
-  version "6.0.0"
-  resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee"
-  integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==
-
-universalify@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
-  integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
-
-vite-plugin-monaco-editor@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/vite-plugin-monaco-editor/-/vite-plugin-monaco-editor-1.1.0.tgz#a6238c2e13d5e98dd54a1bc51f6f189325219de3"
-  integrity sha512-IvtUqZotrRoVqwT0PBBDIZPNraya3BxN/bfcNfnxZ5rkJiGcNtO5eAOWWSgT7zullIAEqQwxMU83yL9J5k7gww==
-
-vite-plugin-svgr@^2.2.1:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/vite-plugin-svgr/-/vite-plugin-svgr-2.2.1.tgz#6e1132a3b66f71e1d69e8c5fe989393260184ac3"
-  integrity sha512-+EqwahbwjETJH/ssA/66dNYyKN1cO0AStq96MuXmq5maU7AePBMf2lDKfQna49tJZAjtRz+R899BWCsUUP45Fg==
-  dependencies:
-    "@rollup/pluginutils" "^4.2.1"
-    "@svgr/core" "^6.3.1"
-
-vite@^3.2.5:
-  version "3.2.5"
-  resolved "https://registry.yarnpkg.com/vite/-/vite-3.2.5.tgz#dee5678172a8a0ab3e547ad4148c3d547f90e86a"
-  integrity sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==
-  dependencies:
-    esbuild "^0.15.9"
-    postcss "^8.4.18"
-    resolve "^1.22.1"
-    rollup "^2.79.1"
-  optionalDependencies:
-    fsevents "~2.3.2"
-
-void-elements@3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
-  integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=
-
-web-streams-polyfill@^3.0.3:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz#a6b74026b38e4885869fb5c589e90b95ccfc7965"
-  integrity sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==
-
-webidl-conversions@^3.0.0:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
-  integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=
-
-whatwg-url@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
-  integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0=
-  dependencies:
-    tr46 "~0.0.3"
-    webidl-conversions "^3.0.0"
-
-which@^2.0.1:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
-  integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
-  dependencies:
-    isexe "^2.0.0"
-
-wrappy@1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
-  integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
-
-yaml@^1.10.0:
-  version "1.10.2"
-  resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
-  integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==