Repository: web-scrobbler/web-scrobbler
Pull request #4334 (2023-12-01 03:42:56)

KEXP connector - Added filter to replace "smart" quotes with plain
Added filter function to replace "smart" quotes with plain quotes.  Filter function copied from #3548.

The KEXP website often uses right single apostrophes ("smart" quotes) instead of plain apostrophes.  On Last.fm, tags with right single apostrophes are treated as separate pages which is often the less common tag.

playlist with right single apostrophe
![image](https://github.com/web-scrobbler/web-scrobbler/assets/8346050/e98812af-569c-4758-b557-1d29ef2f1157)

plain apostrophe
![image](https://github.com/web-scrobbler/web-scrobbler/assets/8346050/86982ac7-df71-460c-9f66-9a52c9f20ddf)

right single apostrophe
![image](https://github.com/web-scrobbler/web-scrobbler/assets/8346050/0589c676-b615-4b86-9d6d-5cde773a9183)





Patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 89a4da6d..178a79fa 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -16,6 +16,7 @@ jobs:
         uses: actions/setup-node@v4
         with:
           node-version-file: '.nvmrc'
+          cache: 'npm'
 
       - name: Install dependencies
         run: npm ci
@@ -24,12 +25,6 @@ jobs:
         run: |
           npm run build chrome
 
-      - name: Upload the extension as an artifact
-        uses: actions/upload-artifact@v3
-        with:
-          name: web-scrobbler-chrome
-          path: build/chrome
-
   build-firefox:
     name: Build the extension for Firefox
     runs-on: ubuntu-latest
@@ -45,6 +40,7 @@ jobs:
         uses: actions/setup-node@v4
         with:
           node-version-file: '.nvmrc'
+          cache: 'npm'
 
       - name: Install dependencies
         run: npm ci
@@ -53,12 +49,6 @@ jobs:
         run: |
           npm run build firefox
 
-      - name: Upload the extension as an artifact
-        uses: actions/upload-artifact@v3
-        with:
-          name: web-scrobbler-firefox
-          path: build/firefox
-
   build-safari:
     name: Build the extension for Safari
     runs-on: macos-latest
@@ -70,6 +60,7 @@ jobs:
         uses: actions/setup-node@v4
         with:
           node-version-file: '.nvmrc'
+          cache: 'npm'
 
       - name: Install dependencies
         run: npm ci
@@ -77,9 +68,3 @@ jobs:
       - name: Build the extension
         run: |
           npm run build safari
-
-      - name: Upload the extension as an artifact
-        uses: actions/upload-artifact@v3
-        with:
-          name: web-scrobbler-safari
-          path: build/safari
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 019a6ca1..ebda7f00 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -17,6 +17,7 @@ jobs:
         uses: actions/setup-node@v4
         with:
           node-version-file: '.nvmrc'
+          cache: 'npm'
 
       - name: Install dependencies
         run: npm ci
@@ -44,6 +45,7 @@ jobs:
         uses: actions/setup-node@v4
         with:
           node-version-file: '.nvmrc'
+          cache: 'npm'
 
       - name: Install dependencies
         run: npm ci
@@ -71,6 +73,7 @@ jobs:
         uses: actions/setup-node@v4
         with:
           node-version-file: '.nvmrc'
+          cache: 'npm'
 
       - name: Install dependencies
         run: npm ci
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index cda1d244..48ad0529 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -16,6 +16,7 @@ jobs:
         uses: actions/setup-node@v4
         with:
           node-version-file: '.nvmrc'
+          cache: 'npm'
 
       - name: Install dependencies
         run: npm ci
diff --git a/.github/workflows/release-extension.yml b/.github/workflows/release-extension.yml
index 6f2d73b4..01b36f31 100644
--- a/.github/workflows/release-extension.yml
+++ b/.github/workflows/release-extension.yml
@@ -20,16 +20,21 @@ jobs:
         uses: actions/checkout@v4
         with:
           token: ${{ secrets.BOT_PAT }}
+
       - name: Setup git config
         run: |
           git config user.name "web-scrobbler-bot"
           git config user.email "${{ secrets.BOT_EMAIL }}"
+
       - name: Setup Node.js
         uses: actions/setup-node@v4
         with:
           node-version-file: '.nvmrc'
+          cache: 'npm'
+
       - name: Install dependencies
         run: npm ci
+
       - name: Release
         run: ./release-extension.sh ${{ inputs.release_type }}
         env:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 75911052..9ff4ec70 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -18,6 +18,7 @@ jobs:
         uses: actions/setup-node@v4
         with:
           node-version-file: '.nvmrc'
+          cache: 'npm'
 
       - name: Install dependencies
         run: npm ci
diff --git a/package-lock.json b/package-lock.json
index d62ab612..2db4f2e0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,38 +1,38 @@
 {
   "name": "web-scrobbler",
-  "version": "3.2.0",
+  "version": "3.3.0",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "web-scrobbler",
-      "version": "3.2.0",
+      "version": "3.3.0",
       "license": "MIT",
       "dependencies": {
         "@suid/icons-material": "0.6.11",
         "@web-scrobbler/metadata-filter": "3.0.2",
         "blueimp-md5": "2.19.0",
         "stylelint": "15.11.0",
-        "vite": "4.5.0",
+        "vite": "4.5.1",
         "webextension-polyfill": "0.10.0"
       },
       "devDependencies": {
         "@types/archiver": "6.0.2",
         "@types/blueimp-md5": "2.18.2",
         "@types/fs-extra": "11.0.3",
-        "@types/imagemin": "8.0.4",
+        "@types/imagemin": "8.0.5",
         "@types/imagemin-jpegtran": "5.0.4",
-        "@types/node": "20.9.4",
-        "@types/react": "18.2.38",
-        "@types/webextension-polyfill": "0.10.4",
-        "@typescript-eslint/eslint-plugin": "6.7.5",
+        "@types/node": "20.10.4",
+        "@types/react": "18.2.46",
+        "@types/webextension-polyfill": "0.10.7",
+        "@typescript-eslint/eslint-plugin": "6.16.0",
         "@web-scrobbler/eslint-config": "3.0.0",
         "@web-scrobbler/stylelint-config": "1.0.1",
         "archiver": "6.0.1",
         "canvas": "2.11.2",
         "chokidar": "3.5.3",
-        "esbuild": "0.19.5",
-        "eslint": "8.51.0",
+        "esbuild": "0.19.10",
+        "eslint": "8.56.0",
         "eslint-plugin-react": "7.33.2",
         "eslint-plugin-solid": "0.13.0",
         "eslint-plugin-tsdoc": "0.2.17",
@@ -41,18 +41,18 @@
         "imagemin": "8.0.1",
         "imagemin-jpegtran": "7.0.0",
         "imagemin-pngquant": "9.0.2",
-        "prettier": "3.0.3",
+        "prettier": "3.1.1",
         "prettier-config-web-scrobbler": "0.1.0",
         "remark": "15.0.1",
         "remark-cli": "12.0.0",
         "remark-preset-lint-recommended": "6.1.3",
         "sass": "1.69.5",
-        "solid-js": "1.8.5",
-        "tsx": "4.1.3",
-        "typescript": "5.2.2",
+        "solid-js": "1.8.7",
+        "tsx": "4.6.2",
+        "typescript": "5.3.3",
         "vite-plugin-conditional-compiler": "0.2.1",
-        "vite-plugin-solid": "2.7.2",
-        "vite-plugin-static-copy": "0.17.0",
+        "vite-plugin-solid": "2.8.0",
+        "vite-plugin-static-copy": "0.17.1",
         "vitest": "0.34.6"
       },
       "engines": {
@@ -82,11 +82,11 @@
       }
     },
     "node_modules/@babel/code-frame": {
-      "version": "7.22.13",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
-      "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
+      "version": "7.23.5",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
+      "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
       "dependencies": {
-        "@babel/highlight": "^7.22.13",
+        "@babel/highlight": "^7.23.4",
         "chalk": "^2.4.2"
       },
       "engines": {
@@ -158,30 +158,30 @@
       }
     },
     "node_modules/@babel/compat-data": {
-      "version": "7.22.20",
-      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz",
-      "integrity": "sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==",
+      "version": "7.23.5",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz",
+      "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==",
       "dev": true,
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/core": {
-      "version": "7.23.0",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz",
-      "integrity": "sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==",
+      "version": "7.23.5",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz",
+      "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==",
       "dev": true,
       "dependencies": {
         "@ampproject/remapping": "^2.2.0",
-        "@babel/code-frame": "^7.22.13",
-        "@babel/generator": "^7.23.0",
+        "@babel/code-frame": "^7.23.5",
+        "@babel/generator": "^7.23.5",
         "@babel/helper-compilation-targets": "^7.22.15",
-        "@babel/helper-module-transforms": "^7.23.0",
-        "@babel/helpers": "^7.23.0",
-        "@babel/parser": "^7.23.0",
+        "@babel/helper-module-transforms": "^7.23.3",
+        "@babel/helpers": "^7.23.5",
+        "@babel/parser": "^7.23.5",
         "@babel/template": "^7.22.15",
-        "@babel/traverse": "^7.23.0",
-        "@babel/types": "^7.23.0",
+        "@babel/traverse": "^7.23.5",
+        "@babel/types": "^7.23.5",
         "convert-source-map": "^2.0.0",
         "debug": "^4.1.0",
         "gensync": "^1.0.0-beta.2",
@@ -206,12 +206,12 @@
       }
     },
     "node_modules/@babel/generator": {
-      "version": "7.23.0",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
-      "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
+      "version": "7.23.5",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz",
+      "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==",
       "dev": true,
       "dependencies": {
-        "@babel/types": "^7.23.0",
+        "@babel/types": "^7.23.5",
         "@jridgewell/gen-mapping": "^0.3.2",
         "@jridgewell/trace-mapping": "^0.3.17",
         "jsesc": "^2.5.1"
@@ -273,17 +273,17 @@
       "dev": true
     },
     "node_modules/@babel/helper-create-class-features-plugin": {
-      "version": "7.22.15",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz",
-      "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==",
+      "version": "7.23.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.5.tgz",
+      "integrity": "sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==",
       "dev": true,
       "dependencies": {
         "@babel/helper-annotate-as-pure": "^7.22.5",
-        "@babel/helper-environment-visitor": "^7.22.5",
-        "@babel/helper-function-name": "^7.22.5",
-        "@babel/helper-member-expression-to-functions": "^7.22.15",
+        "@babel/helper-environment-visitor": "^7.22.20",
+        "@babel/helper-function-name": "^7.23.0",
+        "@babel/helper-member-expression-to-functions": "^7.23.0",
         "@babel/helper-optimise-call-expression": "^7.22.5",
-        "@babel/helper-replace-supers": "^7.22.9",
+        "@babel/helper-replace-supers": "^7.22.20",
         "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
         "@babel/helper-split-export-declaration": "^7.22.6",
         "semver": "^6.3.1"
@@ -363,9 +363,9 @@
       }
     },
     "node_modules/@babel/helper-module-transforms": {
-      "version": "7.23.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz",
-      "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==",
+      "version": "7.23.3",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz",
+      "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==",
       "dev": true,
       "dependencies": {
         "@babel/helper-environment-visitor": "^7.22.20",
@@ -456,9 +456,9 @@
       }
     },
     "node_modules/@babel/helper-string-parser": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
-      "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
+      "version": "7.23.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
+      "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
       "dev": true,
       "engines": {
         "node": ">=6.9.0"
@@ -473,32 +473,32 @@
       }
     },
     "node_modules/@babel/helper-validator-option": {
-      "version": "7.22.15",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz",
-      "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==",
+      "version": "7.23.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz",
+      "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==",
       "dev": true,
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helpers": {
-      "version": "7.23.1",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz",
-      "integrity": "sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==",
+      "version": "7.23.5",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz",
+      "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==",
       "dev": true,
       "dependencies": {
         "@babel/template": "^7.22.15",
-        "@babel/traverse": "^7.23.0",
-        "@babel/types": "^7.23.0"
+        "@babel/traverse": "^7.23.5",
+        "@babel/types": "^7.23.5"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/highlight": {
-      "version": "7.22.20",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
-      "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
+      "version": "7.23.4",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
+      "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
       "dependencies": {
         "@babel/helper-validator-identifier": "^7.22.20",
         "chalk": "^2.4.2",
@@ -573,9 +573,9 @@
       }
     },
     "node_modules/@babel/parser": {
-      "version": "7.23.0",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
-      "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
+      "version": "7.23.5",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz",
+      "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==",
       "dev": true,
       "bin": {
         "parser": "bin/babel-parser.js"
@@ -585,9 +585,9 @@
       }
     },
     "node_modules/@babel/plugin-syntax-jsx": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz",
-      "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==",
+      "version": "7.23.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz",
+      "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==",
       "dev": true,
       "dependencies": {
         "@babel/helper-plugin-utils": "^7.22.5"
@@ -600,9 +600,9 @@
       }
     },
     "node_modules/@babel/plugin-syntax-typescript": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz",
-      "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==",
+      "version": "7.23.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz",
+      "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==",
       "dev": true,
       "dependencies": {
         "@babel/helper-plugin-utils": "^7.22.5"
@@ -615,12 +615,12 @@
       }
     },
     "node_modules/@babel/plugin-transform-modules-commonjs": {
-      "version": "7.23.0",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.0.tgz",
-      "integrity": "sha512-32Xzss14/UVc7k9g775yMIvkVK8xwKE0DPdP5JTapr3+Z9w4tzeOuLNY6BXDQR6BdnzIlXnCGAzsk/ICHBLVWQ==",
+      "version": "7.23.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz",
+      "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==",
       "dev": true,
       "dependencies": {
-        "@babel/helper-module-transforms": "^7.23.0",
+        "@babel/helper-module-transforms": "^7.23.3",
         "@babel/helper-plugin-utils": "^7.22.5",
         "@babel/helper-simple-access": "^7.22.5"
       },
@@ -632,15 +632,15 @@
       }
     },
     "node_modules/@babel/plugin-transform-typescript": {
-      "version": "7.22.15",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.15.tgz",
-      "integrity": "sha512-1uirS0TnijxvQLnlv5wQBwOX3E1wCFX7ITv+9pBV2wKEk4K+M5tqDaoNXnTH8tjEIYHLO98MwiTWO04Ggz4XuA==",
+      "version": "7.23.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.5.tgz",
+      "integrity": "sha512-2fMkXEJkrmwgu2Bsv1Saxgj30IXZdJ+84lQcKKI7sm719oXs0BBw2ZENKdJdR1PjWndgLCEBNXJOri0fk7RYQA==",
       "dev": true,
       "dependencies": {
         "@babel/helper-annotate-as-pure": "^7.22.5",
-        "@babel/helper-create-class-features-plugin": "^7.22.15",
+        "@babel/helper-create-class-features-plugin": "^7.23.5",
         "@babel/helper-plugin-utils": "^7.22.5",
-        "@babel/plugin-syntax-typescript": "^7.22.5"
+        "@babel/plugin-syntax-typescript": "^7.23.3"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -650,16 +650,16 @@
       }
     },
     "node_modules/@babel/preset-typescript": {
-      "version": "7.23.0",
-      "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.23.0.tgz",
-      "integrity": "sha512-6P6VVa/NM/VlAYj5s2Aq/gdVg8FSENCg3wlZ6Qau9AcPaoF5LbN1nyGlR9DTRIw9PpxI94e+ReydsJHcjwAweg==",
+      "version": "7.23.3",
+      "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.23.3.tgz",
+      "integrity": "sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==",
       "dev": true,
       "dependencies": {
         "@babel/helper-plugin-utils": "^7.22.5",
         "@babel/helper-validator-option": "^7.22.15",
-        "@babel/plugin-syntax-jsx": "^7.22.5",
-        "@babel/plugin-transform-modules-commonjs": "^7.23.0",
-        "@babel/plugin-transform-typescript": "^7.22.15"
+        "@babel/plugin-syntax-jsx": "^7.23.3",
+        "@babel/plugin-transform-modules-commonjs": "^7.23.3",
+        "@babel/plugin-transform-typescript": "^7.23.3"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -696,19 +696,19 @@
       }
     },
     "node_modules/@babel/traverse": {
-      "version": "7.23.2",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
-      "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
+      "version": "7.23.5",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz",
+      "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==",
       "dev": true,
       "dependencies": {
-        "@babel/code-frame": "^7.22.13",
-        "@babel/generator": "^7.23.0",
+        "@babel/code-frame": "^7.23.5",
+        "@babel/generator": "^7.23.5",
         "@babel/helper-environment-visitor": "^7.22.20",
         "@babel/helper-function-name": "^7.23.0",
         "@babel/helper-hoist-variables": "^7.22.5",
         "@babel/helper-split-export-declaration": "^7.22.6",
-        "@babel/parser": "^7.23.0",
-        "@babel/types": "^7.23.0",
+        "@babel/parser": "^7.23.5",
+        "@babel/types": "^7.23.5",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       },
@@ -726,12 +726,12 @@
       }
     },
     "node_modules/@babel/types": {
-      "version": "7.23.0",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
-      "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
+      "version": "7.23.5",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz",
+      "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==",
       "dev": true,
       "dependencies": {
-        "@babel/helper-string-parser": "^7.22.5",
+        "@babel/helper-string-parser": "^7.23.4",
         "@babel/helper-validator-identifier": "^7.22.20",
         "to-fast-properties": "^2.0.0"
       },
@@ -836,10 +836,26 @@
         "node": ">=16"
       }
     },
+    "node_modules/@esbuild/aix-ppc64": {
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.10.tgz",
+      "integrity": "sha512-Q+mk96KJ+FZ30h9fsJl+67IjNJm3x2eX+GBWGmocAKgzp27cowCOOqSdscX80s0SpdFXZnIv/+1xD1EctFx96Q==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/@esbuild/android-arm": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.5.tgz",
-      "integrity": "sha512-bhvbzWFF3CwMs5tbjf3ObfGqbl/17ict2/uwOSfr3wmxDE6VdS2GqY/FuzIPe0q0bdhj65zQsvqfArI9MY6+AA==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.10.tgz",
+      "integrity": "sha512-7W0bK7qfkw1fc2viBfrtAEkDKHatYfHzr/jKAHNr9BvkYDXPcC6bodtm8AyLJNNuqClLNaeTLuwURt4PRT9d7w==",
       "cpu": [
         "arm"
       ],
@@ -853,9 +869,9 @@
       }
     },
     "node_modules/@esbuild/android-arm64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.5.tgz",
-      "integrity": "sha512-5d1OkoJxnYQfmC+Zd8NBFjkhyCNYwM4n9ODrycTFY6Jk1IGiZ+tjVJDDSwDt77nK+tfpGP4T50iMtVi4dEGzhQ==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.10.tgz",
+      "integrity": "sha512-1X4CClKhDgC3by7k8aOWZeBXQX8dHT5QAMCAQDArCLaYfkppoARvh0fit3X2Qs+MXDngKcHv6XXyQCpY0hkK1Q==",
       "cpu": [
         "arm64"
       ],
@@ -869,9 +885,9 @@
       }
     },
     "node_modules/@esbuild/android-x64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.5.tgz",
-      "integrity": "sha512-9t+28jHGL7uBdkBjL90QFxe7DVA+KGqWlHCF8ChTKyaKO//VLuoBricQCgwhOjA1/qOczsw843Fy4cbs4H3DVA==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.10.tgz",
+      "integrity": "sha512-O/nO/g+/7NlitUxETkUv/IvADKuZXyH4BHf/g/7laqKC4i/7whLpB0gvpPc2zpF0q9Q6FXS3TS75QHac9MvVWw==",
       "cpu": [
         "x64"
       ],
@@ -885,9 +901,9 @@
       }
     },
     "node_modules/@esbuild/darwin-arm64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.5.tgz",
-      "integrity": "sha512-mvXGcKqqIqyKoxq26qEDPHJuBYUA5KizJncKOAf9eJQez+L9O+KfvNFu6nl7SCZ/gFb2QPaRqqmG0doSWlgkqw==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.10.tgz",
+      "integrity": "sha512-YSRRs2zOpwypck+6GL3wGXx2gNP7DXzetmo5pHXLrY/VIMsS59yKfjPizQ4lLt5vEI80M41gjm2BxrGZ5U+VMA==",
       "cpu": [
         "arm64"
       ],
@@ -901,9 +917,9 @@
       }
     },
     "node_modules/@esbuild/darwin-x64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.5.tgz",
-      "integrity": "sha512-Ly8cn6fGLNet19s0X4unjcniX24I0RqjPv+kurpXabZYSXGM4Pwpmf85WHJN3lAgB8GSth7s5A0r856S+4DyiA==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.10.tgz",
+      "integrity": "sha512-alfGtT+IEICKtNE54hbvPg13xGBe4GkVxyGWtzr+yHO7HIiRJppPDhOKq3zstTcVf8msXb/t4eavW3jCDpMSmA==",
       "cpu": [
         "x64"
       ],
@@ -917,9 +933,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.5.tgz",
-      "integrity": "sha512-GGDNnPWTmWE+DMchq1W8Sd0mUkL+APvJg3b11klSGUDvRXh70JqLAO56tubmq1s2cgpVCSKYywEiKBfju8JztQ==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.10.tgz",
+      "integrity": "sha512-dMtk1wc7FSH8CCkE854GyGuNKCewlh+7heYP/sclpOG6Cectzk14qdUIY5CrKDbkA/OczXq9WesqnPl09mj5dg==",
       "cpu": [
         "arm64"
       ],
@@ -933,9 +949,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-x64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.5.tgz",
-      "integrity": "sha512-1CCwDHnSSoA0HNwdfoNY0jLfJpd7ygaLAp5EHFos3VWJCRX9DMwWODf96s9TSse39Br7oOTLryRVmBoFwXbuuQ==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.10.tgz",
+      "integrity": "sha512-G5UPPspryHu1T3uX8WiOEUa6q6OlQh6gNl4CO4Iw5PS+Kg5bVggVFehzXBJY6X6RSOMS8iXDv2330VzaObm4Ag==",
       "cpu": [
         "x64"
       ],
@@ -949,9 +965,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.5.tgz",
-      "integrity": "sha512-lrWXLY/vJBzCPC51QN0HM71uWgIEpGSjSZZADQhq7DKhPcI6NH1IdzjfHkDQws2oNpJKpR13kv7/pFHBbDQDwQ==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.10.tgz",
+      "integrity": "sha512-j6gUW5aAaPgD416Hk9FHxn27On28H4eVI9rJ4az7oCGTFW48+LcgNDBN+9f8rKZz7EEowo889CPKyeaD0iw9Kg==",
       "cpu": [
         "arm"
       ],
@@ -965,9 +981,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.5.tgz",
-      "integrity": "sha512-o3vYippBmSrjjQUCEEiTZ2l+4yC0pVJD/Dl57WfPwwlvFkrxoSO7rmBZFii6kQB3Wrn/6GwJUPLU5t52eq2meA==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.10.tgz",
+      "integrity": "sha512-QxaouHWZ+2KWEj7cGJmvTIHVALfhpGxo3WLmlYfJ+dA5fJB6lDEIg+oe/0//FuyVHuS3l79/wyBxbHr0NgtxJQ==",
       "cpu": [
         "arm64"
       ],
@@ -981,9 +997,9 @@
       }
     },
     "node_modules/@esbuild/linux-ia32": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.5.tgz",
-      "integrity": "sha512-MkjHXS03AXAkNp1KKkhSKPOCYztRtK+KXDNkBa6P78F8Bw0ynknCSClO/ztGszILZtyO/lVKpa7MolbBZ6oJtQ==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.10.tgz",
+      "integrity": "sha512-4ub1YwXxYjj9h1UIZs2hYbnTZBtenPw5NfXCRgEkGb0b6OJ2gpkMvDqRDYIDRjRdWSe/TBiZltm3Y3Q8SN1xNg==",
       "cpu": [
         "ia32"
       ],
@@ -997,9 +1013,9 @@
       }
     },
     "node_modules/@esbuild/linux-loong64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.5.tgz",
-      "integrity": "sha512-42GwZMm5oYOD/JHqHska3Jg0r+XFb/fdZRX+WjADm3nLWLcIsN27YKtqxzQmGNJgu0AyXg4HtcSK9HuOk3v1Dw==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.10.tgz",
+      "integrity": "sha512-lo3I9k+mbEKoxtoIbM0yC/MZ1i2wM0cIeOejlVdZ3D86LAcFXFRdeuZmh91QJvUTW51bOK5W2BznGNIl4+mDaA==",
       "cpu": [
         "loong64"
       ],
@@ -1013,9 +1029,9 @@
       }
     },
     "node_modules/@esbuild/linux-mips64el": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.5.tgz",
-      "integrity": "sha512-kcjndCSMitUuPJobWCnwQ9lLjiLZUR3QLQmlgaBfMX23UEa7ZOrtufnRds+6WZtIS9HdTXqND4yH8NLoVVIkcg==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.10.tgz",
+      "integrity": "sha512-J4gH3zhHNbdZN0Bcr1QUGVNkHTdpijgx5VMxeetSk6ntdt+vR1DqGmHxQYHRmNb77tP6GVvD+K0NyO4xjd7y4A==",
       "cpu": [
         "mips64el"
       ],
@@ -1029,9 +1045,9 @@
       }
     },
     "node_modules/@esbuild/linux-ppc64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.5.tgz",
-      "integrity": "sha512-yJAxJfHVm0ZbsiljbtFFP1BQKLc8kUF6+17tjQ78QjqjAQDnhULWiTA6u0FCDmYT1oOKS9PzZ2z0aBI+Mcyj7Q==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.10.tgz",
+      "integrity": "sha512-tgT/7u+QhV6ge8wFMzaklOY7KqiyitgT1AUHMApau32ZlvTB/+efeCtMk4eXS+uEymYK249JsoiklZN64xt6oQ==",
       "cpu": [
         "ppc64"
       ],
@@ -1045,9 +1061,9 @@
       }
     },
     "node_modules/@esbuild/linux-riscv64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.5.tgz",
-      "integrity": "sha512-5u8cIR/t3gaD6ad3wNt1MNRstAZO+aNyBxu2We8X31bA8XUNyamTVQwLDA1SLoPCUehNCymhBhK3Qim1433Zag==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.10.tgz",
+      "integrity": "sha512-0f/spw0PfBMZBNqtKe5FLzBDGo0SKZKvMl5PHYQr3+eiSscfJ96XEknCe+JoOayybWUFQbcJTrk946i3j9uYZA==",
       "cpu": [
         "riscv64"
       ],
@@ -1061,9 +1077,9 @@
       }
     },
     "node_modules/@esbuild/linux-s390x": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.5.tgz",
-      "integrity": "sha512-Z6JrMyEw/EmZBD/OFEFpb+gao9xJ59ATsoTNlj39jVBbXqoZm4Xntu6wVmGPB/OATi1uk/DB+yeDPv2E8PqZGw==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.10.tgz",
+      "integrity": "sha512-pZFe0OeskMHzHa9U38g+z8Yx5FNCLFtUnJtQMpwhS+r4S566aK2ci3t4NCP4tjt6d5j5uo4h7tExZMjeKoehAA==",
       "cpu": [
         "s390x"
       ],
@@ -1077,9 +1093,9 @@
       }
     },
     "node_modules/@esbuild/linux-x64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.5.tgz",
-      "integrity": "sha512-psagl+2RlK1z8zWZOmVdImisMtrUxvwereIdyJTmtmHahJTKb64pAcqoPlx6CewPdvGvUKe2Jw+0Z/0qhSbG1A==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.10.tgz",
+      "integrity": "sha512-SpYNEqg/6pZYoc+1zLCjVOYvxfZVZj6w0KROZ3Fje/QrM3nfvT2llI+wmKSrWuX6wmZeTapbarvuNNK/qepSgA==",
       "cpu": [
         "x64"
       ],
@@ -1093,9 +1109,9 @@
       }
     },
     "node_modules/@esbuild/netbsd-x64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.5.tgz",
-      "integrity": "sha512-kL2l+xScnAy/E/3119OggX8SrWyBEcqAh8aOY1gr4gPvw76la2GlD4Ymf832UCVbmuWeTf2adkZDK+h0Z/fB4g==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.10.tgz",
+      "integrity": "sha512-ACbZ0vXy9zksNArWlk2c38NdKg25+L9pr/mVaj9SUq6lHZu/35nx2xnQVRGLrC1KKQqJKRIB0q8GspiHI3J80Q==",
       "cpu": [
         "x64"
       ],
@@ -1109,9 +1125,9 @@
       }
     },
     "node_modules/@esbuild/openbsd-x64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.5.tgz",
-      "integrity": "sha512-sPOfhtzFufQfTBgRnE1DIJjzsXukKSvZxloZbkJDG383q0awVAq600pc1nfqBcl0ice/WN9p4qLc39WhBShRTA==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.10.tgz",
+      "integrity": "sha512-PxcgvjdSjtgPMiPQrM3pwSaG4kGphP+bLSb+cihuP0LYdZv1epbAIecHVl5sD3npkfYBZ0ZnOjR878I7MdJDFg==",
       "cpu": [
         "x64"
       ],
@@ -1125,9 +1141,9 @@
       }
     },
     "node_modules/@esbuild/sunos-x64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.5.tgz",
-      "integrity": "sha512-dGZkBXaafuKLpDSjKcB0ax0FL36YXCvJNnztjKV+6CO82tTYVDSH2lifitJ29jxRMoUhgkg9a+VA/B03WK5lcg==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.10.tgz",
+      "integrity": "sha512-ZkIOtrRL8SEJjr+VHjmW0znkPs+oJXhlJbNwfI37rvgeMtk3sxOQevXPXjmAPZPigVTncvFqLMd+uV0IBSEzqA==",
       "cpu": [
         "x64"
       ],
@@ -1141,9 +1157,9 @@
       }
     },
     "node_modules/@esbuild/win32-arm64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.5.tgz",
-      "integrity": "sha512-dWVjD9y03ilhdRQ6Xig1NWNgfLtf2o/STKTS+eZuF90fI2BhbwD6WlaiCGKptlqXlURVB5AUOxUj09LuwKGDTg==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.10.tgz",
+      "integrity": "sha512-+Sa4oTDbpBfGpl3Hn3XiUe4f8TU2JF7aX8cOfqFYMMjXp6ma6NJDztl5FDG8Ezx0OjwGikIHw+iA54YLDNNVfw==",
       "cpu": [
         "arm64"
       ],
@@ -1157,9 +1173,9 @@
       }
     },
     "node_modules/@esbuild/win32-ia32": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.5.tgz",
-      "integrity": "sha512-4liggWIA4oDgUxqpZwrDhmEfAH4d0iljanDOK7AnVU89T6CzHon/ony8C5LeOdfgx60x5cnQJFZwEydVlYx4iw==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.10.tgz",
+      "integrity": "sha512-EOGVLK1oWMBXgfttJdPHDTiivYSjX6jDNaATeNOaCOFEVcfMjtbx7WVQwPSE1eIfCp/CaSF2nSrDtzc4I9f8TQ==",
       "cpu": [
         "ia32"
       ],
@@ -1173,9 +1189,9 @@
       }
     },
     "node_modules/@esbuild/win32-x64": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.5.tgz",
-      "integrity": "sha512-czTrygUsB/jlM8qEW5MD8bgYU2Xg14lo6kBDXW6HdxKjh8M5PzETGiSHaz9MtbXBYDloHNUAUW2tMiKW4KM9Mw==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.10.tgz",
+      "integrity": "sha512-whqLG6Sc70AbU73fFYvuYzaE4MNMBIlR1Y/IrUeOXFrWHxBEjjbZaQ3IXIQS8wJdAzue2GwYZCjOrgrU1oUHoA==",
       "cpu": [
         "x64"
       ],
@@ -1213,9 +1229,9 @@
       }
     },
     "node_modules/@eslint/eslintrc": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
-      "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+      "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
       "dev": true,
       "dependencies": {
         "ajv": "^6.12.4",
@@ -1236,21 +1252,21 @@
       }
     },
     "node_modules/@eslint/js": {
-      "version": "8.51.0",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz",
-      "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==",
+      "version": "8.56.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz",
+      "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==",
       "dev": true,
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       }
     },
     "node_modules/@humanwhocodes/config-array": {
-      "version": "0.11.11",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
-      "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
+      "version": "0.11.13",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
+      "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
       "dev": true,
       "dependencies": {
-        "@humanwhocodes/object-schema": "^1.2.1",
+        "@humanwhocodes/object-schema": "^2.0.1",
         "debug": "^4.1.1",
         "minimatch": "^3.0.5"
       },
@@ -1272,9 +1288,9 @@
       }
     },
     "node_modules/@humanwhocodes/object-schema": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
-      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
+      "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
       "dev": true
     },
     "node_modules/@isaacs/cliui": {
@@ -1709,9 +1725,9 @@
       }
     },
     "node_modules/@types/babel__core": {
-      "version": "7.20.2",
-      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz",
-      "integrity": "sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==",
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+      "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
       "dev": true,
       "dependencies": {
         "@babel/parser": "^7.20.7",
@@ -1722,18 +1738,18 @@
       }
     },
     "node_modules/@types/babel__generator": {
-      "version": "7.6.5",
-      "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.5.tgz",
-      "integrity": "sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w==",
+      "version": "7.6.7",
+      "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz",
+      "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==",
       "dev": true,
       "dependencies": {
         "@babel/types": "^7.0.0"
       }
     },
     "node_modules/@types/babel__template": {
-      "version": "7.4.2",
-      "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.2.tgz",
-      "integrity": "sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ==",
+      "version": "7.4.4",
+      "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+      "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
       "dev": true,
       "dependencies": {
         "@babel/parser": "^7.1.0",
@@ -1741,9 +1757,9 @@
       }
     },
     "node_modules/@types/babel__traverse": {
-      "version": "7.20.2",
-      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.2.tgz",
-      "integrity": "sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw==",
+      "version": "7.20.4",
+      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz",
+      "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==",
       "dev": true,
       "dependencies": {
         "@babel/types": "^7.20.7"
@@ -1823,9 +1839,9 @@
       }
     },
     "node_modules/@types/imagemin": {
-      "version": "8.0.4",
-      "resolved": "https://registry.npmjs.org/@types/imagemin/-/imagemin-8.0.4.tgz",
-      "integrity": "sha512-t7vady38h/FTQAxFe6gJvaTxjgi/uw54ZrDbqyKx3yOMPu3NQjQexCoLxBR03FRv0HcKJMV2MqGLeY7BuPl6/A==",
+      "version": "8.0.5",
+      "resolved": "https://registry.npmjs.org/@types/imagemin/-/imagemin-8.0.5.tgz",
+      "integrity": "sha512-tah3dm+5sG+fEDAz6CrQ5evuEaPX9K6DF3E5a01MPOKhA2oGBoC+oA5EJzSugB905sN4DE19EDzldT2Cld2g6Q==",
       "dev": true,
       "dependencies": {
         "@types/node": "*"
@@ -1882,9 +1898,9 @@
       "dev": true
     },
     "node_modules/@types/node": {
-      "version": "20.9.4",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.4.tgz",
-      "integrity": "sha512-wmyg8HUhcn6ACjsn8oKYjkN/zUzQeNtMy44weTJSM6p4MMzEOuKbA3OjJ267uPCOW7Xex9dyrNTful8XTQYoDA==",
+      "version": "20.10.4",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz",
+      "integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==",
       "devOptional": true,
       "dependencies": {
         "undici-types": "~5.26.4"
@@ -1902,9 +1918,9 @@
       "dev": true
     },
     "node_modules/@types/react": {
-      "version": "18.2.38",
-      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.38.tgz",
-      "integrity": "sha512-cBBXHzuPtQK6wNthuVMV6IjHAFkdl/FOPFIlkd81/Cd1+IqkHu/A+w4g43kaQQoYHik/ruaQBDL72HyCy1vuMw==",
+      "version": "18.2.46",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.46.tgz",
+      "integrity": "sha512-nNCvVBcZlvX4NU1nRRNV/mFl1nNRuTuslAJglQsq+8ldXe5Xv0Wd2f7WTE3jOxhLH2BFfiZGC6GCp+kHQbgG+w==",
       "dev": true,
       "dependencies": {
         "@types/prop-types": "*",
@@ -1952,22 +1968,22 @@
       "dev": true
     },
     "node_modules/@types/webextension-polyfill": {
-      "version": "0.10.4",
-      "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.10.4.tgz",
-      "integrity": "sha512-pvEIqAZEbJRzaqTaWq3xlUoMWa3+euZHHz+VZHCzHWW+jOf8qLOq9wXy38U+WiPG3108SJC/wNc1X6vPC5TcjQ==",
+      "version": "0.10.7",
+      "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.10.7.tgz",
+      "integrity": "sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==",
       "dev": true
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "6.7.5",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz",
-      "integrity": "sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==",
+      "version": "6.16.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.16.0.tgz",
+      "integrity": "sha512-O5f7Kv5o4dLWQtPX4ywPPa+v9G+1q1x8mz0Kr0pXUtKsevo+gIJHLkGc8RxaZWtP8RrhwhSNIWThnW42K9/0rQ==",
       "dev": true,
       "dependencies": {
         "@eslint-community/regexpp": "^4.5.1",
-        "@typescript-eslint/scope-manager": "6.7.5",
-        "@typescript-eslint/type-utils": "6.7.5",
-        "@typescript-eslint/utils": "6.7.5",
-        "@typescript-eslint/visitor-keys": "6.7.5",
+        "@typescript-eslint/scope-manager": "6.16.0",
+        "@typescript-eslint/type-utils": "6.16.0",
+        "@typescript-eslint/utils": "6.16.0",
+        "@typescript-eslint/visitor-keys": "6.16.0",
         "debug": "^4.3.4",
         "graphemer": "^1.4.0",
         "ignore": "^5.2.4",
@@ -1993,13 +2009,13 @@
       }
     },
     "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
-      "version": "6.7.5",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz",
-      "integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==",
+      "version": "6.16.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz",
+      "integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "6.7.5",
-        "@typescript-eslint/visitor-keys": "6.7.5"
+        "@typescript-eslint/types": "6.16.0",
+        "@typescript-eslint/visitor-keys": "6.16.0"
       },
       "engines": {
         "node": "^16.0.0 || >=18.0.0"
@@ -2010,9 +2026,9 @@
       }
     },
     "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": {
-      "version": "6.7.5",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz",
-      "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==",
+      "version": "6.16.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz",
+      "integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==",
       "dev": true,
       "engines": {
         "node": "^16.0.0 || >=18.0.0"
@@ -2023,12 +2039,12 @@
       }
     },
     "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
-      "version": "6.7.5",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz",
-      "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==",
+      "version": "6.16.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz",
+      "integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "6.7.5",
+        "@typescript-eslint/types": "6.16.0",
         "eslint-visitor-keys": "^3.4.1"
       },
       "engines": {
@@ -2087,13 +2103,13 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils": {
-      "version": "6.7.5",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz",
-      "integrity": "sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==",
+      "version": "6.16.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.16.0.tgz",
+      "integrity": "sha512-ThmrEOcARmOnoyQfYkHw/DX2SEYBalVECmoldVuH6qagKROp/jMnfXpAU/pAIWub9c4YTxga+XwgAkoA0pxfmg==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/typescript-estree": "6.7.5",
-        "@typescript-eslint/utils": "6.7.5",
+        "@typescript-eslint/typescript-estree": "6.16.0",
+        "@typescript-eslint/utils": "6.16.0",
         "debug": "^4.3.4",
         "ts-api-utils": "^1.0.1"
       },
@@ -2114,9 +2130,9 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": {
-      "version": "6.7.5",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz",
-      "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==",
+      "version": "6.16.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz",
+      "integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==",
       "dev": true,
       "engines": {
         "node": "^16.0.0 || >=18.0.0"
@@ -2127,16 +2143,17 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": {
-      "version": "6.7.5",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz",
-      "integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==",
+      "version": "6.16.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz",
+      "integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "6.7.5",
-        "@typescript-eslint/visitor-keys": "6.7.5",
+        "@typescript-eslint/types": "6.16.0",
+        "@typescript-eslint/visitor-keys": "6.16.0",
         "debug": "^4.3.4",
         "globby": "^11.1.0",
         "is-glob": "^4.0.3",
+        "minimatch": "9.0.3",
         "semver": "^7.5.4",
         "ts-api-utils": "^1.0.1"
       },
@@ -2154,12 +2171,12 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": {
-      "version": "6.7.5",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz",
-      "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==",
+      "version": "6.16.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz",
+      "integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "6.7.5",
+        "@typescript-eslint/types": "6.16.0",
         "eslint-visitor-keys": "^3.4.1"
       },
       "engines": {
@@ -2170,6 +2187,30 @@
         "url": "https://opencollective.com/typescript-eslint"
       }
     },
+    "node_modules/@typescript-eslint/type-utils/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": {
+      "version": "9.0.3",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+      "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
     "node_modules/@typescript-eslint/types": {
       "version": "6.7.3",
       "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.3.tgz",
@@ -2213,17 +2254,17 @@
       }
     },
     "node_modules/@typescript-eslint/utils": {
-      "version": "6.7.5",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.5.tgz",
-      "integrity": "sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==",
+      "version": "6.16.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.16.0.tgz",
+      "integrity": "sha512-T83QPKrBm6n//q9mv7oiSvy/Xq/7Hyw9SzSEhMHJwznEmQayfBM87+oAlkNAMEO7/MjIwKyOHgBJbxB0s7gx2A==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.4.0",
         "@types/json-schema": "^7.0.12",
         "@types/semver": "^7.5.0",
-        "@typescript-eslint/scope-manager": "6.7.5",
-        "@typescript-eslint/types": "6.7.5",
-        "@typescript-eslint/typescript-estree": "6.7.5",
+        "@typescript-eslint/scope-manager": "6.16.0",
+        "@typescript-eslint/types": "6.16.0",
+        "@typescript-eslint/typescript-estree": "6.16.0",
         "semver": "^7.5.4"
       },
       "engines": {
@@ -2238,13 +2279,13 @@
       }
     },
     "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": {
-      "version": "6.7.5",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz",
-      "integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==",
+      "version": "6.16.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz",
+      "integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "6.7.5",
-        "@typescript-eslint/visitor-keys": "6.7.5"
+        "@typescript-eslint/types": "6.16.0",
+        "@typescript-eslint/visitor-keys": "6.16.0"
       },
       "engines": {
         "node": "^16.0.0 || >=18.0.0"
@@ -2255,9 +2296,9 @@
       }
     },
     "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": {
-      "version": "6.7.5",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz",
-      "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==",
+      "version": "6.16.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz",
+      "integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==",
       "dev": true,
       "engines": {
         "node": "^16.0.0 || >=18.0.0"
@@ -2268,16 +2309,17 @@
       }
     },
     "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": {
-      "version": "6.7.5",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz",
-      "integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==",
+      "version": "6.16.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz",
+      "integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "6.7.5",
-        "@typescript-eslint/visitor-keys": "6.7.5",
+        "@typescript-eslint/types": "6.16.0",
+        "@typescript-eslint/visitor-keys": "6.16.0",
         "debug": "^4.3.4",
         "globby": "^11.1.0",
         "is-glob": "^4.0.3",
+        "minimatch": "9.0.3",
         "semver": "^7.5.4",
         "ts-api-utils": "^1.0.1"
       },
@@ -2295,12 +2337,12 @@
       }
     },
     "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": {
-      "version": "6.7.5",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz",
-      "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==",
+      "version": "6.16.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz",
+      "integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "6.7.5",
+        "@typescript-eslint/types": "6.16.0",
         "eslint-visitor-keys": "^3.4.1"
       },
       "engines": {
@@ -2311,6 +2353,30 @@
         "url": "https://opencollective.com/typescript-eslint"
       }
     },
+    "node_modules/@typescript-eslint/utils/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/utils/node_modules/minimatch": {
+      "version": "9.0.3",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+      "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
     "node_modules/@typescript-eslint/visitor-keys": {
       "version": "6.7.3",
       "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.3.tgz",
@@ -2899,9 +2965,9 @@
       "dev": true
     },
     "node_modules/babel-plugin-jsx-dom-expressions": {
-      "version": "0.37.2",
-      "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.37.2.tgz",
-      "integrity": "sha512-u3VKB+On86cYSLAbw9j0m0X8ZejL4MR7oG7TRlrMQ/y1mauR/ZpM2xkiOPZEUlzHLo1GYGlTdP9s5D3XuA6iSQ==",
+      "version": "0.37.9",
+      "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.37.9.tgz",
+      "integrity": "sha512-6w+zs2i14fVanj4e1hXCU5cp+x0U0LJ5jScknpMZZUteHhwFRGJflHMVJ+xAcW7ku41FYjr7DgtK9mnc2SXlJg==",
       "dev": true,
       "dependencies": {
         "@babel/helper-module-imports": "7.18.6",
@@ -2927,12 +2993,12 @@
       }
     },
     "node_modules/babel-preset-solid": {
-      "version": "1.8.0",
-      "resolved": "https://registry.npmjs.org/babel-preset-solid/-/babel-preset-solid-1.8.0.tgz",
-      "integrity": "sha512-TCsC3kTNYRi+0/mHYFvC2VsSq++GZPFyHF3QTP7L37TXaVFD0HZQPyLQnf+waOGPHQuAhKXo0GEQziquSwBAVw==",
+      "version": "1.8.6",
+      "resolved": "https://registry.npmjs.org/babel-preset-solid/-/babel-preset-solid-1.8.6.tgz",
+      "integrity": "sha512-Ened42CHjU4EFkvNeS042/3Pm21yvMWn8p4G4ddzQTlKaMwSGGD1VciA/e7EshBVHJCcBj9vHiUd/r3A4qLPZA==",
       "dev": true,
       "dependencies": {
-        "babel-plugin-jsx-dom-expressions": "^0.37.0"
+        "babel-plugin-jsx-dom-expressions": "^0.37.9"
       },
       "peerDependencies": {
         "@babel/core": "^7.0.0"
@@ -3401,9 +3467,9 @@
       }
     },
     "node_modules/browserslist": {
-      "version": "4.21.11",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.11.tgz",
-      "integrity": "sha512-xn1UXOKUz7DjdGlg9RrUr0GGiWzI97UQJnugHtH0OLDfJB7jMgoIkYvRIEO1l9EeEERVqeqLYOcFBW9ldjypbQ==",
+      "version": "4.22.2",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz",
+      "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==",
       "dev": true,
       "funding": [
         {
@@ -3420,9 +3486,9 @@
         }
       ],
       "dependencies": {
-        "caniuse-lite": "^1.0.30001538",
-        "electron-to-chromium": "^1.4.526",
-        "node-releases": "^2.0.13",
+        "caniuse-lite": "^1.0.30001565",
+        "electron-to-chromium": "^1.4.601",
+        "node-releases": "^2.0.14",
         "update-browserslist-db": "^1.0.13"
       },
       "bin": {
@@ -3598,9 +3664,9 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001539",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001539.tgz",
-      "integrity": "sha512-hfS5tE8bnNiNvEOEkm8HElUHroYwlqMMENEzELymy77+tJ6m+gA2krtHl5hxJaj71OlpC2cHZbdSMX1/YEqEkA==",
+      "version": "1.0.30001568",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001568.tgz",
+      "integrity": "sha512-vSUkH84HontZJ88MiNrOau1EBrCqEQYgkC5gIySiDlpsm8sGVrhU7Kx4V6h0tnqaHzIHZv08HlJIwPbL4XL9+A==",
       "dev": true,
       "funding": [
         {
@@ -4529,9 +4595,9 @@
       "dev": true
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.4.529",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.529.tgz",
-      "integrity": "sha512-6uyPyXTo8lkv8SWAmjKFbG42U073TXlzD4R8rW3EzuznhFS2olCIAfjjQtV2dV2ar/vRF55KUd3zQYnCB0dd3A==",
+      "version": "1.4.609",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.609.tgz",
+      "integrity": "sha512-ihiCP7PJmjoGNuLpl7TjNA8pCQWu09vGyjlPYw1Rqww4gvNuCcmvl+44G+2QyJ6S2K4o+wbTS++Xz0YN8Q9ERw==",
       "dev": true
     },
     "node_modules/emoji-regex": {
@@ -4673,9 +4739,9 @@
       }
     },
     "node_modules/esbuild": {
-      "version": "0.19.5",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.5.tgz",
-      "integrity": "sha512-bUxalY7b1g8vNhQKdB24QDmHeY4V4tw/s6Ak5z+jJX9laP5MoQseTOMemAr0gxssjNcH0MCViG8ONI2kksvfFQ==",
+      "version": "0.19.10",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.10.tgz",
+      "integrity": "sha512-S1Y27QGt/snkNYrRcswgRFqZjaTG5a5xM3EQo97uNBnH505pdzSNe/HLBq1v0RO7iK/ngdbhJB6mDAp0OK+iUA==",
       "dev": true,
       "hasInstallScript": true,
       "bin": {
@@ -4685,28 +4751,29 @@
         "node": ">=12"
       },
       "optionalDependencies": {
-        "@esbuild/android-arm": "0.19.5",
-        "@esbuild/android-arm64": "0.19.5",
-        "@esbuild/android-x64": "0.19.5",
-        "@esbuild/darwin-arm64": "0.19.5",
-        "@esbuild/darwin-x64": "0.19.5",
-        "@esbuild/freebsd-arm64": "0.19.5",
-        "@esbuild/freebsd-x64": "0.19.5",
-        "@esbuild/linux-arm": "0.19.5",
-        "@esbuild/linux-arm64": "0.19.5",
-        "@esbuild/linux-ia32": "0.19.5",
-        "@esbuild/linux-loong64": "0.19.5",
-        "@esbuild/linux-mips64el": "0.19.5",
-        "@esbuild/linux-ppc64": "0.19.5",
-        "@esbuild/linux-riscv64": "0.19.5",
-        "@esbuild/linux-s390x": "0.19.5",
-        "@esbuild/linux-x64": "0.19.5",
-        "@esbuild/netbsd-x64": "0.19.5",
-        "@esbuild/openbsd-x64": "0.19.5",
-        "@esbuild/sunos-x64": "0.19.5",
-        "@esbuild/win32-arm64": "0.19.5",
-        "@esbuild/win32-ia32": "0.19.5",
-        "@esbuild/win32-x64": "0.19.5"
+        "@esbuild/aix-ppc64": "0.19.10",
+        "@esbuild/android-arm": "0.19.10",
+        "@esbuild/android-arm64": "0.19.10",
+        "@esbuild/android-x64": "0.19.10",
+        "@esbuild/darwin-arm64": "0.19.10",
+        "@esbuild/darwin-x64": "0.19.10",
+        "@esbuild/freebsd-arm64": "0.19.10",
+        "@esbuild/freebsd-x64": "0.19.10",
+        "@esbuild/linux-arm": "0.19.10",
+        "@esbuild/linux-arm64": "0.19.10",
+        "@esbuild/linux-ia32": "0.19.10",
+        "@esbuild/linux-loong64": "0.19.10",
+        "@esbuild/linux-mips64el": "0.19.10",
+        "@esbuild/linux-ppc64": "0.19.10",
+        "@esbuild/linux-riscv64": "0.19.10",
+        "@esbuild/linux-s390x": "0.19.10",
+        "@esbuild/linux-x64": "0.19.10",
+        "@esbuild/netbsd-x64": "0.19.10",
+        "@esbuild/openbsd-x64": "0.19.10",
+        "@esbuild/sunos-x64": "0.19.10",
+        "@esbuild/win32-arm64": "0.19.10",
+        "@esbuild/win32-ia32": "0.19.10",
+        "@esbuild/win32-x64": "0.19.10"
       }
     },
     "node_modules/escalade": {
@@ -4731,18 +4798,19 @@
       }
     },
     "node_modules/eslint": {
-      "version": "8.51.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz",
-      "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==",
+      "version": "8.56.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz",
+      "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.2.0",
         "@eslint-community/regexpp": "^4.6.1",
-        "@eslint/eslintrc": "^2.1.2",
-        "@eslint/js": "8.51.0",
-        "@humanwhocodes/config-array": "^0.11.11",
+        "@eslint/eslintrc": "^2.1.4",
+        "@eslint/js": "8.56.0",
+        "@humanwhocodes/config-array": "^0.11.13",
         "@humanwhocodes/module-importer": "^1.0.1",
         "@nodelib/fs.walk": "^1.2.8",
+        "@ungap/structured-clone": "^1.2.0",
         "ajv": "^6.12.4",
         "chalk": "^4.0.0",
         "cross-spawn": "^7.0.2",
@@ -5760,9 +5828,9 @@
       }
     },
     "node_modules/globals": {
-      "version": "13.22.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz",
-      "integrity": "sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==",
+      "version": "13.23.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz",
+      "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==",
       "dev": true,
       "dependencies": {
         "type-fest": "^0.20.2"
@@ -8222,9 +8290,9 @@
       }
     },
     "node_modules/node-releases": {
-      "version": "2.0.13",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
-      "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
+      "version": "2.0.14",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
+      "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
       "dev": true
     },
     "node_modules/nopt": {
@@ -9065,9 +9133,9 @@
       }
     },
     "node_modules/prettier": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz",
-      "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz",
+      "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==",
       "dev": true,
       "bin": {
         "prettier": "bin/prettier.cjs"
@@ -11057,9 +11125,9 @@
       }
     },
     "node_modules/seroval": {
-      "version": "0.12.3",
-      "resolved": "https://registry.npmjs.org/seroval/-/seroval-0.12.3.tgz",
-      "integrity": "sha512-5WDeMpv7rmEylsypRj1iwRVHE/QLsMLiZ+9savlNNQEVdgGia1iRMb7qyaAagY0wu/7+QTe6d2wldk/lgaLb6g==",
+      "version": "0.15.1",
+      "resolved": "https://registry.npmjs.org/seroval/-/seroval-0.15.1.tgz",
+      "integrity": "sha512-OPVtf0qmeC7RW+ScVX+7aOS+xoIM7pWcZ0jOWg2aTZigCydgRB04adfteBRbecZnnrO1WuGQ+C3tLeBBzX2zSQ==",
       "engines": {
         "node": ">=10"
       }
@@ -11216,12 +11284,12 @@
       }
     },
     "node_modules/solid-js": {
-      "version": "1.8.5",
-      "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.8.5.tgz",
-      "integrity": "sha512-xvtJvzJzWbsn35oKFhW9kNwaxG1Z/YLMsDp4tLVcYZTMPzvzQ8vEZuyDQ6nt7xDArVgZJ7TUFrJUwrui/oq53A==",
+      "version": "1.8.7",
+      "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.8.7.tgz",
+      "integrity": "sha512-9dzrSVieh2zj3SnJ02II6xZkonR6c+j/91b7XZUNcC6xSaldlqjjGh98F1fk5cRJ8ZTkzqF5fPIWDxEOs6QZXA==",
       "dependencies": {
         "csstype": "^3.1.0",
-        "seroval": "^0.12.0"
+        "seroval": "^0.15.1"
       }
     },
     "node_modules/solid-refresh": {
@@ -11262,15 +11330,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/source-map": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/source-map-js": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
@@ -11279,16 +11338,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/source-map-support": {
-      "version": "0.5.21",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
-      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
-      "dev": true,
-      "dependencies": {
-        "buffer-from": "^1.0.0",
-        "source-map": "^0.6.0"
-      }
-    },
     "node_modules/spdx-correct": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
@@ -12465,14 +12514,13 @@
       }
     },
     "node_modules/tsx": {
-      "version": "4.1.3",
-      "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.1.3.tgz",
-      "integrity": "sha512-DLiTy1eri4nhqgVVy+15YKC6Ij2BMFxGdDMkVrSDkNuISUJLv7n0NgZpFLpdM+qmwXar34XllgYi4cxkNMbDwQ==",
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.6.2.tgz",
+      "integrity": "sha512-QPpBdJo+ZDtqZgAnq86iY/PD2KYCUPSUGIunHdGwyII99GKH+f3z3FZ8XNFLSGQIA4I365ui8wnQpl8OKLqcsg==",
       "dev": true,
       "dependencies": {
         "esbuild": "~0.18.20",
-        "get-tsconfig": "^4.7.2",
-        "source-map-support": "^0.5.21"
+        "get-tsconfig": "^4.7.2"
       },
       "bin": {
         "tsx": "dist/cli.mjs"
@@ -12990,9 +13038,9 @@
       "dev": true
     },
     "node_modules/typescript": {
-      "version": "5.2.2",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
-      "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
+      "version": "5.3.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
+      "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
       "devOptional": true,
       "bin": {
         "tsc": "bin/tsc",
@@ -13893,9 +13941,9 @@
       }
     },
     "node_modules/vite": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz",
-      "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==",
+      "version": "4.5.1",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz",
+      "integrity": "sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==",
       "dependencies": {
         "esbuild": "^0.18.10",
         "postcss": "^8.4.27",
@@ -13979,28 +14027,28 @@
       }
     },
     "node_modules/vite-plugin-solid": {
-      "version": "2.7.2",
-      "resolved": "https://registry.npmjs.org/vite-plugin-solid/-/vite-plugin-solid-2.7.2.tgz",
-      "integrity": "sha512-GV2SMLAibOoXe76i02AsjAg7sbm/0lngBlERvJKVN67HOrJsHcWgkt0R6sfGLDJuFkv2aBe14Zm4vJcNME+7zw==",
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/vite-plugin-solid/-/vite-plugin-solid-2.8.0.tgz",
+      "integrity": "sha512-n5FAm7ZmTl94VWUoiJCgG7bouF2NlC9CA1wY/qbVnkFbYDWk++bFWyNoU48aLJ+lMtzNeYzJypJXOHzFKxL9xA==",
       "dev": true,
       "dependencies": {
-        "@babel/core": "^7.23.0",
-        "@babel/preset-typescript": "^7.23.0",
-        "@types/babel__core": "^7.20.2",
-        "babel-preset-solid": "^1.8.0",
+        "@babel/core": "^7.23.3",
+        "@babel/preset-typescript": "^7.23.3",
+        "@types/babel__core": "^7.20.4",
+        "babel-preset-solid": "^1.8.4",
         "merge-anything": "^5.1.7",
         "solid-refresh": "^0.5.3",
-        "vitefu": "^0.2.4"
+        "vitefu": "^0.2.5"
       },
       "peerDependencies": {
         "solid-js": "^1.7.2",
-        "vite": "^3.0.0 || ^4.0.0"
+        "vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
       }
     },
     "node_modules/vite-plugin-static-copy": {
-      "version": "0.17.0",
-      "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-0.17.0.tgz",
-      "integrity": "sha512-2HpNbHfDt8SDy393AGXh9llHkc8FJMQkI8s3T5WsH3SWLMO+f5cFIyPErl4yGKU9Uh3Vaqsd4lHZYTf042fQ2A==",
+      "version": "0.17.1",
+      "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-0.17.1.tgz",
+      "integrity": "sha512-9h3iaVs0bqnqZOM5YHJXGHqdC5VAVlTZ2ARYsuNpzhEJUHmFqXY7dAK4ZFpjEQ4WLFKcaN8yWbczr81n01U4sQ==",
       "dev": true,
       "dependencies": {
         "chokidar": "^3.5.3",
@@ -14012,7 +14060,7 @@
         "node": "^14.18.0 || >=16.0.0"
       },
       "peerDependencies": {
-        "vite": "^3.0.0 || ^4.0.0"
+        "vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
       }
     },
     "node_modules/vite/node_modules/@esbuild/android-arm": {
@@ -14382,12 +14430,12 @@
       }
     },
     "node_modules/vitefu": {
-      "version": "0.2.4",
-      "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.4.tgz",
-      "integrity": "sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==",
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz",
+      "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==",
       "dev": true,
       "peerDependencies": {
-        "vite": "^3.0.0 || ^4.0.0"
+        "vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
       },
       "peerDependenciesMeta": {
         "vite": {
diff --git a/package.json b/package.json
index 568f9ff9..e26469c3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "web-scrobbler",
-  "version": "3.2.0",
+  "version": "3.3.0",
   "author": "David Šabata <posta@davidsabata.cz>",
   "contributors": [
     "@mountainash (https://mountainash.id.au/)"
@@ -32,26 +32,26 @@
     "@web-scrobbler/metadata-filter": "3.0.2",
     "blueimp-md5": "2.19.0",
     "stylelint": "15.11.0",
-    "vite": "4.5.0",
+    "vite": "4.5.1",
     "webextension-polyfill": "0.10.0"
   },
   "devDependencies": {
     "@types/archiver": "6.0.2",
     "@types/blueimp-md5": "2.18.2",
     "@types/fs-extra": "11.0.3",
-    "@types/imagemin": "8.0.4",
+    "@types/imagemin": "8.0.5",
     "@types/imagemin-jpegtran": "5.0.4",
-    "@types/node": "20.9.4",
-    "@types/react": "18.2.38",
-    "@types/webextension-polyfill": "0.10.4",
-    "@typescript-eslint/eslint-plugin": "6.7.5",
+    "@types/node": "20.10.4",
+    "@types/react": "18.2.46",
+    "@types/webextension-polyfill": "0.10.7",
+    "@typescript-eslint/eslint-plugin": "6.16.0",
     "@web-scrobbler/eslint-config": "3.0.0",
     "@web-scrobbler/stylelint-config": "1.0.1",
     "archiver": "6.0.1",
     "canvas": "2.11.2",
     "chokidar": "3.5.3",
-    "esbuild": "0.19.5",
-    "eslint": "8.51.0",
+    "esbuild": "0.19.10",
+    "eslint": "8.56.0",
     "eslint-plugin-react": "7.33.2",
     "eslint-plugin-solid": "0.13.0",
     "eslint-plugin-tsdoc": "0.2.17",
@@ -60,18 +60,18 @@
     "imagemin": "8.0.1",
     "imagemin-jpegtran": "7.0.0",
     "imagemin-pngquant": "9.0.2",
-    "prettier": "3.0.3",
+    "prettier": "3.1.1",
     "prettier-config-web-scrobbler": "0.1.0",
     "remark": "15.0.1",
     "remark-cli": "12.0.0",
     "remark-preset-lint-recommended": "6.1.3",
     "sass": "1.69.5",
-    "solid-js": "1.8.5",
-    "tsx": "4.1.3",
-    "typescript": "5.2.2",
+    "solid-js": "1.8.7",
+    "tsx": "4.6.2",
+    "typescript": "5.3.3",
     "vite-plugin-conditional-compiler": "0.2.1",
-    "vite-plugin-solid": "2.7.2",
-    "vite-plugin-static-copy": "0.17.0",
+    "vite-plugin-solid": "2.8.0",
+    "vite-plugin-static-copy": "0.17.1",
     "vitest": "0.34.6"
   },
   "engines": {
diff --git a/src/connectors/buymusicclub.ts b/src/connectors/buymusicclub.ts
new file mode 100644
index 00000000..65dc29a3
--- /dev/null
+++ b/src/connectors/buymusicclub.ts
@@ -0,0 +1,17 @@
+export {};
+
+Connector.playerSelector = '#player';
+
+Connector.playButtonSelector = '#play-button';
+
+Connector.artistSelector = '#track-artist';
+
+Connector.albumSelector = '#track-album';
+
+Connector.trackSelector = '#track-title';
+
+Connector.trackArtSelector = '#track-art';
+
+Connector.durationSelector = '#duration';
+
+Connector.currentTimeSelector = '#time';
diff --git a/src/connectors/joox.ts b/src/connectors/joox.ts
index 2599b4cc..0d07e2ee 100644
--- a/src/connectors/joox.ts
+++ b/src/connectors/joox.ts
@@ -1,23 +1,9 @@
 export {};
 
-const playerSelector = '.kIpMXu';
-const artistSelector = `${playerSelector} .kOwKMw a`;
-
 Connector.useMediaSessionApi();
 
-Connector.playerSelector = playerSelector;
-
-Connector.trackSelector = '.xXMwE';
-
-Connector.trackArtSelector = `${playerSelector} .XVHIE img`;
-
-Connector.getArtist = () => {
-	const artistNodes = document.querySelectorAll(artistSelector);
-	return Util.joinArtists(Array.from(artistNodes));
-};
+Connector.playerSelector = '#__next > div:nth-child(2) > div:nth-child(2)';
 
 Connector.currentTimeSelector = '#currentTime';
 
-Connector.durationSelector = '.GeFxq';
-
 Connector.playButtonSelector = '.playerIcon--play';
diff --git a/src/connectors/kexp.ts b/src/connectors/kexp.ts
index 02c9f596..6f921e07 100644
--- a/src/connectors/kexp.ts
+++ b/src/connectors/kexp.ts
@@ -1,5 +1,11 @@
 export {};
 
+const filter = MetadataFilter.createFilter({
+	artist: replaceSmartQuotes,
+	track: replaceSmartQuotes,
+	album: replaceSmartQuotes,
+});
+
 Connector.playerSelector = '.Player';
 
 Connector.artistTrackSelector = '.Player-title';
@@ -12,3 +18,9 @@ Connector.isTrackArtDefault = (url) => url?.includes('default');
 
 Connector.isPlaying = () =>
 	Util.hasElementClass(Connector.playerSelector, 'Player--playing');
+
+Connector.applyFilter(filter);
+
+function replaceSmartQuotes(text: string) {
+	return text.replace(/[\u2018\u2019]/g, "'").replace(/[\u201c\u201d]/g, '"');
+}
diff --git a/src/connectors/overcast.ts b/src/connectors/overcast.ts
new file mode 100644
index 00000000..02801a02
--- /dev/null
+++ b/src/connectors/overcast.ts
@@ -0,0 +1,34 @@
+export {};
+
+Connector.playerSelector = '.pure-u-1';
+
+Connector.artistSelector = `${Connector.playerSelector} h3`;
+
+Connector.trackSelector = `${Connector.playerSelector} h2`;
+
+Connector.trackArtSelector = `${Connector.playerSelector} .fullart`;
+
+Connector.playButtonSelector = '#playpausebutton_playicon';
+
+Connector.currentTimeSelector = '#timeelapsed';
+
+Connector.remainingTimeSelector = '#timeremaining';
+
+Connector.isPodcast = () => true;
+
+const filter = MetadataFilter.createFilter({
+	track: trimPodcaster,
+});
+
+Connector.applyFilter(filter);
+
+function trimPodcaster(track: string) {
+	const separator = ': ';
+	const chunks = track.split(separator);
+	const artist = Connector.getArtist();
+	const trackArtist = chunks.shift();
+	if (artist?.toLowerCase() === trackArtist?.toLowerCase()) {
+		return chunks.join(separator);
+	}
+	return track;
+}
diff --git a/src/connectors/radio.de.ts b/src/connectors/radio.de.ts
new file mode 100644
index 00000000..2d68e0af
--- /dev/null
+++ b/src/connectors/radio.de.ts
@@ -0,0 +1,15 @@
+export {};
+
+Connector.playerSelector = 'div.player-nav-holder';
+
+Connector.getArtistTrack = () => {
+	const text = Util.getTextFromSelectors('span');
+	const m = text?.match(/(.*?) - (.*?) auf (.*?)/);
+	if (m && m.length === 4) {
+		return { artist: m[1], track: m[2] };
+	}
+	return null;
+};
+
+Connector.isPlaying = () =>
+	Util.getAttrFromSelectors('.player_playbutton', 'title') !== 'Wiedergabe';
diff --git a/src/connectors/radiocidade.ts b/src/connectors/radiocidade.ts
new file mode 100644
index 00000000..d29150e6
--- /dev/null
+++ b/src/connectors/radiocidade.ts
@@ -0,0 +1,11 @@
+export {};
+
+Connector.playerSelector = '.musica-info-total';
+
+Connector.artistSelector = '.nome-artista';
+
+Connector.trackSelector = '.nome-musica';
+
+Connector.trackArtSelector = '#capa-album';
+
+Connector.isPlaying = () => Util.hasElementClass('#botao-play', 'tocando');
diff --git a/src/connectors/radiostudent.ts b/src/connectors/radiostudent.ts
new file mode 100644
index 00000000..52ead07b
--- /dev/null
+++ b/src/connectors/radiostudent.ts
@@ -0,0 +1,4 @@
+export {};
+
+Connector.playerSelector = '#icecast_list';
+Connector.artistTrackSelector = '#icecast_list > ul > li > p';
diff --git a/src/connectors/rpfm.ts b/src/connectors/rpfm.ts
new file mode 100644
index 00000000..bca1218d
--- /dev/null
+++ b/src/connectors/rpfm.ts
@@ -0,0 +1,40 @@
+export {};
+
+interface Property {
+	[key: string]: string;
+}
+
+const props: Property = {
+	trackSelector: '.radio-current-track',
+	artistSelector: '.radio-current-artist',
+	trackArtSelector: '.radio-current-cover',
+	durationSelector: '.track-time-duration',
+	currentTimeSelector: '.track-time-position',
+};
+
+Connector.playerSelector = '.app-player';
+
+for (const prop in props) {
+	const selector = props[prop];
+	Object.defineProperty(Connector, prop, {
+		get: () => `${getCurrentContext()} ${selector}`,
+	});
+}
+
+Connector.isTrackArtDefault = (url) => url?.includes('no-cover');
+
+Connector.isPlaying = () =>
+	Util.getDataFromSelectors('.app-player', 'status') === 'play';
+
+Connector.isStateChangeAllowed = () => {
+	const artist = Connector.getArtist();
+	return artist !== null && artist !== 'Реклама';
+};
+
+function getCurrentContext(): string {
+	const single = Util.hasElementClass(
+		Connector.playerSelector,
+		'single-player',
+	);
+	return single ? '.app-player-panel' : '#broadcast-panel';
+}
diff --git a/src/connectors/vk-save.ts b/src/connectors/vk-save.ts
new file mode 100644
index 00000000..22e15910
--- /dev/null
+++ b/src/connectors/vk-save.ts
@@ -0,0 +1,13 @@
+export {};
+
+Connector.playerSelector = '.popup_player_wrapper > .popup_player_content';
+
+Connector.artistSelector = '.info_wr > .author > a';
+
+Connector.trackSelector = '.info_wr > .info > .title';
+
+Connector.currentTimeSelector = '.durations_wrap > .durations_start';
+
+Connector.remainingTimeSelector = '.durations_wrap > .durations_end';
+
+Connector.playButtonSelector = '.footer_player > .footer_play';
diff --git a/src/connectors/youtube-music.ts b/src/connectors/youtube-music.ts
index 2e2e1d5e..a42496a4 100644
--- a/src/connectors/youtube-music.ts
+++ b/src/connectors/youtube-music.ts
@@ -104,12 +104,14 @@ Connector.isPlaying = () => {
 };
 
 Connector.getUniqueID = () => {
-	const videoUrl = Util.getAttrFromSelectors('.yt-uix-sessionlink', 'href');
+	const uniqueId = new URLSearchParams(window.location.search).get('v');
 
-	if (videoUrl) {
-		return Util.getYtVideoIdFromUrl(videoUrl);
+	if (uniqueId) {
+		return uniqueId;
 	}
-	return null;
+
+	const videoUrl = Util.getAttrFromSelectors('.yt-uix-sessionlink', 'href');
+	return Util.getYtVideoIdFromUrl(videoUrl);
 };
 
 Connector.isScrobblingAllowed = () => !Util.isElementVisible(adSelector);
diff --git a/src/core/connectors.ts b/src/core/connectors.ts
index 0c9074fe..07d8dfc1 100644
--- a/src/core/connectors.ts
+++ b/src/core/connectors.ts
@@ -39,6 +39,12 @@ export default <ConnectorMeta[]>[
 		id: 'bndcmpr',
 		allFrames: true,
 	},
+	{
+		label: 'Buy Music Club',
+		matches: ['*://www.buymusic.club/*'],
+		js: 'buymusicclub.js',
+		id: 'buymusicclub',
+	},
 	{
 		label: 'Pandora',
 		matches: ['*://www.pandora.com/*'],
@@ -138,6 +144,17 @@ export default <ConnectorMeta[]>[
 		js: '8tracks.js',
 		id: '8tracks',
 	},
+	{
+		label: 'Radio Cidade',
+		matches: [
+			'*://radiocidade.fm/player/*',
+			'*://play.radiomania.com.br/*',
+			'*://*.melodia.com.br/*',
+			'*://jb.fm/player/*',
+		],
+		js: 'radiocidade.js',
+		id: 'radiocidade',
+	},
 	{
 		label: 'Radio Nova',
 		matches: ['*://www.nova.fr/*'],
@@ -150,6 +167,12 @@ export default <ConnectorMeta[]>[
 		js: 'radioplus.js',
 		id: 'radioplus',
 	},
+	{
+		label: 'Радио Premium',
+		matches: ['*://rpfm.ru/*'],
+		js: 'rpfm.js',
+		id: 'rpfm',
+	},
 	{
 		label: 'Douban.FM',
 		matches: ['*://douban.fm/*', '*://fm.douban.fm/*'],
@@ -244,6 +267,12 @@ export default <ConnectorMeta[]>[
 		js: 'odnoklassniki.js',
 		id: 'odnoklassniki',
 	},
+	{
+		label: 'Overcast',
+		matches: ['*://overcast.fm/*'],
+		js: 'overcast.js',
+		id: 'overcast',
+	},
 	{
 		label: 'Online Radio Box',
 		matches: ['*://onlineradiobox.com/*'],
@@ -2270,10 +2299,28 @@ export default <ConnectorMeta[]>[
 		js: 'wdr.js',
 		id: 'wdr',
 	},
+	{
+		label: 'radio.de',
+		matches: ['*://www.radio.de/*'],
+		js: 'radio.de.js',
+		id: 'radiode',
+	},
 	{
 		label: 'FMSpins',
 		matches: ['*://*.fmspins.com/*'],
 		js: 'fmspins.js',
 		id: 'fmspins',
 	},
+	{
+		label: 'vk-save',
+		matches: ['*://*.vk-save.com/*'],
+		js: 'vk-save.js',
+		id: 'vk-save',
+	},
+	{
+		label: 'Radio Student',
+		matches: ['*://www.radiostudent.hr/*'],
+		js: 'radiostudent.js',
+		id: 'radiostudent',
+	},
 ];
diff --git a/src/core/object/controller/controller.ts b/src/core/object/controller/controller.ts
index 97f67371..3382c562 100644
--- a/src/core/object/controller/controller.ts
+++ b/src/core/object/controller/controller.ts
@@ -3,6 +3,7 @@ import * as Options from '@/core/storage/options';
 import {
 	areAllResults,
 	DebugLogType,
+	parseScrobblePercent,
 	getSecondsToScrobble,
 	isAnyResult,
 } from '@/util/util';
@@ -876,13 +877,11 @@ export default class Controller {
 			return;
 		}
 
-		const percent = await Options.getOption(
+		const rawPercent = await Options.getOption(
 			Options.SCROBBLE_PERCENT,
 			this.connector.meta.id,
 		);
-		if (typeof percent !== 'number') {
-			return;
-		}
+		const percent = parseScrobblePercent(rawPercent);
 
 		const secondsToScrobble = getSecondsToScrobble(duration, percent);
 
diff --git a/src/core/scrobbler/listenbrainz/listenbrainz-scrobbler.ts b/src/core/scrobbler/listenbrainz/listenbrainz-scrobbler.ts
index 115d73f6..6d876db5 100644
--- a/src/core/scrobbler/listenbrainz/listenbrainz-scrobbler.ts
+++ b/src/core/scrobbler/listenbrainz/listenbrainz-scrobbler.ts
@@ -278,9 +278,8 @@ export default class ListenBrainzScrobbler extends BaseScrobbler<'ListenBrainz'>
 		}
 
 		if (sessionID && requestInfo.headers) {
-			(
-				requestInfo.headers as Record<string, string>
-			).Authorization = `Token ${sessionID}`;
+			(requestInfo.headers as Record<string, string>).Authorization =
+				`Token ${sessionID}`;
 		}
 		const promise = fetch(url, requestInfo);
 		const timeout = this.REQUEST_TIMEOUT;
@@ -354,7 +353,7 @@ export default class ListenBrainzScrobbler extends BaseScrobbler<'ListenBrainz'>
 					payload: {
 						url,
 					},
-			  });
+				});
 		const timeout = this.REQUEST_TIMEOUT;
 
 		// @ts-expect-error typescript is confused by the combination of ternary and promise wrapped promise. It's a skill issue on typescript's part.
diff --git a/src/core/storage/options.ts b/src/core/storage/options.ts
index 6620546a..7b86005e 100644
--- a/src/core/storage/options.ts
+++ b/src/core/storage/options.ts
@@ -1,6 +1,7 @@
 import connectors, { ConnectorMeta } from '@/core/connectors';
 import * as BrowserStorage from '@/core/storage/browser-storage';
 import { debugLog } from '../content/util';
+import { DEFAULT_SCROBBLE_PERCENT } from '@/util/util';
 
 const options = BrowserStorage.getStorage(BrowserStorage.OPTIONS);
 const connectorsOptions = BrowserStorage.getStorage(
@@ -87,7 +88,7 @@ const DEFAULT_OPTIONS: GlobalOptions = {
 	[SCROBBLE_RECOGNIZED_TRACKS]: true,
 	[SCROBBLE_EDITED_TRACKS_ONLY]: false,
 	[DEBUG_LOGGING_ENABLED]: false,
-	[SCROBBLE_PERCENT]: 50,
+	[SCROBBLE_PERCENT]: DEFAULT_SCROBBLE_PERCENT,
 	[USE_INFOBOX]: true,
 	[DISABLED_CONNECTORS]: {},
 };
diff --git a/src/ui/options/components/edit-options/util.tsx b/src/ui/options/components/edit-options/util.tsx
index 5bb953dc..6813d80c 100644
--- a/src/ui/options/components/edit-options/util.tsx
+++ b/src/ui/options/components/edit-options/util.tsx
@@ -138,7 +138,7 @@ function pushEdits(
 						: {
 								...oldEdits,
 								...edits,
-						  };
+							};
 				editWrapper.set(newEdits);
 				mutate(newEdits);
 			})(arg),
diff --git a/src/ui/options/components/inputs.tsx b/src/ui/options/components/inputs.tsx
index d9dac1c5..957108e5 100644
--- a/src/ui/options/components/inputs.tsx
+++ b/src/ui/options/components/inputs.tsx
@@ -324,7 +324,7 @@ export function RangeOptionEntry(props: {
 						}
 						const newOptions = {
 							...o,
-							[key]: e.currentTarget.value,
+							[key]: parseInt(e.currentTarget.value),
 						};
 						return newOptions;
 					});
@@ -338,7 +338,7 @@ export function RangeOptionEntry(props: {
 						}
 						const newOptions = {
 							...o,
-							[key]: e.currentTarget.value,
+							[key]: parseInt(e.currentTarget.value),
 						};
 						globalOptions.set(newOptions);
 						return newOptions;
diff --git a/src/ui/options/main.tsx b/src/ui/options/main.tsx
index f11d64a1..71bb5a98 100644
--- a/src/ui/options/main.tsx
+++ b/src/ui/options/main.tsx
@@ -75,9 +75,8 @@ function Options() {
 	document.addEventListener('click', onclick);
 	onCleanup(() => document.removeEventListener('click', onclick));
 
-	const [shouldShowContextMenu, setShouldShowContextMenu] = createSignal(
-		contextMenuQuery(),
-	);
+	const [shouldShowContextMenu, setShouldShowContextMenu] =
+		createSignal(contextMenuQuery());
 	const resizeListener = () => setShouldShowContextMenu(contextMenuQuery());
 	window.addEventListener('resize', resizeListener);
 
diff --git a/src/util/util.ts b/src/util/util.ts
index b393166e..22905884 100644
--- a/src/util/util.ts
+++ b/src/util/util.ts
@@ -26,6 +26,12 @@ export const HIDDEN_PLACEHOLDER = '[hidden]';
  */
 export const DEFAULT_SCROBBLE_TIME = 30;
 
+/**
+ * Percentage of track to playback before the track is scrobbled.
+ * This value is used only if scrobble percent storage is somehow corrupted.
+ */
+export const DEFAULT_SCROBBLE_PERCENT = 50;
+
 /**
  * Minimum number of seconds of scrobbleable track.
  */
@@ -54,6 +60,22 @@ export function debugLog(text: unknown, logType: DebugLogType = 'log'): void {
 	logFunc(text);
 }
 
+/**
+ * Narrow the typing of scrobble percent.
+ * Fallback to default if scrobble percent is not a number.
+ *
+ * @param percent - Scrobble percent value from settings
+ * @returns percentage of track to play before scrobbling
+ */
+export function parseScrobblePercent(percent: unknown): number {
+	return percent &&
+		typeof percent === 'number' &&
+		!isNaN(percent) &&
+		isFinite(percent)
+		? percent
+		: DEFAULT_SCROBBLE_PERCENT;
+}
+
 /**
  * Return total number of seconds of playback needed for this track
  * to be scrobbled.


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index cdbd73d1..30146143 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -37,6 +37,7 @@ jobs:
         uses: actions/setup-node@v4
         with:
           node-version-file: '.nvmrc'
+          cache: 'npm'
 
       - name: Install dependencies
         run: npm ci