From 1ad112d3cef12ce0a22b24e7595d3d5f8c4dcb44 Mon Sep 17 00:00:00 2001
From: Brett Saviano <bsaviano@intersystems.com>
Date: Mon, 15 Jul 2024 09:05:07 -0400
Subject: [PATCH 1/9] Client-side editing overhaul

---
 .eslintrc.json                                |    1 -
 README.md                                     |    2 +-
 package-lock.json                             | 6870 ++++++++++-------
 package.json                                  |  100 +-
 src/api/atelier.d.ts                          |   14 -
 src/api/index.ts                              |    7 +-
 src/commands/addServerNamespaceToWorkspace.ts |   77 +-
 src/commands/compile.ts                       |  135 +-
 .../connectFolderToServerNamespace.ts         |    3 +-
 src/commands/delete.ts                        |    8 +-
 src/commands/export.ts                        |  180 +-
 src/commands/jumpToTagAndOffset.ts            |   11 +-
 src/commands/newFile.ts                       |   57 +-
 src/commands/project.ts                       |   99 +-
 src/commands/restDebugPanel.ts                |   27 +-
 src/commands/serverActions.ts                 |   24 +-
 src/commands/studio.ts                        |   29 +-
 src/commands/studioMigration.ts               |   30 +-
 src/commands/superclass.ts                    |    7 +-
 src/commands/unitTest.ts                      |  127 +-
 src/commands/viewOthers.ts                    |   30 +-
 src/commands/webSocketTerminal.ts             |   31 +-
 src/commands/xmlToUdl.ts                      |   44 +-
 src/explorer/explorer.ts                      |   28 +-
 src/explorer/models/classNode.ts              |    3 +-
 src/explorer/models/cspFileNode.ts            |    3 +-
 src/explorer/models/packageNode.ts            |    6 -
 src/explorer/models/rootNode.ts               |    4 +-
 src/explorer/models/routineNode.ts            |    3 +-
 src/explorer/projectsExplorer.ts              |   23 +-
 src/extension.ts                              |  140 +-
 src/languageConfiguration.ts                  |    4 +-
 src/providers/DocumentContentProvider.ts      |  114 +-
 .../DocumentRangeFormattingEditProvider.ts    |   12 -
 .../FileSystemProvider/FileSystemProvider.ts  |   85 +-
 .../FileSystemProvider/TextSearchProvider.ts  |   25 +-
 .../ObjectScriptClassSymbolProvider.ts        |    1 -
 .../ObjectScriptCompletionItemProvider.ts     |    1 -
 src/providers/RuleEditorProvider.ts           |   18 +-
 src/providers/WorkspaceSymbolProvider.ts      |   34 +-
 src/queries.d.ts                              |    9 -
 src/utils/FileProviderUtil.ts                 |    8 +-
 src/utils/documentIndex.ts                    |  208 +
 src/utils/documentPicker.ts                   |   46 +-
 src/utils/index.ts                            |  262 +-
 45 files changed, 4978 insertions(+), 3972 deletions(-)
 delete mode 100644 src/providers/DocumentRangeFormattingEditProvider.ts
 delete mode 100644 src/queries.d.ts
 create mode 100644 src/utils/documentIndex.ts

diff --git a/.eslintrc.json b/.eslintrc.json
index b372533e..b669dba2 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -14,7 +14,6 @@
     "plugin:@typescript-eslint/recommended",
     "plugin:@typescript-eslint/eslint-recommended",
     "prettier",
-    "prettier/@typescript-eslint",
     "plugin:prettier/recommended"
   ],
   "plugins": [
diff --git a/README.md b/README.md
index 97121f05..7c19a8eb 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@
   - press <kbd>⌘</kbd>/<kbd>Ctrl</kbd>+<kbd>F7</kbd>
   - or, select `ObjectScript: Import and Compile Current File` from Command Palette
 - Direct access to edit or view server code in the VS Code Explorer via `isfs` and `isfs-readonly` FileSystemProviders (e.g. using a [multi-root workspace](https://code.visualstudio.com/docs/editor/multi-root-workspaces)). Server-side source control is respected.
-- Server Explorer view (ObjectScript: Explorer) with ability to export items to your working folder.
+- Server Explorer view (InterSystems: Explorer) with ability to export items to your working folder.
 - Integration with with [InterSystems Server Manager](https://marketplace.visualstudio.com/items?itemName=intersystems-community.servermanager) for secure storage of connection passwords.
 
 ## Installation
diff --git a/package-lock.json b/package-lock.json
index d9bef029..f5fce710 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,27 +1,27 @@
 {
   "name": "vscode-objectscript",
-  "version": "2.12.2-SNAPSHOT",
+  "version": "2.12.6-SNAPSHOT",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "vscode-objectscript",
-      "version": "2.12.2-SNAPSHOT",
+      "version": "2.12.6-SNAPSHOT",
       "hasInstallScript": true,
       "license": "MIT",
       "dependencies": {
-        "@vscode/debugadapter": "^1.61.0",
-        "@vscode/debugprotocol": "^1.61.0",
+        "@vscode/debugadapter": "^1.65.0",
+        "@vscode/debugprotocol": "^1.65.0",
         "@xmldom/xmldom": "^0.8.8",
         "core-js": "^3.6.5",
         "iconv-lite": "^0.6.0",
-        "istextorbinary": "^6.0.0",
+        "istextorbinary": "^7.0.0",
         "minimatch": "^9.0.3",
         "node-cmd": "^5.0.0",
         "node-fetch-cjs": "3.1.1",
         "vscode-cache": "^0.3.0",
         "vscode-extension-telemetry": "^0.1.6",
-        "ws": "^8.14.2"
+        "ws": "^8.17.1"
       },
       "devDependencies": {
         "@types/istextorbinary": "2.3.1",
@@ -29,199 +29,101 @@
         "@types/mocha": "^7.0.2",
         "@types/node": "^14.18.0",
         "@types/semver": "7.5.4",
-        "@types/vscode": "1.83.0",
+        "@types/vscode": "1.91.0",
         "@types/ws": "8.5.4",
         "@types/xmldom": "^0.1.29",
-        "@typescript-eslint/eslint-plugin": "^4.32.0",
-        "@typescript-eslint/parser": "^4.32.0",
+        "@typescript-eslint/eslint-plugin": "^7.12.0",
+        "@typescript-eslint/parser": "^7.12.0",
+        "@vscode/debugadapter-testsupport": "^1.65.0",
         "@vscode/dts": "^0.4.0",
-        "@vscode/test-electron": "^2.3.8",
-        "eslint": "^7.32.0",
-        "eslint-config-airbnb-base": "^14.2.1",
-        "eslint-config-prettier": "^6.11.0",
-        "eslint-plugin-import": "^2.24.2",
-        "eslint-plugin-jsx-a11y": "^6.3.1",
+        "@vscode/test-electron": "^2.4.0",
+        "eslint": "^8.56.0",
+        "eslint-config-airbnb-base": "^15.0.0",
+        "eslint-config-prettier": "^9.1.0",
+        "eslint-plugin-import": "^2.29.1",
+        "eslint-plugin-jsx-a11y": "^6.8.0",
         "eslint-plugin-node": "^11.1.0",
-        "eslint-plugin-prettier": "^3.1.4",
-        "eslint-plugin-promise": "^4.2.1",
+        "eslint-plugin-prettier": "^5.1.3",
+        "eslint-plugin-promise": "^6.2.0",
         "glob": "^7.1.6",
         "mocha": "^9.1.3",
         "path-browserify": "^1.0.1",
-        "prettier": "^2.0.5",
-        "ts-loader": "^7.0.5",
-        "typescript": "^4.4.3",
-        "vscode-debugadapter-testsupport": "^1.41.0",
-        "webpack": "^5.76.0",
-        "webpack-cli": "^4.5.0"
+        "prettier": "^3.3.1",
+        "ts-loader": "^9.5.1",
+        "typescript": "^5.4.5",
+        "webpack": "^5.91.0",
+        "webpack-cli": "^5.1.4"
       },
       "engines": {
-        "vscode": "^1.83.0"
+        "vscode": "^1.91.0"
       }
     },
-    "node_modules/@babel/code-frame": {
-      "version": "7.12.11",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
-      "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
-      "dev": true,
-      "dependencies": {
-        "@babel/highlight": "^7.10.4"
-      }
-    },
-    "node_modules/@babel/helper-validator-identifier": {
-      "version": "7.15.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
-      "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
-      "dev": true,
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@babel/highlight": {
-      "version": "7.16.0",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz",
-      "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==",
+    "node_modules/@babel/runtime": {
+      "version": "7.24.7",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz",
+      "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==",
       "dev": true,
       "dependencies": {
-        "@babel/helper-validator-identifier": "^7.15.7",
-        "chalk": "^2.0.0",
-        "js-tokens": "^4.0.0"
+        "regenerator-runtime": "^0.14.0"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
-    "node_modules/@babel/highlight/node_modules/ansi-styles": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-      "dev": true,
-      "dependencies": {
-        "color-convert": "^1.9.0"
-      },
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/@babel/highlight/node_modules/chalk": {
-      "version": "2.4.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-      "dev": true,
-      "dependencies": {
-        "ansi-styles": "^3.2.1",
-        "escape-string-regexp": "^1.0.5",
-        "supports-color": "^5.3.0"
-      },
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/@babel/highlight/node_modules/color-convert": {
-      "version": "1.9.3",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-      "dev": true,
-      "dependencies": {
-        "color-name": "1.1.3"
-      }
-    },
-    "node_modules/@babel/highlight/node_modules/color-name": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-      "dev": true
-    },
-    "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-      "dev": true,
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
-    "node_modules/@babel/highlight/node_modules/has-flag": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-      "dev": true,
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/@babel/highlight/node_modules/supports-color": {
-      "version": "5.5.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+    "node_modules/@discoveryjs/json-ext": {
+      "version": "0.5.5",
+      "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz",
+      "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==",
       "dev": true,
-      "dependencies": {
-        "has-flag": "^3.0.0"
-      },
       "engines": {
-        "node": ">=4"
+        "node": ">=10.0.0"
       }
     },
-    "node_modules/@babel/runtime": {
-      "version": "7.16.3",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz",
-      "integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==",
+    "node_modules/@eslint-community/eslint-utils": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+      "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
       "dev": true,
       "dependencies": {
-        "regenerator-runtime": "^0.13.4"
+        "eslint-visitor-keys": "^3.3.0"
       },
       "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@babel/runtime-corejs3": {
-      "version": "7.16.3",
-      "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.3.tgz",
-      "integrity": "sha512-IAdDC7T0+wEB4y2gbIL0uOXEYpiZEeuFUTVbdGq+UwCcF35T/tS8KrmMomEwEc5wBbyfH3PJVpTSUqrhPDXFcQ==",
-      "dev": true,
-      "dependencies": {
-        "core-js-pure": "^3.19.0",
-        "regenerator-runtime": "^0.13.4"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       },
-      "engines": {
-        "node": ">=6.9.0"
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
       }
     },
-    "node_modules/@discoveryjs/json-ext": {
-      "version": "0.5.5",
-      "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz",
-      "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==",
+    "node_modules/@eslint-community/regexpp": {
+      "version": "4.10.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz",
+      "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==",
       "dev": true,
       "engines": {
-        "node": ">=10.0.0"
+        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
       }
     },
     "node_modules/@eslint/eslintrc": {
-      "version": "0.4.3",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
-      "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
+      "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",
-        "debug": "^4.1.1",
-        "espree": "^7.3.0",
-        "globals": "^13.9.0",
-        "ignore": "^4.0.6",
+        "debug": "^4.3.2",
+        "espree": "^9.6.0",
+        "globals": "^13.19.0",
+        "ignore": "^5.2.0",
         "import-fresh": "^3.2.1",
-        "js-yaml": "^3.13.1",
-        "minimatch": "^3.0.4",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
         "strip-json-comments": "^3.1.1"
       },
       "engines": {
-        "node": "^10.12.0 || >=12.0.0"
-      }
-    },
-    "node_modules/@eslint/eslintrc/node_modules/ignore": {
-      "version": "4.0.6",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
-      "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
-      "dev": true,
-      "engines": {
-        "node": ">= 4"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
       }
     },
     "node_modules/@eslint/eslintrc/node_modules/minimatch": {
@@ -236,15 +138,24 @@
         "node": "*"
       }
     },
+    "node_modules/@eslint/js": {
+      "version": "8.57.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
+      "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
+      "dev": true,
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
     "node_modules/@humanwhocodes/config-array": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
-      "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
+      "version": "0.11.14",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
+      "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
       "dev": true,
       "dependencies": {
-        "@humanwhocodes/object-schema": "^1.2.0",
-        "debug": "^4.1.1",
-        "minimatch": "^3.0.4"
+        "@humanwhocodes/object-schema": "^2.0.2",
+        "debug": "^4.3.1",
+        "minimatch": "^3.0.5"
       },
       "engines": {
         "node": ">=10.10.0"
@@ -262,68 +173,81 @@
         "node": "*"
       }
     },
+    "node_modules/@humanwhocodes/module-importer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+      "dev": true,
+      "engines": {
+        "node": ">=12.22"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
     "node_modules/@humanwhocodes/object-schema": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
-      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+      "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
       "dev": true
     },
     "node_modules/@jridgewell/gen-mapping": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
-      "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
+      "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
       "dev": true,
       "dependencies": {
-        "@jridgewell/set-array": "^1.0.1",
+        "@jridgewell/set-array": "^1.2.1",
         "@jridgewell/sourcemap-codec": "^1.4.10",
-        "@jridgewell/trace-mapping": "^0.3.9"
+        "@jridgewell/trace-mapping": "^0.3.24"
       },
       "engines": {
         "node": ">=6.0.0"
       }
     },
     "node_modules/@jridgewell/resolve-uri": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
-      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
       "dev": true,
       "engines": {
         "node": ">=6.0.0"
       }
     },
     "node_modules/@jridgewell/set-array": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
-      "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+      "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
       "dev": true,
       "engines": {
         "node": ">=6.0.0"
       }
     },
     "node_modules/@jridgewell/source-map": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
-      "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
+      "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
       "dev": true,
       "dependencies": {
-        "@jridgewell/gen-mapping": "^0.3.0",
-        "@jridgewell/trace-mapping": "^0.3.9"
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.25"
       }
     },
     "node_modules/@jridgewell/sourcemap-codec": {
-      "version": "1.4.14",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
-      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+      "version": "1.4.15",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+      "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
       "dev": true
     },
     "node_modules/@jridgewell/trace-mapping": {
-      "version": "0.3.14",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz",
-      "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==",
+      "version": "0.3.25",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+      "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
       "dev": true,
       "dependencies": {
-        "@jridgewell/resolve-uri": "^3.0.3",
-        "@jridgewell/sourcemap-codec": "^1.4.10"
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
       }
     },
     "node_modules/@nodelib/fs.scandir": {
@@ -361,13 +285,16 @@
         "node": ">= 8"
       }
     },
-    "node_modules/@tootallnate/once": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
-      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+    "node_modules/@pkgr/core": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz",
+      "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==",
       "dev": true,
       "engines": {
-        "node": ">= 6"
+        "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/unts"
       }
     },
     "node_modules/@types/eslint": {
@@ -391,9 +318,9 @@
       }
     },
     "node_modules/@types/estree": {
-      "version": "0.0.51",
-      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz",
-      "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
+      "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
       "dev": true
     },
     "node_modules/@types/istextorbinary": {
@@ -414,7 +341,7 @@
     "node_modules/@types/json5": {
       "version": "0.0.29",
       "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
-      "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
+      "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
       "dev": true
     },
     "node_modules/@types/minimatch": {
@@ -442,9 +369,9 @@
       "dev": true
     },
     "node_modules/@types/vscode": {
-      "version": "1.83.0",
-      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.83.0.tgz",
-      "integrity": "sha512-3mUtHqLAVz9hegut9au4xehuBrzRE3UJiQMpoEHkNl6XHliihO7eATx2BMHs0odsmmrwjJrlixx/Pte6M3ygDQ==",
+      "version": "1.91.0",
+      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.91.0.tgz",
+      "integrity": "sha512-PgPr+bUODjG3y+ozWUCyzttqR9EHny9sPAfJagddQjDwdtf66y2sDKJMnFZRuzBA2YtBGASqJGPil8VDUPvO6A==",
       "dev": true
     },
     "node_modules/@types/ws": {
@@ -463,30 +390,31 @@
       "dev": true
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz",
-      "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==",
-      "dev": true,
-      "dependencies": {
-        "@typescript-eslint/experimental-utils": "4.33.0",
-        "@typescript-eslint/scope-manager": "4.33.0",
-        "debug": "^4.3.1",
-        "functional-red-black-tree": "^1.0.1",
-        "ignore": "^5.1.8",
-        "regexpp": "^3.1.0",
-        "semver": "^7.3.5",
-        "tsutils": "^3.21.0"
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz",
+      "integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==",
+      "dev": true,
+      "dependencies": {
+        "@eslint-community/regexpp": "^4.10.0",
+        "@typescript-eslint/scope-manager": "7.12.0",
+        "@typescript-eslint/type-utils": "7.12.0",
+        "@typescript-eslint/utils": "7.12.0",
+        "@typescript-eslint/visitor-keys": "7.12.0",
+        "graphemer": "^1.4.0",
+        "ignore": "^5.3.1",
+        "natural-compare": "^1.4.0",
+        "ts-api-utils": "^1.3.0"
       },
       "engines": {
-        "node": "^10.12.0 || >=12.0.0"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
       "peerDependencies": {
-        "@typescript-eslint/parser": "^4.0.0",
-        "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
+        "@typescript-eslint/parser": "^7.0.0",
+        "eslint": "^8.56.0"
       },
       "peerDependenciesMeta": {
         "typescript": {
@@ -494,68 +422,88 @@
         }
       }
     },
-    "node_modules/@typescript-eslint/experimental-utils": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz",
-      "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==",
+    "node_modules/@typescript-eslint/parser": {
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz",
+      "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==",
       "dev": true,
       "dependencies": {
-        "@types/json-schema": "^7.0.7",
-        "@typescript-eslint/scope-manager": "4.33.0",
-        "@typescript-eslint/types": "4.33.0",
-        "@typescript-eslint/typescript-estree": "4.33.0",
-        "eslint-scope": "^5.1.1",
-        "eslint-utils": "^3.0.0"
+        "@typescript-eslint/scope-manager": "7.12.0",
+        "@typescript-eslint/types": "7.12.0",
+        "@typescript-eslint/typescript-estree": "7.12.0",
+        "@typescript-eslint/visitor-keys": "7.12.0",
+        "debug": "^4.3.4"
       },
       "engines": {
-        "node": "^10.12.0 || >=12.0.0"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
       "peerDependencies": {
-        "eslint": "*"
+        "eslint": "^8.56.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
       }
     },
-    "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-utils": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
-      "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+    "node_modules/@typescript-eslint/parser/node_modules/debug": {
+      "version": "4.3.5",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+      "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
       "dev": true,
       "dependencies": {
-        "eslint-visitor-keys": "^2.0.0"
+        "ms": "2.1.2"
       },
       "engines": {
-        "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+        "node": ">=6.0"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/mysticatea"
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/scope-manager": {
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz",
+      "integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/types": "7.12.0",
+        "@typescript-eslint/visitor-keys": "7.12.0"
       },
-      "peerDependencies": {
-        "eslint": ">=5"
+      "engines": {
+        "node": "^18.18.0 || >=20.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
       }
     },
-    "node_modules/@typescript-eslint/parser": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz",
-      "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==",
+    "node_modules/@typescript-eslint/type-utils": {
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz",
+      "integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "4.33.0",
-        "@typescript-eslint/types": "4.33.0",
-        "@typescript-eslint/typescript-estree": "4.33.0",
-        "debug": "^4.3.1"
+        "@typescript-eslint/typescript-estree": "7.12.0",
+        "@typescript-eslint/utils": "7.12.0",
+        "debug": "^4.3.4",
+        "ts-api-utils": "^1.3.0"
       },
       "engines": {
-        "node": "^10.12.0 || >=12.0.0"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
       "peerDependencies": {
-        "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
+        "eslint": "^8.56.0"
       },
       "peerDependenciesMeta": {
         "typescript": {
@@ -563,30 +511,30 @@
         }
       }
     },
-    "node_modules/@typescript-eslint/scope-manager": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz",
-      "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==",
+    "node_modules/@typescript-eslint/type-utils/node_modules/debug": {
+      "version": "4.3.5",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+      "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "4.33.0",
-        "@typescript-eslint/visitor-keys": "4.33.0"
+        "ms": "2.1.2"
       },
       "engines": {
-        "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+        "node": ">=6.0"
       },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
       }
     },
     "node_modules/@typescript-eslint/types": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz",
-      "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==",
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz",
+      "integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==",
       "dev": true,
       "engines": {
-        "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -594,21 +542,22 @@
       }
     },
     "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz",
-      "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==",
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz",
+      "integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "4.33.0",
-        "@typescript-eslint/visitor-keys": "4.33.0",
-        "debug": "^4.3.1",
-        "globby": "^11.0.3",
-        "is-glob": "^4.0.1",
-        "semver": "^7.3.5",
-        "tsutils": "^3.21.0"
+        "@typescript-eslint/types": "7.12.0",
+        "@typescript-eslint/visitor-keys": "7.12.0",
+        "debug": "^4.3.4",
+        "globby": "^11.1.0",
+        "is-glob": "^4.0.3",
+        "minimatch": "^9.0.4",
+        "semver": "^7.6.0",
+        "ts-api-utils": "^1.3.0"
       },
       "engines": {
-        "node": "^10.12.0 || >=12.0.0"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -620,17 +569,56 @@
         }
       }
     },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": {
+      "version": "4.3.5",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+      "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/utils": {
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz",
+      "integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==",
+      "dev": true,
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.4.0",
+        "@typescript-eslint/scope-manager": "7.12.0",
+        "@typescript-eslint/types": "7.12.0",
+        "@typescript-eslint/typescript-estree": "7.12.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || >=20.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.56.0"
+      }
+    },
     "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz",
-      "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==",
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz",
+      "integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "4.33.0",
-        "eslint-visitor-keys": "^2.0.0"
+        "@typescript-eslint/types": "7.12.0",
+        "eslint-visitor-keys": "^3.4.3"
       },
       "engines": {
-        "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -643,21 +631,39 @@
       "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
       "dev": true
     },
+    "node_modules/@ungap/structured-clone": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
+      "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
+      "dev": true
+    },
     "node_modules/@vscode/debugadapter": {
-      "version": "1.61.0",
-      "resolved": "https://registry.npmjs.org/@vscode/debugadapter/-/debugadapter-1.61.0.tgz",
-      "integrity": "sha512-VDGLUFDVAdnftUebZe4uQCIFUbJ7rTc2Grps4D/CXl+qyzTZSQLv5VADEOZ6kBYG4SvlnMLql5vPQ0G6XvUCvQ==",
+      "version": "1.65.0",
+      "resolved": "https://registry.npmjs.org/@vscode/debugadapter/-/debugadapter-1.65.0.tgz",
+      "integrity": "sha512-l9jdX0GFoFVAc7O4O8iVnCjO0pgxbx+wJJXCaYSuglGtYwMNcJdc7xm96cuVx4LWzSqneIjvjzbuzZtoVZhZzQ==",
+      "dependencies": {
+        "@vscode/debugprotocol": "1.65.0"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@vscode/debugadapter-testsupport": {
+      "version": "1.65.0",
+      "resolved": "https://registry.npmjs.org/@vscode/debugadapter-testsupport/-/debugadapter-testsupport-1.65.0.tgz",
+      "integrity": "sha512-VwXzZKhBBK2rBemzQbw7rKsaNl0rZbcWm6oMxipz152Ki9LhrTy9QDl6zZlcdvJx23r9WtNxt7qHNt02PPMisg==",
+      "dev": true,
       "dependencies": {
-        "@vscode/debugprotocol": "1.61.0"
+        "@vscode/debugprotocol": "1.65.0"
       },
       "engines": {
         "node": ">=14"
       }
     },
     "node_modules/@vscode/debugprotocol": {
-      "version": "1.61.0",
-      "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.61.0.tgz",
-      "integrity": "sha512-K/kF27jIStVFqlmUaGc2u+Dj8IR7YdEiSqShWr7MWhDudqpAW7uu7XMwoFwjpuC9LSaVwJMIX7EFC5OJ/RmnDQ=="
+      "version": "1.65.0",
+      "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.65.0.tgz",
+      "integrity": "sha512-ejerrPMBXzYms6Ks+Gb7cdXtdncmT0xwIKNsc0c/SxhEa0HVY5jdvLUegYE91p7CQJpCnXOD/r2CvViN8txLLA=="
     },
     "node_modules/@vscode/dts": {
       "version": "0.4.0",
@@ -673,238 +679,205 @@
         "dts": "index.js"
       }
     },
-    "node_modules/@vscode/dts/node_modules/agent-base": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
-      "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==",
-      "dev": true,
-      "dependencies": {
-        "debug": "^4.3.4"
-      },
-      "engines": {
-        "node": ">= 14"
-      }
-    },
-    "node_modules/@vscode/dts/node_modules/debug": {
-      "version": "4.3.4",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-      "dev": true,
-      "dependencies": {
-        "ms": "2.1.2"
-      },
-      "engines": {
-        "node": ">=6.0"
-      },
-      "peerDependenciesMeta": {
-        "supports-color": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@vscode/dts/node_modules/https-proxy-agent": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz",
-      "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==",
-      "dev": true,
-      "dependencies": {
-        "agent-base": "^7.0.2",
-        "debug": "4"
-      },
-      "engines": {
-        "node": ">= 14"
-      }
-    },
     "node_modules/@vscode/test-electron": {
-      "version": "2.3.8",
-      "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.8.tgz",
-      "integrity": "sha512-b4aZZsBKtMGdDljAsOPObnAi7+VWIaYl3ylCz1jTs+oV6BZ4TNHcVNC3xUn0azPeszBmwSBDQYfFESIaUQnrOg==",
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.0.tgz",
+      "integrity": "sha512-yojuDFEjohx6Jb+x949JRNtSn6Wk2FAh4MldLE3ck9cfvCqzwxF32QsNy1T9Oe4oT+ZfFcg0uPUCajJzOmPlTA==",
       "dev": true,
       "dependencies": {
-        "http-proxy-agent": "^4.0.1",
-        "https-proxy-agent": "^5.0.0",
+        "http-proxy-agent": "^7.0.2",
+        "https-proxy-agent": "^7.0.4",
         "jszip": "^3.10.1",
-        "semver": "^7.5.2"
+        "ora": "^7.0.1",
+        "semver": "^7.6.2"
       },
       "engines": {
         "node": ">=16"
       }
     },
     "node_modules/@webassemblyjs/ast": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
-      "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",
+      "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",
       "dev": true,
       "dependencies": {
-        "@webassemblyjs/helper-numbers": "1.11.1",
-        "@webassemblyjs/helper-wasm-bytecode": "1.11.1"
+        "@webassemblyjs/helper-numbers": "1.11.6",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6"
       }
     },
     "node_modules/@webassemblyjs/floating-point-hex-parser": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz",
-      "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
+      "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",
       "dev": true
     },
     "node_modules/@webassemblyjs/helper-api-error": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz",
-      "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
+      "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",
       "dev": true
     },
     "node_modules/@webassemblyjs/helper-buffer": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz",
-      "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",
+      "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==",
       "dev": true
     },
     "node_modules/@webassemblyjs/helper-numbers": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz",
-      "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
+      "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
       "dev": true,
       "dependencies": {
-        "@webassemblyjs/floating-point-hex-parser": "1.11.1",
-        "@webassemblyjs/helper-api-error": "1.11.1",
+        "@webassemblyjs/floating-point-hex-parser": "1.11.6",
+        "@webassemblyjs/helper-api-error": "1.11.6",
         "@xtuc/long": "4.2.2"
       }
     },
     "node_modules/@webassemblyjs/helper-wasm-bytecode": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz",
-      "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
+      "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",
       "dev": true
     },
     "node_modules/@webassemblyjs/helper-wasm-section": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz",
-      "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",
+      "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",
       "dev": true,
       "dependencies": {
-        "@webassemblyjs/ast": "1.11.1",
-        "@webassemblyjs/helper-buffer": "1.11.1",
-        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
-        "@webassemblyjs/wasm-gen": "1.11.1"
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-buffer": "1.12.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/wasm-gen": "1.12.1"
       }
     },
     "node_modules/@webassemblyjs/ieee754": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz",
-      "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
+      "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
       "dev": true,
       "dependencies": {
         "@xtuc/ieee754": "^1.2.0"
       }
     },
     "node_modules/@webassemblyjs/leb128": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz",
-      "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
+      "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
       "dev": true,
       "dependencies": {
         "@xtuc/long": "4.2.2"
       }
     },
     "node_modules/@webassemblyjs/utf8": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz",
-      "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
+      "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",
       "dev": true
     },
     "node_modules/@webassemblyjs/wasm-edit": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz",
-      "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz",
+      "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==",
       "dev": true,
       "dependencies": {
-        "@webassemblyjs/ast": "1.11.1",
-        "@webassemblyjs/helper-buffer": "1.11.1",
-        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
-        "@webassemblyjs/helper-wasm-section": "1.11.1",
-        "@webassemblyjs/wasm-gen": "1.11.1",
-        "@webassemblyjs/wasm-opt": "1.11.1",
-        "@webassemblyjs/wasm-parser": "1.11.1",
-        "@webassemblyjs/wast-printer": "1.11.1"
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-buffer": "1.12.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/helper-wasm-section": "1.12.1",
+        "@webassemblyjs/wasm-gen": "1.12.1",
+        "@webassemblyjs/wasm-opt": "1.12.1",
+        "@webassemblyjs/wasm-parser": "1.12.1",
+        "@webassemblyjs/wast-printer": "1.12.1"
       }
     },
     "node_modules/@webassemblyjs/wasm-gen": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz",
-      "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",
+      "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",
       "dev": true,
       "dependencies": {
-        "@webassemblyjs/ast": "1.11.1",
-        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
-        "@webassemblyjs/ieee754": "1.11.1",
-        "@webassemblyjs/leb128": "1.11.1",
-        "@webassemblyjs/utf8": "1.11.1"
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/ieee754": "1.11.6",
+        "@webassemblyjs/leb128": "1.11.6",
+        "@webassemblyjs/utf8": "1.11.6"
       }
     },
     "node_modules/@webassemblyjs/wasm-opt": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz",
-      "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",
+      "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",
       "dev": true,
       "dependencies": {
-        "@webassemblyjs/ast": "1.11.1",
-        "@webassemblyjs/helper-buffer": "1.11.1",
-        "@webassemblyjs/wasm-gen": "1.11.1",
-        "@webassemblyjs/wasm-parser": "1.11.1"
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-buffer": "1.12.1",
+        "@webassemblyjs/wasm-gen": "1.12.1",
+        "@webassemblyjs/wasm-parser": "1.12.1"
       }
     },
     "node_modules/@webassemblyjs/wasm-parser": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz",
-      "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",
+      "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",
       "dev": true,
       "dependencies": {
-        "@webassemblyjs/ast": "1.11.1",
-        "@webassemblyjs/helper-api-error": "1.11.1",
-        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
-        "@webassemblyjs/ieee754": "1.11.1",
-        "@webassemblyjs/leb128": "1.11.1",
-        "@webassemblyjs/utf8": "1.11.1"
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-api-error": "1.11.6",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/ieee754": "1.11.6",
+        "@webassemblyjs/leb128": "1.11.6",
+        "@webassemblyjs/utf8": "1.11.6"
       }
     },
     "node_modules/@webassemblyjs/wast-printer": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz",
-      "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",
+      "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",
       "dev": true,
       "dependencies": {
-        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/ast": "1.12.1",
         "@xtuc/long": "4.2.2"
       }
     },
     "node_modules/@webpack-cli/configtest": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz",
-      "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==",
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz",
+      "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==",
       "dev": true,
+      "engines": {
+        "node": ">=14.15.0"
+      },
       "peerDependencies": {
-        "webpack": "4.x.x || 5.x.x",
-        "webpack-cli": "4.x.x"
+        "webpack": "5.x.x",
+        "webpack-cli": "5.x.x"
       }
     },
     "node_modules/@webpack-cli/info": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz",
-      "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz",
+      "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==",
       "dev": true,
-      "dependencies": {
-        "envinfo": "^7.7.3"
+      "engines": {
+        "node": ">=14.15.0"
       },
       "peerDependencies": {
-        "webpack-cli": "4.x.x"
+        "webpack": "5.x.x",
+        "webpack-cli": "5.x.x"
       }
     },
     "node_modules/@webpack-cli/serve": {
-      "version": "1.6.1",
-      "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz",
-      "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==",
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz",
+      "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==",
       "dev": true,
+      "engines": {
+        "node": ">=14.15.0"
+      },
       "peerDependencies": {
-        "webpack-cli": "4.x.x"
+        "webpack": "5.x.x",
+        "webpack-cli": "5.x.x"
       },
       "peerDependenciesMeta": {
         "webpack-dev-server": {
@@ -933,9 +906,9 @@
       "dev": true
     },
     "node_modules/acorn": {
-      "version": "7.4.1",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
-      "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+      "version": "8.11.3",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
+      "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
       "dev": true,
       "bin": {
         "acorn": "bin/acorn"
@@ -944,6 +917,15 @@
         "node": ">=0.4.0"
       }
     },
+    "node_modules/acorn-import-assertions": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
+      "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
+      "dev": true,
+      "peerDependencies": {
+        "acorn": "^8"
+      }
+    },
     "node_modules/acorn-jsx": {
       "version": "5.3.2",
       "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
@@ -954,15 +936,32 @@
       }
     },
     "node_modules/agent-base": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
-      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+      "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
       "dev": true,
       "dependencies": {
-        "debug": "4"
+        "debug": "^4.3.4"
       },
       "engines": {
-        "node": ">= 6.0.0"
+        "node": ">= 14"
+      }
+    },
+    "node_modules/agent-base/node_modules/debug": {
+      "version": "4.3.5",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+      "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
       }
     },
     "node_modules/ajv": {
@@ -1048,37 +1047,47 @@
       }
     },
     "node_modules/argparse": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
+    "node_modules/aria-query": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
+      "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
       "dev": true,
       "dependencies": {
-        "sprintf-js": "~1.0.2"
+        "dequal": "^2.0.3"
       }
     },
-    "node_modules/aria-query": {
-      "version": "4.2.2",
-      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz",
-      "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==",
+    "node_modules/array-buffer-byte-length": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
+      "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==",
       "dev": true,
       "dependencies": {
-        "@babel/runtime": "^7.10.2",
-        "@babel/runtime-corejs3": "^7.10.2"
+        "call-bind": "^1.0.5",
+        "is-array-buffer": "^3.0.4"
       },
       "engines": {
-        "node": ">=6.0"
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/array-includes": {
-      "version": "3.1.4",
-      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz",
-      "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==",
+      "version": "3.1.8",
+      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
+      "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.1",
-        "get-intrinsic": "^1.1.1",
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-object-atoms": "^1.0.0",
+        "get-intrinsic": "^1.2.4",
         "is-string": "^1.0.7"
       },
       "engines": {
@@ -1097,15 +1106,36 @@
         "node": ">=8"
       }
     },
-    "node_modules/array.prototype.flat": {
+    "node_modules/array.prototype.findlastindex": {
       "version": "1.2.5",
-      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz",
-      "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==",
+      "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
+      "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
+        "es-shim-unscopables": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array.prototype.flat": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
+      "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==",
       "dev": true,
       "dependencies": {
         "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.0"
+        "define-properties": "^1.2.0",
+        "es-abstract": "^1.22.1",
+        "es-shim-unscopables": "^1.0.0"
       },
       "engines": {
         "node": ">= 0.4"
@@ -1114,21 +1144,52 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/ast-types-flow": {
-      "version": "0.0.7",
-      "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
-      "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
-      "dev": true
+    "node_modules/array.prototype.flatmap": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz",
+      "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.2.0",
+        "es-abstract": "^1.22.1",
+        "es-shim-unscopables": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
     },
-    "node_modules/astral-regex": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
-      "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+    "node_modules/arraybuffer.prototype.slice": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz",
+      "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==",
       "dev": true,
+      "dependencies": {
+        "array-buffer-byte-length": "^1.0.1",
+        "call-bind": "^1.0.5",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.22.3",
+        "es-errors": "^1.2.1",
+        "get-intrinsic": "^1.2.3",
+        "is-array-buffer": "^3.0.4",
+        "is-shared-array-buffer": "^1.0.2"
+      },
       "engines": {
-        "node": ">=8"
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/ast-types-flow": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
+      "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
+      "dev": true
+    },
     "node_modules/async-hook-jl": {
       "version": "1.7.6",
       "resolved": "https://registry.npmjs.org/async-hook-jl/-/async-hook-jl-1.7.6.tgz",
@@ -1160,34 +1221,63 @@
         "semver": "bin/semver"
       }
     },
+    "node_modules/available-typed-arrays": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+      "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+      "dev": true,
+      "dependencies": {
+        "possible-typed-array-names": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/axe-core": {
-      "version": "4.3.5",
-      "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz",
-      "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==",
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz",
+      "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==",
       "dev": true,
       "engines": {
         "node": ">=4"
       }
     },
     "node_modules/axobject-query": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
-      "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==",
-      "dev": true
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
+      "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==",
+      "dev": true,
+      "dependencies": {
+        "dequal": "^2.0.3"
+      }
     },
     "node_modules/balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
       "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
     },
-    "node_modules/big.js": {
-      "version": "5.2.2",
-      "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
-      "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
+    "node_modules/base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
       "dev": true,
-      "engines": {
-        "node": "*"
-      }
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
     },
     "node_modules/binary-extensions": {
       "version": "2.2.0",
@@ -1209,6 +1299,31 @@
         "url": "https://bevry.me/fund"
       }
     },
+    "node_modules/bl": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz",
+      "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==",
+      "dev": true,
+      "dependencies": {
+        "buffer": "^6.0.3",
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.4.0"
+      }
+    },
+    "node_modules/bl/node_modules/readable-stream": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -1220,12 +1335,12 @@
       }
     },
     "node_modules/braces": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
       "dev": true,
       "dependencies": {
-        "fill-range": "^7.0.1"
+        "fill-range": "^7.1.1"
       },
       "engines": {
         "node": ">=8"
@@ -1238,26 +1353,59 @@
       "dev": true
     },
     "node_modules/browserslist": {
-      "version": "4.18.1",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.18.1.tgz",
-      "integrity": "sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ==",
+      "version": "4.23.0",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
+      "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
       "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
       "dependencies": {
-        "caniuse-lite": "^1.0.30001280",
-        "electron-to-chromium": "^1.3.896",
-        "escalade": "^3.1.1",
-        "node-releases": "^2.0.1",
-        "picocolors": "^1.0.0"
+        "caniuse-lite": "^1.0.30001587",
+        "electron-to-chromium": "^1.4.668",
+        "node-releases": "^2.0.14",
+        "update-browserslist-db": "^1.0.13"
       },
       "bin": {
         "browserslist": "cli.js"
       },
       "engines": {
         "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/browserslist"
+      }
+    },
+    "node_modules/buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
       }
     },
     "node_modules/buffer-from": {
@@ -1267,13 +1415,19 @@
       "dev": true
     },
     "node_modules/call-bind": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
-      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+      "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
       "dev": true,
       "dependencies": {
-        "function-bind": "^1.1.1",
-        "get-intrinsic": "^1.0.2"
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "set-function-length": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
@@ -1301,14 +1455,24 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001283",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001283.tgz",
-      "integrity": "sha512-9RoKo841j1GQFSJz/nCXOj0sD7tHBtlowjYlrqIUS812x9/emfBLBt6IyMz1zIaYc/eRL8Cs6HPUVi2Hzq4sIg==",
+      "version": "1.0.30001629",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001629.tgz",
+      "integrity": "sha512-c3dl911slnQhmxUIT4HhYzT7wnBK/XYpGnYLOj4nJBaRiw52Ibe7YxlDaAeRECvA786zCuExhxIUJ2K7nHMrBw==",
       "dev": true,
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/browserslist"
-      }
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ]
     },
     "node_modules/chalk": {
       "version": "4.1.2",
@@ -1362,6 +1526,33 @@
         "node": ">=6.0"
       }
     },
+    "node_modules/cli-cursor": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz",
+      "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==",
+      "dev": true,
+      "dependencies": {
+        "restore-cursor": "^4.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/cli-spinners": {
+      "version": "2.9.2",
+      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
+      "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/cliui": {
       "version": "7.0.4",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -1469,17 +1660,6 @@
         "url": "https://opencollective.com/core-js"
       }
     },
-    "node_modules/core-js-pure": {
-      "version": "3.19.1",
-      "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.1.tgz",
-      "integrity": "sha512-Q0Knr8Es84vtv62ei6/6jXH/7izKmOrtrxH9WJTHLCMAVeU+8TF8z8Nr08CsH4Ot0oJKzBzJJL9SJBYIv7WlfQ==",
-      "dev": true,
-      "hasInstallScript": true,
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/core-js"
-      }
-    },
     "node_modules/core-util-is": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
@@ -1501,11 +1681,62 @@
       }
     },
     "node_modules/damerau-levenshtein": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz",
-      "integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw==",
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
+      "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
       "dev": true
     },
+    "node_modules/data-view-buffer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
+      "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.6",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/data-view-byte-length": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
+      "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/data-view-byte-offset": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
+      "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.6",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/debug": {
       "version": "4.3.3",
       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
@@ -1541,16 +1772,47 @@
       "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
       "dev": true
     },
+    "node_modules/define-data-property": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+      "dev": true,
+      "dependencies": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/define-properties": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
-      "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+      "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
       "dev": true,
       "dependencies": {
-        "object-keys": "^1.0.12"
+        "define-data-property": "^1.0.1",
+        "has-property-descriptors": "^1.0.0",
+        "object-keys": "^1.1.1"
       },
       "engines": {
         "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/dequal": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+      "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
       }
     },
     "node_modules/diagnostic-channel": {
@@ -1610,10 +1872,16 @@
         "node": ">=6.0.0"
       }
     },
+    "node_modules/eastasianwidth": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+      "dev": true
+    },
     "node_modules/electron-to-chromium": {
-      "version": "1.4.4",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.4.tgz",
-      "integrity": "sha512-teHtgwcmVcL46jlFvAaqjyiTLWuMrUQO1JqV303JKB4ysXG6m8fXSFhbjal9st0r9mNskI22AraJZorb1VcLVg==",
+      "version": "1.4.794",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.794.tgz",
+      "integrity": "sha512-6FApLtsYhDCY0Vglq3AptsdxQ+PJLc6AxlAM0HjEihUAiOPPbkASEsq9gtxUeZY9o0sJIEa3WnF0vVH4VT4iug==",
       "dev": true
     },
     "node_modules/emitter-listener": {
@@ -1630,104 +1898,177 @@
       "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
       "dev": true
     },
-    "node_modules/emojis-list": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
-      "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+    "node_modules/enhanced-resolve": {
+      "version": "5.17.0",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz",
+      "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==",
       "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.2.4",
+        "tapable": "^2.2.0"
+      },
       "engines": {
-        "node": ">= 4"
+        "node": ">=10.13.0"
       }
     },
-    "node_modules/enhanced-resolve": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
-      "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
+    "node_modules/envinfo": {
+      "version": "7.13.0",
+      "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz",
+      "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==",
       "dev": true,
-      "dependencies": {
-        "graceful-fs": "^4.1.2",
-        "memory-fs": "^0.5.0",
-        "tapable": "^1.0.0"
+      "bin": {
+        "envinfo": "dist/cli.js"
       },
       "engines": {
-        "node": ">=6.9.0"
+        "node": ">=4"
       }
     },
-    "node_modules/enquirer": {
-      "version": "2.3.6",
-      "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
-      "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
+    "node_modules/es-abstract": {
+      "version": "1.23.3",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
+      "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==",
+      "dev": true,
+      "dependencies": {
+        "array-buffer-byte-length": "^1.0.1",
+        "arraybuffer.prototype.slice": "^1.0.3",
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.7",
+        "data-view-buffer": "^1.0.1",
+        "data-view-byte-length": "^1.0.1",
+        "data-view-byte-offset": "^1.0.0",
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
+        "es-set-tostringtag": "^2.0.3",
+        "es-to-primitive": "^1.2.1",
+        "function.prototype.name": "^1.1.6",
+        "get-intrinsic": "^1.2.4",
+        "get-symbol-description": "^1.0.2",
+        "globalthis": "^1.0.3",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.2",
+        "has-proto": "^1.0.3",
+        "has-symbols": "^1.0.3",
+        "hasown": "^2.0.2",
+        "internal-slot": "^1.0.7",
+        "is-array-buffer": "^3.0.4",
+        "is-callable": "^1.2.7",
+        "is-data-view": "^1.0.1",
+        "is-negative-zero": "^2.0.3",
+        "is-regex": "^1.1.4",
+        "is-shared-array-buffer": "^1.0.3",
+        "is-string": "^1.0.7",
+        "is-typed-array": "^1.1.13",
+        "is-weakref": "^1.0.2",
+        "object-inspect": "^1.13.1",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.5",
+        "regexp.prototype.flags": "^1.5.2",
+        "safe-array-concat": "^1.1.2",
+        "safe-regex-test": "^1.0.3",
+        "string.prototype.trim": "^1.2.9",
+        "string.prototype.trimend": "^1.0.8",
+        "string.prototype.trimstart": "^1.0.8",
+        "typed-array-buffer": "^1.0.2",
+        "typed-array-byte-length": "^1.0.1",
+        "typed-array-byte-offset": "^1.0.2",
+        "typed-array-length": "^1.0.6",
+        "unbox-primitive": "^1.0.2",
+        "which-typed-array": "^1.1.15"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/es-define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+      "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
       "dev": true,
       "dependencies": {
-        "ansi-colors": "^4.1.1"
+        "get-intrinsic": "^1.2.4"
       },
       "engines": {
-        "node": ">=8.6"
+        "node": ">= 0.4"
       }
     },
-    "node_modules/envinfo": {
-      "version": "7.8.1",
-      "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
-      "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==",
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
       "dev": true,
-      "bin": {
-        "envinfo": "dist/cli.js"
-      },
       "engines": {
-        "node": ">=4"
+        "node": ">= 0.4"
       }
     },
-    "node_modules/errno": {
-      "version": "0.1.8",
-      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
-      "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
+    "node_modules/es-iterator-helpers": {
+      "version": "1.0.19",
+      "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz",
+      "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==",
       "dev": true,
       "dependencies": {
-        "prr": "~1.0.1"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.3",
+        "es-errors": "^1.3.0",
+        "es-set-tostringtag": "^2.0.3",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "globalthis": "^1.0.3",
+        "has-property-descriptors": "^1.0.2",
+        "has-proto": "^1.0.3",
+        "has-symbols": "^1.0.3",
+        "internal-slot": "^1.0.7",
+        "iterator.prototype": "^1.1.2",
+        "safe-array-concat": "^1.1.2"
       },
-      "bin": {
-        "errno": "cli.js"
+      "engines": {
+        "node": ">= 0.4"
       }
     },
-    "node_modules/es-abstract": {
-      "version": "1.19.1",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz",
-      "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==",
+    "node_modules/es-module-lexer": {
+      "version": "1.5.3",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.3.tgz",
+      "integrity": "sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg==",
+      "dev": true
+    },
+    "node_modules/es-object-atoms": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
+      "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "es-to-primitive": "^1.2.1",
-        "function-bind": "^1.1.1",
-        "get-intrinsic": "^1.1.1",
-        "get-symbol-description": "^1.0.0",
-        "has": "^1.0.3",
-        "has-symbols": "^1.0.2",
-        "internal-slot": "^1.0.3",
-        "is-callable": "^1.2.4",
-        "is-negative-zero": "^2.0.1",
-        "is-regex": "^1.1.4",
-        "is-shared-array-buffer": "^1.0.1",
-        "is-string": "^1.0.7",
-        "is-weakref": "^1.0.1",
-        "object-inspect": "^1.11.0",
-        "object-keys": "^1.1.1",
-        "object.assign": "^4.1.2",
-        "string.prototype.trimend": "^1.0.4",
-        "string.prototype.trimstart": "^1.0.4",
-        "unbox-primitive": "^1.0.1"
+        "es-errors": "^1.3.0"
       },
       "engines": {
         "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-set-tostringtag": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
+      "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.2.4",
+        "has-tostringtag": "^1.0.2",
+        "hasown": "^2.0.1"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
+      "engines": {
+        "node": ">= 0.4"
       }
     },
-    "node_modules/es-module-lexer": {
-      "version": "0.9.3",
-      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
-      "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==",
-      "dev": true
+    "node_modules/es-shim-unscopables": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz",
+      "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==",
+      "dev": true,
+      "dependencies": {
+        "hasown": "^2.0.0"
+      }
     },
     "node_modules/es-to-primitive": {
       "version": "1.2.1",
@@ -1747,9 +2088,9 @@
       }
     },
     "node_modules/escalade": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
+      "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
       "dev": true,
       "engines": {
         "node": ">=6"
@@ -1768,103 +2109,109 @@
       }
     },
     "node_modules/eslint": {
-      "version": "7.32.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
-      "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
-      "dev": true,
-      "dependencies": {
-        "@babel/code-frame": "7.12.11",
-        "@eslint/eslintrc": "^0.4.3",
-        "@humanwhocodes/config-array": "^0.5.0",
-        "ajv": "^6.10.0",
+      "version": "8.57.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
+      "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
+      "dev": true,
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@eslint-community/regexpp": "^4.6.1",
+        "@eslint/eslintrc": "^2.1.4",
+        "@eslint/js": "8.57.0",
+        "@humanwhocodes/config-array": "^0.11.14",
+        "@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",
-        "debug": "^4.0.1",
+        "debug": "^4.3.2",
         "doctrine": "^3.0.0",
-        "enquirer": "^2.3.5",
         "escape-string-regexp": "^4.0.0",
-        "eslint-scope": "^5.1.1",
-        "eslint-utils": "^2.1.0",
-        "eslint-visitor-keys": "^2.0.0",
-        "espree": "^7.3.1",
-        "esquery": "^1.4.0",
+        "eslint-scope": "^7.2.2",
+        "eslint-visitor-keys": "^3.4.3",
+        "espree": "^9.6.1",
+        "esquery": "^1.4.2",
         "esutils": "^2.0.2",
         "fast-deep-equal": "^3.1.3",
         "file-entry-cache": "^6.0.1",
-        "functional-red-black-tree": "^1.0.1",
-        "glob-parent": "^5.1.2",
-        "globals": "^13.6.0",
-        "ignore": "^4.0.6",
-        "import-fresh": "^3.0.0",
+        "find-up": "^5.0.0",
+        "glob-parent": "^6.0.2",
+        "globals": "^13.19.0",
+        "graphemer": "^1.4.0",
+        "ignore": "^5.2.0",
         "imurmurhash": "^0.1.4",
         "is-glob": "^4.0.0",
-        "js-yaml": "^3.13.1",
+        "is-path-inside": "^3.0.3",
+        "js-yaml": "^4.1.0",
         "json-stable-stringify-without-jsonify": "^1.0.1",
         "levn": "^0.4.1",
         "lodash.merge": "^4.6.2",
-        "minimatch": "^3.0.4",
+        "minimatch": "^3.1.2",
         "natural-compare": "^1.4.0",
-        "optionator": "^0.9.1",
-        "progress": "^2.0.0",
-        "regexpp": "^3.1.0",
-        "semver": "^7.2.1",
-        "strip-ansi": "^6.0.0",
-        "strip-json-comments": "^3.1.0",
-        "table": "^6.0.9",
-        "text-table": "^0.2.0",
-        "v8-compile-cache": "^2.0.3"
+        "optionator": "^0.9.3",
+        "strip-ansi": "^6.0.1",
+        "text-table": "^0.2.0"
       },
       "bin": {
         "eslint": "bin/eslint.js"
       },
       "engines": {
-        "node": "^10.12.0 || >=12.0.0"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       },
       "funding": {
         "url": "https://opencollective.com/eslint"
       }
     },
     "node_modules/eslint-config-airbnb-base": {
-      "version": "14.2.1",
-      "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz",
-      "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz",
+      "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==",
       "dev": true,
       "dependencies": {
         "confusing-browser-globals": "^1.0.10",
         "object.assign": "^4.1.2",
-        "object.entries": "^1.1.2"
+        "object.entries": "^1.1.5",
+        "semver": "^6.3.0"
       },
       "engines": {
-        "node": ">= 6"
+        "node": "^10.12.0 || >=12.0.0"
       },
       "peerDependencies": {
-        "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0",
-        "eslint-plugin-import": "^2.22.1"
+        "eslint": "^7.32.0 || ^8.2.0",
+        "eslint-plugin-import": "^2.25.2"
+      }
+    },
+    "node_modules/eslint-config-airbnb-base/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
       }
     },
     "node_modules/eslint-config-prettier": {
-      "version": "6.15.0",
-      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz",
-      "integrity": "sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==",
+      "version": "9.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz",
+      "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
       "dev": true,
-      "dependencies": {
-        "get-stdin": "^6.0.0"
-      },
       "bin": {
-        "eslint-config-prettier-check": "bin/cli.js"
+        "eslint-config-prettier": "bin/cli.js"
       },
       "peerDependencies": {
-        "eslint": ">=3.14.1"
+        "eslint": ">=7.0.0"
       }
     },
     "node_modules/eslint-import-resolver-node": {
-      "version": "0.3.6",
-      "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
-      "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==",
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
+      "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
       "dev": true,
       "dependencies": {
         "debug": "^3.2.7",
-        "resolve": "^1.20.0"
+        "is-core-module": "^2.13.0",
+        "resolve": "^1.22.4"
       }
     },
     "node_modules/eslint-import-resolver-node/node_modules/debug": {
@@ -1877,17 +2224,20 @@
       }
     },
     "node_modules/eslint-module-utils": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz",
-      "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==",
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz",
+      "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==",
       "dev": true,
       "dependencies": {
-        "debug": "^3.2.7",
-        "find-up": "^2.1.0",
-        "pkg-dir": "^2.0.0"
+        "debug": "^3.2.7"
       },
       "engines": {
         "node": ">=4"
+      },
+      "peerDependenciesMeta": {
+        "eslint": {
+          "optional": true
+        }
       }
     },
     "node_modules/eslint-module-utils/node_modules/debug": {
@@ -1900,24 +2250,28 @@
       }
     },
     "node_modules/eslint-plugin-import": {
-      "version": "2.25.3",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz",
-      "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==",
+      "version": "2.29.1",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz",
+      "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==",
       "dev": true,
       "dependencies": {
-        "array-includes": "^3.1.4",
-        "array.prototype.flat": "^1.2.5",
-        "debug": "^2.6.9",
+        "array-includes": "^3.1.7",
+        "array.prototype.findlastindex": "^1.2.3",
+        "array.prototype.flat": "^1.3.2",
+        "array.prototype.flatmap": "^1.3.2",
+        "debug": "^3.2.7",
         "doctrine": "^2.1.0",
-        "eslint-import-resolver-node": "^0.3.6",
-        "eslint-module-utils": "^2.7.1",
-        "has": "^1.0.3",
-        "is-core-module": "^2.8.0",
+        "eslint-import-resolver-node": "^0.3.9",
+        "eslint-module-utils": "^2.8.0",
+        "hasown": "^2.0.0",
+        "is-core-module": "^2.13.1",
         "is-glob": "^4.0.3",
-        "minimatch": "^3.0.4",
-        "object.values": "^1.1.5",
-        "resolve": "^1.20.0",
-        "tsconfig-paths": "^3.11.0"
+        "minimatch": "^3.1.2",
+        "object.fromentries": "^2.0.7",
+        "object.groupby": "^1.0.1",
+        "object.values": "^1.1.7",
+        "semver": "^6.3.1",
+        "tsconfig-paths": "^3.15.0"
       },
       "engines": {
         "node": ">=4"
@@ -1927,12 +2281,12 @@
       }
     },
     "node_modules/eslint-plugin-import/node_modules/debug": {
-      "version": "2.6.9",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
       "dev": true,
       "dependencies": {
-        "ms": "2.0.0"
+        "ms": "^2.1.1"
       }
     },
     "node_modules/eslint-plugin-import/node_modules/doctrine": {
@@ -1959,30 +2313,37 @@
         "node": "*"
       }
     },
-    "node_modules/eslint-plugin-import/node_modules/ms": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-      "dev": true
+    "node_modules/eslint-plugin-import/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
     },
     "node_modules/eslint-plugin-jsx-a11y": {
-      "version": "6.5.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz",
-      "integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==",
-      "dev": true,
-      "dependencies": {
-        "@babel/runtime": "^7.16.3",
-        "aria-query": "^4.2.2",
-        "array-includes": "^3.1.4",
-        "ast-types-flow": "^0.0.7",
-        "axe-core": "^4.3.5",
-        "axobject-query": "^2.2.0",
-        "damerau-levenshtein": "^1.0.7",
+      "version": "6.8.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz",
+      "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/runtime": "^7.23.2",
+        "aria-query": "^5.3.0",
+        "array-includes": "^3.1.7",
+        "array.prototype.flatmap": "^1.3.2",
+        "ast-types-flow": "^0.0.8",
+        "axe-core": "=4.7.0",
+        "axobject-query": "^3.2.1",
+        "damerau-levenshtein": "^1.0.8",
         "emoji-regex": "^9.2.2",
-        "has": "^1.0.3",
-        "jsx-ast-utils": "^3.2.1",
-        "language-tags": "^1.0.5",
-        "minimatch": "^3.0.4"
+        "es-iterator-helpers": "^1.0.15",
+        "hasown": "^2.0.0",
+        "jsx-ast-utils": "^3.3.5",
+        "language-tags": "^1.0.9",
+        "minimatch": "^3.1.2",
+        "object.entries": "^1.1.7",
+        "object.fromentries": "^2.0.7"
       },
       "engines": {
         "node": ">=4.0"
@@ -2064,33 +2425,48 @@
       }
     },
     "node_modules/eslint-plugin-prettier": {
-      "version": "3.4.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz",
-      "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==",
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz",
+      "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==",
       "dev": true,
       "dependencies": {
-        "prettier-linter-helpers": "^1.0.0"
+        "prettier-linter-helpers": "^1.0.0",
+        "synckit": "^0.8.6"
       },
       "engines": {
-        "node": ">=6.0.0"
+        "node": "^14.18.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint-plugin-prettier"
       },
       "peerDependencies": {
-        "eslint": ">=5.0.0",
-        "prettier": ">=1.13.0"
+        "@types/eslint": ">=8.0.0",
+        "eslint": ">=8.0.0",
+        "eslint-config-prettier": "*",
+        "prettier": ">=3.0.0"
       },
       "peerDependenciesMeta": {
+        "@types/eslint": {
+          "optional": true
+        },
         "eslint-config-prettier": {
           "optional": true
         }
       }
     },
     "node_modules/eslint-plugin-promise": {
-      "version": "4.3.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz",
-      "integrity": "sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ==",
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.2.0.tgz",
+      "integrity": "sha512-QmAqwizauvnKOlifxyDj2ObfULpHQawlg/zQdgEixur9vl0CvZGv/LCJV2rtj3210QCoeGBzVMfMXqGAOr/4fA==",
       "dev": true,
       "engines": {
-        "node": ">=6"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0"
       }
     },
     "node_modules/eslint-scope": {
@@ -2131,21 +2507,52 @@
       }
     },
     "node_modules/eslint-visitor-keys": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
-      "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
       "dev": true,
       "engines": {
-        "node": ">=10"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
       }
     },
-    "node_modules/eslint/node_modules/ignore": {
-      "version": "4.0.6",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
-      "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+    "node_modules/eslint/node_modules/eslint-scope": {
+      "version": "7.2.2",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+      "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
       "dev": true,
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^5.2.0"
+      },
       "engines": {
-        "node": ">= 4"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint/node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/eslint/node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
       }
     },
     "node_modules/eslint/node_modules/minimatch": {
@@ -2161,45 +2568,26 @@
       }
     },
     "node_modules/espree": {
-      "version": "7.3.1",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
-      "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
+      "version": "9.6.1",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+      "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
       "dev": true,
       "dependencies": {
-        "acorn": "^7.4.0",
-        "acorn-jsx": "^5.3.1",
-        "eslint-visitor-keys": "^1.3.0"
+        "acorn": "^8.9.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.4.1"
       },
       "engines": {
-        "node": "^10.12.0 || >=12.0.0"
-      }
-    },
-    "node_modules/espree/node_modules/eslint-visitor-keys": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
-      "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/esprima": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-      "dev": true,
-      "bin": {
-        "esparse": "bin/esparse.js",
-        "esvalidate": "bin/esvalidate.js"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       },
-      "engines": {
-        "node": ">=4"
+      "funding": {
+        "url": "https://opencollective.com/eslint"
       }
     },
     "node_modules/esquery": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
-      "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
+      "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
       "dev": true,
       "dependencies": {
         "estraverse": "^5.1.0"
@@ -2265,29 +2653,6 @@
         "node": ">=0.8.x"
       }
     },
-    "node_modules/execa": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
-      "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
-      "dev": true,
-      "dependencies": {
-        "cross-spawn": "^7.0.3",
-        "get-stream": "^6.0.0",
-        "human-signals": "^2.1.0",
-        "is-stream": "^2.0.0",
-        "merge-stream": "^2.0.0",
-        "npm-run-path": "^4.0.1",
-        "onetime": "^5.1.2",
-        "signal-exit": "^3.0.3",
-        "strip-final-newline": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sindresorhus/execa?sponsor=1"
-      }
-    },
     "node_modules/fast-deep-equal": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -2301,9 +2666,9 @@
       "dev": true
     },
     "node_modules/fast-glob": {
-      "version": "3.2.7",
-      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz",
-      "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==",
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+      "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
       "dev": true,
       "dependencies": {
         "@nodelib/fs.stat": "^2.0.2",
@@ -2313,7 +2678,7 @@
         "micromatch": "^4.0.4"
       },
       "engines": {
-        "node": ">=8"
+        "node": ">=8.6.0"
       }
     },
     "node_modules/fast-json-stable-stringify": {
@@ -2325,7 +2690,7 @@
     "node_modules/fast-levenshtein": {
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
       "dev": true
     },
     "node_modules/fastest-levenshtein": {
@@ -2335,9 +2700,9 @@
       "dev": true
     },
     "node_modules/fastq": {
-      "version": "1.13.0",
-      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
-      "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
+      "version": "1.17.1",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+      "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
       "dev": true,
       "dependencies": {
         "reusify": "^1.0.4"
@@ -2356,9 +2721,9 @@
       }
     },
     "node_modules/fill-range": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
       "dev": true,
       "dependencies": {
         "to-regex-range": "^5.0.1"
@@ -2368,15 +2733,19 @@
       }
     },
     "node_modules/find-up": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
-      "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
       "dev": true,
       "dependencies": {
-        "locate-path": "^2.0.0"
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
       },
       "engines": {
-        "node": ">=4"
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/flat": {
@@ -2407,6 +2776,15 @@
       "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==",
       "dev": true
     },
+    "node_modules/for-each": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+      "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+      "dev": true,
+      "dependencies": {
+        "is-callable": "^1.1.3"
+      }
+    },
     "node_modules/fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -2428,69 +2806,78 @@
       }
     },
     "node_modules/function-bind": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
-      "dev": true
-    },
-    "node_modules/functional-red-black-tree": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
-      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
-      "dev": true
-    },
-    "node_modules/get-caller-file": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
       "dev": true,
-      "engines": {
-        "node": "6.* || 8.* || >= 10.*"
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/get-intrinsic": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
-      "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+    "node_modules/function.prototype.name": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
+      "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
       "dev": true,
       "dependencies": {
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3",
-        "has-symbols": "^1.0.1"
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.2.0",
+        "es-abstract": "^1.22.1",
+        "functions-have-names": "^1.2.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/get-stdin": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
-      "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
+    "node_modules/functions-have-names": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
       "dev": true,
       "engines": {
-        "node": ">=4"
+        "node": "6.* || 8.* || >= 10.*"
       }
     },
-    "node_modules/get-stream": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
-      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+    "node_modules/get-intrinsic": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+      "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
       "dev": true,
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "has-proto": "^1.0.1",
+        "has-symbols": "^1.0.3",
+        "hasown": "^2.0.0"
+      },
       "engines": {
-        "node": ">=10"
+        "node": ">= 0.4"
       },
       "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/get-symbol-description": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
-      "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
+      "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "get-intrinsic": "^1.1.1"
+        "call-bind": "^1.0.5",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.4"
       },
       "engines": {
         "node": ">= 0.4"
@@ -2550,9 +2937,9 @@
       }
     },
     "node_modules/globals": {
-      "version": "13.12.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz",
-      "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==",
+      "version": "13.24.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+      "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
       "dev": true,
       "dependencies": {
         "type-fest": "^0.20.2"
@@ -2564,30 +2951,64 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/globalthis": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+      "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+      "dev": true,
+      "dependencies": {
+        "define-properties": "^1.2.1",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/globby": {
-      "version": "11.0.4",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz",
-      "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==",
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
       "dev": true,
       "dependencies": {
         "array-union": "^2.1.0",
         "dir-glob": "^3.0.1",
-        "fast-glob": "^3.1.1",
-        "ignore": "^5.1.4",
-        "merge2": "^1.3.0",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
         "slash": "^3.0.0"
       },
       "engines": {
         "node": ">=10"
       },
       "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+      "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.1.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/graceful-fs": {
-      "version": "4.2.9",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
-      "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+      "dev": true
+    },
+    "node_modules/graphemer": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+      "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
       "dev": true
     },
     "node_modules/growl": {
@@ -2599,22 +3020,10 @@
         "node": ">=4.x"
       }
     },
-    "node_modules/has": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
-      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
-      "dev": true,
-      "dependencies": {
-        "function-bind": "^1.1.1"
-      },
-      "engines": {
-        "node": ">= 0.4.0"
-      }
-    },
     "node_modules/has-bigints": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz",
-      "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
+      "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
       "dev": true,
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
@@ -2629,10 +3038,34 @@
         "node": ">=8"
       }
     },
-    "node_modules/has-symbols": {
+    "node_modules/has-property-descriptors": {
       "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
-      "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+      "dev": true,
+      "dependencies": {
+        "es-define-property": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-proto": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+      "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
       "dev": true,
       "engines": {
         "node": ">= 0.4"
@@ -2642,12 +3075,12 @@
       }
     },
     "node_modules/has-tostringtag": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
-      "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
       "dev": true,
       "dependencies": {
-        "has-symbols": "^1.0.2"
+        "has-symbols": "^1.0.3"
       },
       "engines": {
         "node": ">= 0.4"
@@ -2656,6 +3089,18 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/hasown": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+      "dev": true,
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
     "node_modules/he": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
@@ -2666,39 +3111,46 @@
       }
     },
     "node_modules/http-proxy-agent": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
-      "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+      "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
       "dev": true,
       "dependencies": {
-        "@tootallnate/once": "1",
-        "agent-base": "6",
-        "debug": "4"
+        "agent-base": "^7.1.0",
+        "debug": "^4.3.4"
       },
       "engines": {
-        "node": ">= 6"
+        "node": ">= 14"
       }
     },
-    "node_modules/https-proxy-agent": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
-      "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
+    "node_modules/http-proxy-agent/node_modules/debug": {
+      "version": "4.3.5",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+      "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
       "dev": true,
       "dependencies": {
-        "agent-base": "6",
-        "debug": "4"
+        "ms": "2.1.2"
       },
       "engines": {
-        "node": ">= 6"
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
       }
     },
-    "node_modules/human-signals": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
-      "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+    "node_modules/https-proxy-agent": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz",
+      "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==",
       "dev": true,
+      "dependencies": {
+        "agent-base": "^7.0.2",
+        "debug": "4"
+      },
       "engines": {
-        "node": ">=10.17.0"
+        "node": ">= 14"
       }
     },
     "node_modules/iconv-lite": {
@@ -2712,10 +3164,30 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
     "node_modules/ignore": {
-      "version": "5.1.9",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz",
-      "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==",
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
+      "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
       "dev": true,
       "engines": {
         "node": ">= 4"
@@ -2820,15 +3292,6 @@
         "node": ">=6"
       }
     },
-    "node_modules/import-local/node_modules/path-exists": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-      "dev": true,
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/import-local/node_modules/pkg-dir": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
@@ -2867,13 +3330,13 @@
       "dev": true
     },
     "node_modules/internal-slot": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
-      "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
+      "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==",
       "dev": true,
       "dependencies": {
-        "get-intrinsic": "^1.1.0",
-        "has": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "hasown": "^2.0.0",
         "side-channel": "^1.0.4"
       },
       "engines": {
@@ -2881,12 +3344,43 @@
       }
     },
     "node_modules/interpret": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
-      "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz",
+      "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/is-array-buffer": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
+      "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-async-function": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
+      "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==",
       "dev": true,
+      "dependencies": {
+        "has-tostringtag": "^1.0.0"
+      },
       "engines": {
-        "node": ">= 0.10"
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/is-bigint": {
@@ -2930,9 +3424,9 @@
       }
     },
     "node_modules/is-callable": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
-      "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+      "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
       "dev": true,
       "engines": {
         "node": ">= 0.4"
@@ -2942,12 +3436,27 @@
       }
     },
     "node_modules/is-core-module": {
-      "version": "2.8.0",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz",
-      "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==",
+      "version": "2.13.1",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
+      "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
+      "dev": true,
+      "dependencies": {
+        "hasown": "^2.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-data-view": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
+      "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
       "dev": true,
       "dependencies": {
-        "has": "^1.0.3"
+        "is-typed-array": "^1.1.13"
+      },
+      "engines": {
+        "node": ">= 0.4"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
@@ -2977,6 +3486,18 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/is-finalizationregistry": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz",
+      "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/is-fullwidth-code-point": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@@ -2986,6 +3507,21 @@
         "node": ">=8"
       }
     },
+    "node_modules/is-generator-function": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
+      "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
+      "dev": true,
+      "dependencies": {
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/is-glob": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
@@ -2998,10 +3534,34 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/is-interactive": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz",
+      "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-map": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
+      "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/is-negative-zero": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
-      "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
+      "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
       "dev": true,
       "engines": {
         "node": ">= 0.4"
@@ -3020,9 +3580,9 @@
       }
     },
     "node_modules/is-number-object": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz",
-      "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==",
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
+      "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
       "dev": true,
       "dependencies": {
         "has-tostringtag": "^1.0.0"
@@ -3034,6 +3594,15 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-path-inside": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/is-plain-obj": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
@@ -3071,25 +3640,31 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/is-shared-array-buffer": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz",
-      "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==",
+    "node_modules/is-set": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
+      "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
       "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/is-stream": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
-      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+    "node_modules/is-shared-array-buffer": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
+      "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
       "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.7"
+      },
       "engines": {
-        "node": ">=8"
+        "node": ">= 0.4"
       },
       "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/is-string": {
@@ -3122,6 +3697,21 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-typed-array": {
+      "version": "1.1.13",
+      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
+      "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
+      "dev": true,
+      "dependencies": {
+        "which-typed-array": "^1.1.14"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/is-unicode-supported": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
@@ -3134,18 +3724,52 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/is-weakmap": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
+      "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/is-weakref": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz",
-      "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
+      "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakset": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz",
+      "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.0"
+        "call-bind": "^1.0.7",
+        "get-intrinsic": "^1.2.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/isarray": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+      "dev": true
+    },
     "node_modules/isexe": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -3162,24 +3786,37 @@
       }
     },
     "node_modules/istextorbinary": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-6.0.0.tgz",
-      "integrity": "sha512-4j3UqQCa06GAf6QHlN3giz2EeFU7qc6Q5uB/aY7Gmb3xmLDLepDOtsZqkb4sCfJgFvTbLUinNw0kHgHs8XOHoQ==",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-7.0.0.tgz",
+      "integrity": "sha512-RrJZgAttvlKBUoG8zGS2oyl12Exb1PJ6K6rSFH+9tEXadXMT/mRd0Lm4zwQN29jQyM6iGUFzL5HStEmismPNgw==",
       "dependencies": {
-        "binaryextensions": "^4.18.0",
-        "textextensions": "^5.14.0"
+        "binaryextensions": "^4.19.0",
+        "textextensions": "^5.16.0"
       },
       "engines": {
-        "node": ">=10"
+        "node": ">=14"
       },
       "funding": {
         "url": "https://bevry.me/fund"
       }
     },
+    "node_modules/iterator.prototype": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz",
+      "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==",
+      "dev": true,
+      "dependencies": {
+        "define-properties": "^1.2.1",
+        "get-intrinsic": "^1.2.1",
+        "has-symbols": "^1.0.3",
+        "reflect.getprototypeof": "^1.0.4",
+        "set-function-name": "^2.0.1"
+      }
+    },
     "node_modules/jest-worker": {
-      "version": "27.4.0",
-      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.0.tgz",
-      "integrity": "sha512-4WuKcUxtzxBoKOUFbt1MtTY9fJwPVD4aN/4Cgxee7OLetPZn5as2bjfZz98XSf2Zq1JFfhqPZpS+43BmWXKgCA==",
+      "version": "27.5.1",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+      "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
       "dev": true,
       "dependencies": {
         "@types/node": "*",
@@ -3205,20 +3842,13 @@
         "url": "https://github.com/chalk/supports-color?sponsor=1"
       }
     },
-    "node_modules/js-tokens": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-      "dev": true
-    },
     "node_modules/js-yaml": {
-      "version": "3.14.1",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
-      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
       "dev": true,
       "dependencies": {
-        "argparse": "^1.0.7",
-        "esprima": "^4.0.0"
+        "argparse": "^2.0.1"
       },
       "bin": {
         "js-yaml": "bin/js-yaml.js"
@@ -3255,13 +3885,15 @@
       }
     },
     "node_modules/jsx-ast-utils": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz",
-      "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==",
+      "version": "3.3.5",
+      "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
+      "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
       "dev": true,
       "dependencies": {
-        "array-includes": "^3.1.3",
-        "object.assign": "^4.1.2"
+        "array-includes": "^3.1.6",
+        "array.prototype.flat": "^1.3.1",
+        "object.assign": "^4.1.4",
+        "object.values": "^1.1.6"
       },
       "engines": {
         "node": ">=4.0"
@@ -3298,18 +3930,21 @@
       }
     },
     "node_modules/language-subtag-registry": {
-      "version": "0.3.21",
-      "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
-      "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==",
+      "version": "0.3.23",
+      "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
+      "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==",
       "dev": true
     },
     "node_modules/language-tags": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
-      "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=",
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz",
+      "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==",
       "dev": true,
       "dependencies": {
-        "language-subtag-registry": "~0.3.2"
+        "language-subtag-registry": "^0.3.20"
+      },
+      "engines": {
+        "node": ">=0.10"
       }
     },
     "node_modules/levn": {
@@ -3343,31 +3978,19 @@
         "node": ">=6.11.5"
       }
     },
-    "node_modules/loader-utils": {
-      "version": "1.4.2",
-      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
-      "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
-      "dev": true,
-      "dependencies": {
-        "big.js": "^5.2.2",
-        "emojis-list": "^3.0.0",
-        "json5": "^1.0.1"
-      },
-      "engines": {
-        "node": ">=4.0.0"
-      }
-    },
     "node_modules/locate-path": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
-      "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
       "dev": true,
       "dependencies": {
-        "p-locate": "^2.0.0",
-        "path-exists": "^3.0.0"
+        "p-locate": "^5.0.0"
       },
       "engines": {
-        "node": ">=4"
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/lodash.merge": {
@@ -3376,12 +3999,6 @@
       "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
       "dev": true
     },
-    "node_modules/lodash.truncate": {
-      "version": "4.4.2",
-      "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
-      "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
-      "dev": true
-    },
     "node_modules/log-symbols": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -3398,31 +4015,6 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/lru-cache": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-      "dev": true,
-      "dependencies": {
-        "yallist": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/memory-fs": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
-      "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
-      "dev": true,
-      "dependencies": {
-        "errno": "^0.1.3",
-        "readable-stream": "^2.0.1"
-      },
-      "engines": {
-        "node": ">=4.3.0 <5.0.0 || >=5.10"
-      }
-    },
     "node_modules/merge-stream": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -3482,9 +4074,9 @@
       }
     },
     "node_modules/minimatch": {
-      "version": "9.0.3",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
-      "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+      "version": "9.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
+      "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
       "dependencies": {
         "brace-expansion": "^2.0.1"
       },
@@ -3555,28 +4147,6 @@
         "url": "https://opencollective.com/mochajs"
       }
     },
-    "node_modules/mocha/node_modules/argparse": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-      "dev": true
-    },
-    "node_modules/mocha/node_modules/find-up": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
-      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
-      "dev": true,
-      "dependencies": {
-        "locate-path": "^6.0.0",
-        "path-exists": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
     "node_modules/mocha/node_modules/glob": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
@@ -3609,33 +4179,6 @@
         "node": "*"
       }
     },
-    "node_modules/mocha/node_modules/js-yaml": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-      "dev": true,
-      "dependencies": {
-        "argparse": "^2.0.1"
-      },
-      "bin": {
-        "js-yaml": "bin/js-yaml.js"
-      }
-    },
-    "node_modules/mocha/node_modules/locate-path": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
-      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
-      "dev": true,
-      "dependencies": {
-        "p-locate": "^5.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
     "node_modules/mocha/node_modules/minimatch": {
       "version": "4.2.1",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz",
@@ -3654,45 +4197,6 @@
       "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
       "dev": true
     },
-    "node_modules/mocha/node_modules/p-limit": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
-      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
-      "dev": true,
-      "dependencies": {
-        "yocto-queue": "^0.1.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/mocha/node_modules/p-locate": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
-      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
-      "dev": true,
-      "dependencies": {
-        "p-limit": "^3.0.2"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/mocha/node_modules/path-exists": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-      "dev": true,
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/mocha/node_modules/supports-color": {
       "version": "8.1.1",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
@@ -3759,9 +4263,9 @@
       }
     },
     "node_modules/node-releases": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
-      "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
+      "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/normalize-path": {
@@ -3773,22 +4277,10 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/npm-run-path": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
-      "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
-      "dev": true,
-      "dependencies": {
-        "path-key": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/object-inspect": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
-      "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==",
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
+      "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
       "dev": true,
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
@@ -3804,14 +4296,14 @@
       }
     },
     "node_modules/object.assign": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
-      "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+      "version": "4.1.5",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
+      "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.0",
-        "define-properties": "^1.1.3",
-        "has-symbols": "^1.0.1",
+        "call-bind": "^1.0.5",
+        "define-properties": "^1.2.1",
+        "has-symbols": "^1.0.3",
         "object-keys": "^1.1.1"
       },
       "engines": {
@@ -3822,28 +4314,60 @@
       }
     },
     "node_modules/object.entries": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz",
-      "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==",
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
+      "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.1"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/object.fromentries": {
+      "version": "2.0.8",
+      "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
+      "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object.groupby": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
+      "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2"
       },
       "engines": {
         "node": ">= 0.4"
       }
     },
     "node_modules/object.values": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz",
-      "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz",
+      "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.1"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
       },
       "engines": {
         "node": ">= 0.4"
@@ -3877,9 +4401,9 @@
       }
     },
     "node_modules/optionator": {
-      "version": "0.9.1",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
-      "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+      "version": "0.9.4",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+      "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
       "dev": true,
       "dependencies": {
         "deep-is": "^0.1.3",
@@ -3887,43 +4411,153 @@
         "levn": "^0.4.1",
         "prelude-ls": "^1.2.1",
         "type-check": "^0.4.0",
-        "word-wrap": "^1.2.3"
+        "word-wrap": "^1.2.5"
       },
       "engines": {
         "node": ">= 0.8.0"
       }
     },
-    "node_modules/p-limit": {
+    "node_modules/ora": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz",
+      "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^5.3.0",
+        "cli-cursor": "^4.0.0",
+        "cli-spinners": "^2.9.0",
+        "is-interactive": "^2.0.0",
+        "is-unicode-supported": "^1.3.0",
+        "log-symbols": "^5.1.0",
+        "stdin-discarder": "^0.1.0",
+        "string-width": "^6.1.0",
+        "strip-ansi": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ora/node_modules/ansi-regex": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+      "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "node_modules/ora/node_modules/chalk": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+      "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
+      "dev": true,
+      "engines": {
+        "node": "^12.17.0 || ^14.13 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/ora/node_modules/emoji-regex": {
+      "version": "10.3.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz",
+      "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==",
+      "dev": true
+    },
+    "node_modules/ora/node_modules/is-unicode-supported": {
       "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
-      "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
+      "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ora/node_modules/log-symbols": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz",
+      "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==",
       "dev": true,
       "dependencies": {
-        "p-try": "^1.0.0"
+        "chalk": "^5.0.0",
+        "is-unicode-supported": "^1.1.0"
       },
       "engines": {
-        "node": ">=4"
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/p-locate": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
-      "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+    "node_modules/ora/node_modules/string-width": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz",
+      "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==",
       "dev": true,
       "dependencies": {
-        "p-limit": "^1.1.0"
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^10.2.1",
+        "strip-ansi": "^7.0.1"
       },
       "engines": {
-        "node": ">=4"
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/p-try": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
-      "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+    "node_modules/ora/node_modules/strip-ansi": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+      "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
       "dev": true,
+      "dependencies": {
+        "ansi-regex": "^6.0.1"
+      },
       "engines": {
-        "node": ">=4"
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
+    "node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/pako": {
@@ -3951,12 +4585,12 @@
       "dev": true
     },
     "node_modules/path-exists": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-      "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
       "dev": true,
       "engines": {
-        "node": ">=4"
+        "node": ">=8"
       }
     },
     "node_modules/path-is-absolute": {
@@ -3993,9 +4627,9 @@
       }
     },
     "node_modules/picocolors": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
-      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
+      "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
       "dev": true
     },
     "node_modules/picomatch": {
@@ -4010,16 +4644,13 @@
         "url": "https://github.com/sponsors/jonschlinkert"
       }
     },
-    "node_modules/pkg-dir": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
-      "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=",
+    "node_modules/possible-typed-array-names": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
+      "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
       "dev": true,
-      "dependencies": {
-        "find-up": "^2.1.0"
-      },
       "engines": {
-        "node": ">=4"
+        "node": ">= 0.4"
       }
     },
     "node_modules/prelude-ls": {
@@ -4032,15 +4663,18 @@
       }
     },
     "node_modules/prettier": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz",
-      "integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==",
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.1.tgz",
+      "integrity": "sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==",
       "dev": true,
       "bin": {
-        "prettier": "bin-prettier.js"
+        "prettier": "bin/prettier.cjs"
       },
       "engines": {
-        "node": ">=10.13.0"
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
       }
     },
     "node_modules/prettier-linter-helpers": {
@@ -4061,15 +4695,6 @@
       "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
       "dev": true
     },
-    "node_modules/progress": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
-      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.4.0"
-      }
-    },
     "node_modules/prompts": {
       "version": "2.4.2",
       "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
@@ -4083,12 +4708,6 @@
         "node": ">= 6"
       }
     },
-    "node_modules/prr": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
-      "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
-      "dev": true
-    },
     "node_modules/punycode": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
@@ -4167,23 +4786,62 @@
       }
     },
     "node_modules/rechoir": {
-      "version": "0.7.1",
-      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
-      "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==",
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
+      "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==",
       "dev": true,
       "dependencies": {
-        "resolve": "^1.9.0"
+        "resolve": "^1.20.0"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      }
+    },
+    "node_modules/reflect.getprototypeof": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
+      "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.1",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.4",
+        "globalthis": "^1.0.3",
+        "which-builtin-type": "^1.1.3"
       },
       "engines": {
-        "node": ">= 0.10"
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/regenerator-runtime": {
-      "version": "0.13.9",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
-      "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
+      "version": "0.14.1",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+      "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
       "dev": true
     },
+    "node_modules/regexp.prototype.flags": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
+      "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.6",
+        "define-properties": "^1.2.1",
+        "es-errors": "^1.3.0",
+        "set-function-name": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/regexpp": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
@@ -4205,23 +4863,18 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/require-from-string": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
-      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/resolve": {
-      "version": "1.20.0",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
-      "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
+      "version": "1.22.8",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+      "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
       "dev": true,
       "dependencies": {
-        "is-core-module": "^2.2.0",
-        "path-parse": "^1.0.6"
+        "is-core-module": "^2.13.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
@@ -4257,6 +4910,22 @@
         "node": ">=4"
       }
     },
+    "node_modules/restore-cursor": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
+      "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
+      "dev": true,
+      "dependencies": {
+        "onetime": "^5.1.0",
+        "signal-exit": "^3.0.2"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/reusify": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -4305,6 +4974,24 @@
         "queue-microtask": "^1.2.2"
       }
     },
+    "node_modules/safe-array-concat": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
+      "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "get-intrinsic": "^1.2.4",
+        "has-symbols": "^1.0.3",
+        "isarray": "^2.0.5"
+      },
+      "engines": {
+        "node": ">=0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/safe-buffer": {
       "version": "5.2.1",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -4325,15 +5012,32 @@
         }
       ]
     },
+    "node_modules/safe-regex-test": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
+      "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.6",
+        "es-errors": "^1.3.0",
+        "is-regex": "^1.1.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/safer-buffer": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
     },
     "node_modules/schema-utils": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
-      "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
+      "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
       "dev": true,
       "dependencies": {
         "@types/json-schema": "^7.0.8",
@@ -4349,13 +5053,10 @@
       }
     },
     "node_modules/semver": {
-      "version": "7.5.4",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
-      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+      "version": "7.6.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
+      "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
       "dev": true,
-      "dependencies": {
-        "lru-cache": "^6.0.0"
-      },
       "bin": {
         "semver": "bin/semver.js"
       },
@@ -4372,6 +5073,38 @@
         "randombytes": "^2.1.0"
       }
     },
+    "node_modules/set-function-length": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+      "dev": true,
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/set-function-name": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+      "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+      "dev": true,
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "functions-have-names": "^1.2.3",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
     "node_modules/setimmediate": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
@@ -4417,23 +5150,27 @@
       "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="
     },
     "node_modules/side-channel": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
-      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+      "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.0",
-        "get-intrinsic": "^1.0.2",
-        "object-inspect": "^1.9.0"
+        "call-bind": "^1.0.7",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.4",
+        "object-inspect": "^1.13.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/signal-exit": {
-      "version": "3.0.6",
-      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
-      "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==",
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+      "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
       "dev": true
     },
     "node_modules/sisteransi": {
@@ -4451,30 +5188,13 @@
         "node": ">=8"
       }
     },
-    "node_modules/slice-ansi": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
-      "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
-      "dev": true,
-      "dependencies": {
-        "ansi-styles": "^4.0.0",
-        "astral-regex": "^2.0.0",
-        "is-fullwidth-code-point": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/slice-ansi?sponsor=1"
-      }
-    },
     "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==",
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+      "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
       "dev": true,
       "engines": {
-        "node": ">=0.10.0"
+        "node": ">= 8"
       }
     },
     "node_modules/source-map-support": {
@@ -4487,17 +5207,35 @@
         "source-map": "^0.6.0"
       }
     },
-    "node_modules/sprintf-js": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
-      "dev": true
+    "node_modules/source-map-support/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/stack-chain": {
       "version": "1.3.7",
       "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz",
       "integrity": "sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU="
     },
+    "node_modules/stdin-discarder": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz",
+      "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==",
+      "dev": true,
+      "dependencies": {
+        "bl": "^5.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/string_decoder": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
@@ -4533,27 +5271,50 @@
       "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
       "dev": true
     },
+    "node_modules/string.prototype.trim": {
+      "version": "1.2.9",
+      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
+      "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.0",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/string.prototype.trimend": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
-      "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
+      "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/string.prototype.trimstart": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
-      "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+      "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
@@ -4574,21 +5335,12 @@
     "node_modules/strip-bom": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-      "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+      "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
       "dev": true,
       "engines": {
         "node": ">=4"
       }
     },
-    "node_modules/strip-final-newline": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
-      "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
-      "dev": true,
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/strip-json-comments": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -4613,61 +5365,51 @@
         "node": ">=8"
       }
     },
-    "node_modules/table": {
-      "version": "6.7.3",
-      "resolved": "https://registry.npmjs.org/table/-/table-6.7.3.tgz",
-      "integrity": "sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw==",
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
       "dev": true,
-      "dependencies": {
-        "ajv": "^8.0.1",
-        "lodash.truncate": "^4.4.2",
-        "slice-ansi": "^4.0.0",
-        "string-width": "^4.2.3",
-        "strip-ansi": "^6.0.1"
-      },
       "engines": {
-        "node": ">=10.0.0"
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/table/node_modules/ajv": {
-      "version": "8.8.2",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz",
-      "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==",
+    "node_modules/synckit": {
+      "version": "0.8.8",
+      "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz",
+      "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==",
       "dev": true,
       "dependencies": {
-        "fast-deep-equal": "^3.1.1",
-        "json-schema-traverse": "^1.0.0",
-        "require-from-string": "^2.0.2",
-        "uri-js": "^4.2.2"
+        "@pkgr/core": "^0.1.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": "^14.18.0 || >=16.0.0"
       },
       "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/epoberezkin"
+        "url": "https://opencollective.com/unts"
       }
     },
-    "node_modules/table/node_modules/json-schema-traverse": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
-      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
-      "dev": true
-    },
     "node_modules/tapable": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
-      "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+      "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
       "dev": true,
       "engines": {
         "node": ">=6"
       }
     },
     "node_modules/terser": {
-      "version": "5.14.2",
-      "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz",
-      "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==",
+      "version": "5.31.1",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz",
+      "integrity": "sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==",
       "dev": true,
       "dependencies": {
-        "@jridgewell/source-map": "^0.3.2",
-        "acorn": "^8.5.0",
+        "@jridgewell/source-map": "^0.3.3",
+        "acorn": "^8.8.2",
         "commander": "^2.20.0",
         "source-map-support": "~0.5.20"
       },
@@ -4679,16 +5421,16 @@
       }
     },
     "node_modules/terser-webpack-plugin": {
-      "version": "5.2.5",
-      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.5.tgz",
-      "integrity": "sha512-3luOVHku5l0QBeYS8r4CdHYWEGMmIj3H1U64jgkdZzECcSOJAyJ9TjuqcQZvw1Y+4AOBN9SeYJPJmFn2cM4/2g==",
+      "version": "5.3.10",
+      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz",
+      "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==",
       "dev": true,
       "dependencies": {
-        "jest-worker": "^27.0.6",
+        "@jridgewell/trace-mapping": "^0.3.20",
+        "jest-worker": "^27.4.5",
         "schema-utils": "^3.1.1",
-        "serialize-javascript": "^6.0.0",
-        "source-map": "^0.6.1",
-        "terser": "^5.7.2"
+        "serialize-javascript": "^6.0.1",
+        "terser": "^5.26.0"
       },
       "engines": {
         "node": ">= 10.13.0"
@@ -4712,16 +5454,13 @@
         }
       }
     },
-    "node_modules/terser/node_modules/acorn": {
-      "version": "8.7.1",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
-      "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
+    "node_modules/terser-webpack-plugin/node_modules/serialize-javascript": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+      "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
       "dev": true,
-      "bin": {
-        "acorn": "bin/acorn"
-      },
-      "engines": {
-        "node": ">=0.4.0"
+      "dependencies": {
+        "randombytes": "^2.1.0"
       }
     },
     "node_modules/text-table": {
@@ -4753,190 +5492,211 @@
         "node": ">=8.0"
       }
     },
-    "node_modules/ts-loader": {
-      "version": "7.0.5",
-      "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-7.0.5.tgz",
-      "integrity": "sha512-zXypEIT6k3oTc+OZNx/cqElrsbBtYqDknf48OZos0NQ3RTt045fBIU8RRSu+suObBzYB355aIPGOe/3kj9h7Ig==",
+    "node_modules/ts-api-utils": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
+      "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
       "dev": true,
-      "dependencies": {
-        "chalk": "^2.3.0",
-        "enhanced-resolve": "^4.0.0",
-        "loader-utils": "^1.0.2",
-        "micromatch": "^4.0.0",
-        "semver": "^6.0.0"
-      },
       "engines": {
-        "node": ">=10.0.0"
+        "node": ">=16"
       },
       "peerDependencies": {
-        "typescript": "*"
+        "typescript": ">=4.2.0"
       }
     },
-    "node_modules/ts-loader/node_modules/ansi-styles": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+    "node_modules/ts-loader": {
+      "version": "9.5.1",
+      "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz",
+      "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==",
       "dev": true,
       "dependencies": {
-        "color-convert": "^1.9.0"
+        "chalk": "^4.1.0",
+        "enhanced-resolve": "^5.0.0",
+        "micromatch": "^4.0.0",
+        "semver": "^7.3.4",
+        "source-map": "^0.7.4"
       },
       "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/ts-loader/node_modules/chalk": {
-      "version": "2.4.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-      "dev": true,
-      "dependencies": {
-        "ansi-styles": "^3.2.1",
-        "escape-string-regexp": "^1.0.5",
-        "supports-color": "^5.3.0"
+        "node": ">=12.0.0"
       },
-      "engines": {
-        "node": ">=4"
+      "peerDependencies": {
+        "typescript": "*",
+        "webpack": "^5.0.0"
       }
     },
-    "node_modules/ts-loader/node_modules/color-convert": {
-      "version": "1.9.3",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+    "node_modules/tsconfig-paths": {
+      "version": "3.15.0",
+      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
+      "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
       "dev": true,
       "dependencies": {
-        "color-name": "1.1.3"
+        "@types/json5": "^0.0.29",
+        "json5": "^1.0.2",
+        "minimist": "^1.2.6",
+        "strip-bom": "^3.0.0"
       }
     },
-    "node_modules/ts-loader/node_modules/color-name": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+    "node_modules/tslib": {
+      "version": "2.6.3",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
+      "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
       "dev": true
     },
-    "node_modules/ts-loader/node_modules/escape-string-regexp": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+    "node_modules/type-check": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
       "dev": true,
+      "dependencies": {
+        "prelude-ls": "^1.2.1"
+      },
       "engines": {
-        "node": ">=0.8.0"
+        "node": ">= 0.8.0"
       }
     },
-    "node_modules/ts-loader/node_modules/has-flag": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+    "node_modules/type-fest": {
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
       "dev": true,
       "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/ts-loader/node_modules/semver": {
-      "version": "6.3.1",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
-      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
-      "dev": true,
-      "bin": {
-        "semver": "bin/semver.js"
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/ts-loader/node_modules/supports-color": {
-      "version": "5.5.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+    "node_modules/typed-array-buffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
+      "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==",
       "dev": true,
       "dependencies": {
-        "has-flag": "^3.0.0"
+        "call-bind": "^1.0.7",
+        "es-errors": "^1.3.0",
+        "is-typed-array": "^1.1.13"
       },
       "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/tsconfig-paths": {
-      "version": "3.12.0",
-      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz",
-      "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==",
-      "dev": true,
-      "dependencies": {
-        "@types/json5": "^0.0.29",
-        "json5": "^1.0.1",
-        "minimist": "^1.2.0",
-        "strip-bom": "^3.0.0"
+        "node": ">= 0.4"
       }
     },
-    "node_modules/tslib": {
-      "version": "1.14.1",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
-      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
-      "dev": true
-    },
-    "node_modules/tsutils": {
-      "version": "3.21.0",
-      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
-      "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+    "node_modules/typed-array-byte-length": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz",
+      "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==",
       "dev": true,
       "dependencies": {
-        "tslib": "^1.8.1"
+        "call-bind": "^1.0.7",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "has-proto": "^1.0.3",
+        "is-typed-array": "^1.1.13"
       },
       "engines": {
-        "node": ">= 6"
+        "node": ">= 0.4"
       },
-      "peerDependencies": {
-        "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
-      }
-    },
-    "node_modules/type-check": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
-      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/typed-array-byte-offset": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz",
+      "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==",
       "dev": true,
       "dependencies": {
-        "prelude-ls": "^1.2.1"
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.7",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "has-proto": "^1.0.3",
+        "is-typed-array": "^1.1.13"
       },
       "engines": {
-        "node": ">= 0.8.0"
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/type-fest": {
-      "version": "0.20.2",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
-      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+    "node_modules/typed-array-length": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz",
+      "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==",
       "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "has-proto": "^1.0.3",
+        "is-typed-array": "^1.1.13",
+        "possible-typed-array-names": "^1.0.0"
+      },
       "engines": {
-        "node": ">=10"
+        "node": ">= 0.4"
       },
       "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/typescript": {
-      "version": "4.5.2",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz",
-      "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==",
+      "version": "5.4.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+      "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
       "dev": true,
       "bin": {
         "tsc": "bin/tsc",
         "tsserver": "bin/tsserver"
       },
       "engines": {
-        "node": ">=4.2.0"
+        "node": ">=14.17"
       }
     },
     "node_modules/unbox-primitive": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
-      "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
+      "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
       "dev": true,
       "dependencies": {
-        "function-bind": "^1.1.1",
-        "has-bigints": "^1.0.1",
-        "has-symbols": "^1.0.2",
+        "call-bind": "^1.0.2",
+        "has-bigints": "^1.0.2",
+        "has-symbols": "^1.0.3",
         "which-boxed-primitive": "^1.0.2"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/update-browserslist-db": {
+      "version": "1.0.16",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz",
+      "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "escalade": "^3.1.2",
+        "picocolors": "^1.0.1"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
     "node_modules/uri-js": {
       "version": "4.4.1",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -4952,32 +5712,11 @@
       "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
       "dev": true
     },
-    "node_modules/v8-compile-cache": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
-      "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
-      "dev": true
-    },
     "node_modules/vscode-cache": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/vscode-cache/-/vscode-cache-0.3.0.tgz",
       "integrity": "sha1-fMOWZOvZnTcDAwaLibxMlWFGZ8A="
     },
-    "node_modules/vscode-debugadapter-testsupport": {
-      "version": "1.50.0",
-      "resolved": "https://registry.npmjs.org/vscode-debugadapter-testsupport/-/vscode-debugadapter-testsupport-1.50.0.tgz",
-      "integrity": "sha512-stS8yE8le59FLeKvCvdSY6PoYtmUXMxR1WiAW2JS65Sg7ip+yQm+WMKQZz8Dat0vtUF4ALcaKf/P+KjPTdzVww==",
-      "dev": true,
-      "dependencies": {
-        "vscode-debugprotocol": "1.50.1"
-      }
-    },
-    "node_modules/vscode-debugprotocol": {
-      "version": "1.50.1",
-      "resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.50.1.tgz",
-      "integrity": "sha512-kIHIipklHnSjBm2KkRqTJLKL2FMZlJl0+/qpJt2y62YOamMNwcxNATnXXRgAwnzKKRMweqp93tJ83UTJ8+O7SQ==",
-      "dev": true
-    },
     "node_modules/vscode-extension-telemetry": {
       "version": "0.1.7",
       "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.7.tgz",
@@ -4990,9 +5729,9 @@
       }
     },
     "node_modules/watchpack": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
-      "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz",
+      "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==",
       "dev": true,
       "dependencies": {
         "glob-to-regexp": "^0.4.1",
@@ -5003,34 +5742,34 @@
       }
     },
     "node_modules/webpack": {
-      "version": "5.76.0",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz",
-      "integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==",
+      "version": "5.91.0",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz",
+      "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==",
       "dev": true,
       "dependencies": {
         "@types/eslint-scope": "^3.7.3",
-        "@types/estree": "^0.0.51",
-        "@webassemblyjs/ast": "1.11.1",
-        "@webassemblyjs/wasm-edit": "1.11.1",
-        "@webassemblyjs/wasm-parser": "1.11.1",
+        "@types/estree": "^1.0.5",
+        "@webassemblyjs/ast": "^1.12.1",
+        "@webassemblyjs/wasm-edit": "^1.12.1",
+        "@webassemblyjs/wasm-parser": "^1.12.1",
         "acorn": "^8.7.1",
-        "acorn-import-assertions": "^1.7.6",
-        "browserslist": "^4.14.5",
+        "acorn-import-assertions": "^1.9.0",
+        "browserslist": "^4.21.10",
         "chrome-trace-event": "^1.0.2",
-        "enhanced-resolve": "^5.10.0",
-        "es-module-lexer": "^0.9.0",
+        "enhanced-resolve": "^5.16.0",
+        "es-module-lexer": "^1.2.1",
         "eslint-scope": "5.1.1",
         "events": "^3.2.0",
         "glob-to-regexp": "^0.4.1",
-        "graceful-fs": "^4.2.9",
+        "graceful-fs": "^4.2.11",
         "json-parse-even-better-errors": "^2.3.1",
         "loader-runner": "^4.2.0",
         "mime-types": "^2.1.27",
         "neo-async": "^2.6.2",
-        "schema-utils": "^3.1.0",
+        "schema-utils": "^3.2.0",
         "tapable": "^2.1.1",
-        "terser-webpack-plugin": "^5.1.3",
-        "watchpack": "^2.4.0",
+        "terser-webpack-plugin": "^5.3.10",
+        "watchpack": "^2.4.1",
         "webpack-sources": "^3.2.3"
       },
       "bin": {
@@ -5050,40 +5789,42 @@
       }
     },
     "node_modules/webpack-cli": {
-      "version": "4.9.2",
-      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz",
-      "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz",
+      "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
       "dev": true,
       "dependencies": {
         "@discoveryjs/json-ext": "^0.5.0",
-        "@webpack-cli/configtest": "^1.1.1",
-        "@webpack-cli/info": "^1.4.1",
-        "@webpack-cli/serve": "^1.6.1",
+        "@webpack-cli/configtest": "^2.1.1",
+        "@webpack-cli/info": "^2.0.2",
+        "@webpack-cli/serve": "^2.0.5",
         "colorette": "^2.0.14",
-        "commander": "^7.0.0",
-        "execa": "^5.0.0",
+        "commander": "^10.0.1",
+        "cross-spawn": "^7.0.3",
+        "envinfo": "^7.7.3",
         "fastest-levenshtein": "^1.0.12",
         "import-local": "^3.0.2",
-        "interpret": "^2.2.0",
-        "rechoir": "^0.7.0",
+        "interpret": "^3.1.1",
+        "rechoir": "^0.8.0",
         "webpack-merge": "^5.7.3"
       },
       "bin": {
         "webpack-cli": "bin/cli.js"
       },
       "engines": {
-        "node": ">=10.13.0"
+        "node": ">=14.15.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
       },
       "peerDependencies": {
-        "webpack": "4.x.x || 5.x.x"
+        "webpack": "5.x.x"
       },
       "peerDependenciesMeta": {
         "@webpack-cli/generators": {
           "optional": true
         },
-        "@webpack-cli/migrate": {
-          "optional": true
-        },
         "webpack-bundle-analyzer": {
           "optional": true
         },
@@ -5093,12 +5834,12 @@
       }
     },
     "node_modules/webpack-cli/node_modules/commander": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
-      "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+      "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
       "dev": true,
       "engines": {
-        "node": ">= 10"
+        "node": ">=14"
       }
     },
     "node_modules/webpack-merge": {
@@ -5123,49 +5864,6 @@
         "node": ">=10.13.0"
       }
     },
-    "node_modules/webpack/node_modules/acorn": {
-      "version": "8.8.2",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
-      "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
-      "dev": true,
-      "bin": {
-        "acorn": "bin/acorn"
-      },
-      "engines": {
-        "node": ">=0.4.0"
-      }
-    },
-    "node_modules/webpack/node_modules/acorn-import-assertions": {
-      "version": "1.8.0",
-      "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
-      "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
-      "dev": true,
-      "peerDependencies": {
-        "acorn": "^8"
-      }
-    },
-    "node_modules/webpack/node_modules/enhanced-resolve": {
-      "version": "5.12.0",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
-      "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==",
-      "dev": true,
-      "dependencies": {
-        "graceful-fs": "^4.2.4",
-        "tapable": "^2.2.0"
-      },
-      "engines": {
-        "node": ">=10.13.0"
-      }
-    },
-    "node_modules/webpack/node_modules/tapable": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
-      "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -5197,6 +5895,69 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/which-builtin-type": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz",
+      "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==",
+      "dev": true,
+      "dependencies": {
+        "function.prototype.name": "^1.1.5",
+        "has-tostringtag": "^1.0.0",
+        "is-async-function": "^2.0.0",
+        "is-date-object": "^1.0.5",
+        "is-finalizationregistry": "^1.0.2",
+        "is-generator-function": "^1.0.10",
+        "is-regex": "^1.1.4",
+        "is-weakref": "^1.0.2",
+        "isarray": "^2.0.5",
+        "which-boxed-primitive": "^1.0.2",
+        "which-collection": "^1.0.1",
+        "which-typed-array": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-collection": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
+      "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+      "dev": true,
+      "dependencies": {
+        "is-map": "^2.0.3",
+        "is-set": "^2.0.3",
+        "is-weakmap": "^2.0.2",
+        "is-weakset": "^2.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-typed-array": {
+      "version": "1.1.15",
+      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
+      "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==",
+      "dev": true,
+      "dependencies": {
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.7",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/wildcard": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
@@ -5204,9 +5965,9 @@
       "dev": true
     },
     "node_modules/word-wrap": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
-      "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+      "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
       "dev": true,
       "engines": {
         "node": ">=0.10.0"
@@ -5242,9 +6003,9 @@
       "dev": true
     },
     "node_modules/ws": {
-      "version": "8.14.2",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz",
-      "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==",
+      "version": "8.17.1",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+      "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
       "engines": {
         "node": ">=10.0.0"
       },
@@ -5270,12 +6031,6 @@
         "node": ">=10"
       }
     },
-    "node_modules/yallist": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-      "dev": true
-    },
     "node_modules/yargs": {
       "version": "16.2.0",
       "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
@@ -5332,138 +6087,53 @@
     }
   },
   "dependencies": {
-    "@babel/code-frame": {
-      "version": "7.12.11",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
-      "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
+    "@babel/runtime": {
+      "version": "7.24.7",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz",
+      "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==",
       "dev": true,
       "requires": {
-        "@babel/highlight": "^7.10.4"
+        "regenerator-runtime": "^0.14.0"
       }
     },
-    "@babel/helper-validator-identifier": {
-      "version": "7.15.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
-      "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
+    "@discoveryjs/json-ext": {
+      "version": "0.5.5",
+      "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz",
+      "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==",
       "dev": true
     },
-    "@babel/highlight": {
-      "version": "7.16.0",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz",
-      "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-validator-identifier": "^7.15.7",
-        "chalk": "^2.0.0",
-        "js-tokens": "^4.0.0"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^1.9.0"
-          }
-        },
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
-        "color-convert": {
-          "version": "1.9.3",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-          "dev": true,
-          "requires": {
-            "color-name": "1.1.3"
-          }
-        },
-        "color-name": {
-          "version": "1.1.3",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-          "dev": true
-        },
-        "escape-string-regexp": {
-          "version": "1.0.5",
-          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-          "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
-      }
-    },
-    "@babel/runtime": {
-      "version": "7.16.3",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz",
-      "integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==",
-      "dev": true,
-      "requires": {
-        "regenerator-runtime": "^0.13.4"
-      }
-    },
-    "@babel/runtime-corejs3": {
-      "version": "7.16.3",
-      "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.3.tgz",
-      "integrity": "sha512-IAdDC7T0+wEB4y2gbIL0uOXEYpiZEeuFUTVbdGq+UwCcF35T/tS8KrmMomEwEc5wBbyfH3PJVpTSUqrhPDXFcQ==",
+    "@eslint-community/eslint-utils": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+      "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
       "dev": true,
       "requires": {
-        "core-js-pure": "^3.19.0",
-        "regenerator-runtime": "^0.13.4"
+        "eslint-visitor-keys": "^3.3.0"
       }
     },
-    "@discoveryjs/json-ext": {
-      "version": "0.5.5",
-      "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz",
-      "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==",
+    "@eslint-community/regexpp": {
+      "version": "4.10.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz",
+      "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==",
       "dev": true
     },
     "@eslint/eslintrc": {
-      "version": "0.4.3",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
-      "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+      "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
       "dev": true,
       "requires": {
         "ajv": "^6.12.4",
-        "debug": "^4.1.1",
-        "espree": "^7.3.0",
-        "globals": "^13.9.0",
-        "ignore": "^4.0.6",
+        "debug": "^4.3.2",
+        "espree": "^9.6.0",
+        "globals": "^13.19.0",
+        "ignore": "^5.2.0",
         "import-fresh": "^3.2.1",
-        "js-yaml": "^3.13.1",
-        "minimatch": "^3.0.4",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
         "strip-json-comments": "^3.1.1"
       },
       "dependencies": {
-        "ignore": {
-          "version": "4.0.6",
-          "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
-          "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
-          "dev": true
-        },
         "minimatch": {
           "version": "3.1.2",
           "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -5475,15 +6145,21 @@
         }
       }
     },
+    "@eslint/js": {
+      "version": "8.57.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
+      "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
+      "dev": true
+    },
     "@humanwhocodes/config-array": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
-      "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
+      "version": "0.11.14",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
+      "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
       "dev": true,
       "requires": {
-        "@humanwhocodes/object-schema": "^1.2.0",
-        "debug": "^4.1.1",
-        "minimatch": "^3.0.4"
+        "@humanwhocodes/object-schema": "^2.0.2",
+        "debug": "^4.3.1",
+        "minimatch": "^3.0.5"
       },
       "dependencies": {
         "minimatch": {
@@ -5497,59 +6173,65 @@
         }
       }
     },
+    "@humanwhocodes/module-importer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+      "dev": true
+    },
     "@humanwhocodes/object-schema": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
-      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+      "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
       "dev": true
     },
     "@jridgewell/gen-mapping": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
-      "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
+      "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
       "dev": true,
       "requires": {
-        "@jridgewell/set-array": "^1.0.1",
+        "@jridgewell/set-array": "^1.2.1",
         "@jridgewell/sourcemap-codec": "^1.4.10",
-        "@jridgewell/trace-mapping": "^0.3.9"
+        "@jridgewell/trace-mapping": "^0.3.24"
       }
     },
     "@jridgewell/resolve-uri": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
-      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
       "dev": true
     },
     "@jridgewell/set-array": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
-      "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+      "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
       "dev": true
     },
     "@jridgewell/source-map": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
-      "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
+      "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
       "dev": true,
       "requires": {
-        "@jridgewell/gen-mapping": "^0.3.0",
-        "@jridgewell/trace-mapping": "^0.3.9"
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.25"
       }
     },
     "@jridgewell/sourcemap-codec": {
-      "version": "1.4.14",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
-      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+      "version": "1.4.15",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+      "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
       "dev": true
     },
     "@jridgewell/trace-mapping": {
-      "version": "0.3.14",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz",
-      "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==",
+      "version": "0.3.25",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+      "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
       "dev": true,
       "requires": {
-        "@jridgewell/resolve-uri": "^3.0.3",
-        "@jridgewell/sourcemap-codec": "^1.4.10"
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
       }
     },
     "@nodelib/fs.scandir": {
@@ -5578,10 +6260,10 @@
         "fastq": "^1.6.0"
       }
     },
-    "@tootallnate/once": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
-      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+    "@pkgr/core": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz",
+      "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==",
       "dev": true
     },
     "@types/eslint": {
@@ -5605,9 +6287,9 @@
       }
     },
     "@types/estree": {
-      "version": "0.0.51",
-      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz",
-      "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
+      "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
       "dev": true
     },
     "@types/istextorbinary": {
@@ -5628,7 +6310,7 @@
     "@types/json5": {
       "version": "0.0.29",
       "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
-      "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
+      "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
       "dev": true
     },
     "@types/minimatch": {
@@ -5656,9 +6338,9 @@
       "dev": true
     },
     "@types/vscode": {
-      "version": "1.83.0",
-      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.83.0.tgz",
-      "integrity": "sha512-3mUtHqLAVz9hegut9au4xehuBrzRE3UJiQMpoEHkNl6XHliihO7eATx2BMHs0odsmmrwjJrlixx/Pte6M3ygDQ==",
+      "version": "1.91.0",
+      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.91.0.tgz",
+      "integrity": "sha512-PgPr+bUODjG3y+ozWUCyzttqR9EHny9sPAfJagddQjDwdtf66y2sDKJMnFZRuzBA2YtBGASqJGPil8VDUPvO6A==",
       "dev": true
     },
     "@types/ws": {
@@ -5677,97 +6359,132 @@
       "dev": true
     },
     "@typescript-eslint/eslint-plugin": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz",
-      "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==",
-      "dev": true,
-      "requires": {
-        "@typescript-eslint/experimental-utils": "4.33.0",
-        "@typescript-eslint/scope-manager": "4.33.0",
-        "debug": "^4.3.1",
-        "functional-red-black-tree": "^1.0.1",
-        "ignore": "^5.1.8",
-        "regexpp": "^3.1.0",
-        "semver": "^7.3.5",
-        "tsutils": "^3.21.0"
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz",
+      "integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==",
+      "dev": true,
+      "requires": {
+        "@eslint-community/regexpp": "^4.10.0",
+        "@typescript-eslint/scope-manager": "7.12.0",
+        "@typescript-eslint/type-utils": "7.12.0",
+        "@typescript-eslint/utils": "7.12.0",
+        "@typescript-eslint/visitor-keys": "7.12.0",
+        "graphemer": "^1.4.0",
+        "ignore": "^5.3.1",
+        "natural-compare": "^1.4.0",
+        "ts-api-utils": "^1.3.0"
       }
     },
-    "@typescript-eslint/experimental-utils": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz",
-      "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==",
+    "@typescript-eslint/parser": {
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz",
+      "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==",
       "dev": true,
       "requires": {
-        "@types/json-schema": "^7.0.7",
-        "@typescript-eslint/scope-manager": "4.33.0",
-        "@typescript-eslint/types": "4.33.0",
-        "@typescript-eslint/typescript-estree": "4.33.0",
-        "eslint-scope": "^5.1.1",
-        "eslint-utils": "^3.0.0"
+        "@typescript-eslint/scope-manager": "7.12.0",
+        "@typescript-eslint/types": "7.12.0",
+        "@typescript-eslint/typescript-estree": "7.12.0",
+        "@typescript-eslint/visitor-keys": "7.12.0",
+        "debug": "^4.3.4"
       },
       "dependencies": {
-        "eslint-utils": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
-          "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+        "debug": {
+          "version": "4.3.5",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+          "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
           "dev": true,
           "requires": {
-            "eslint-visitor-keys": "^2.0.0"
+            "ms": "2.1.2"
           }
         }
       }
     },
-    "@typescript-eslint/parser": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz",
-      "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==",
+    "@typescript-eslint/scope-manager": {
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz",
+      "integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/scope-manager": "4.33.0",
-        "@typescript-eslint/types": "4.33.0",
-        "@typescript-eslint/typescript-estree": "4.33.0",
-        "debug": "^4.3.1"
+        "@typescript-eslint/types": "7.12.0",
+        "@typescript-eslint/visitor-keys": "7.12.0"
       }
     },
-    "@typescript-eslint/scope-manager": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz",
-      "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==",
+    "@typescript-eslint/type-utils": {
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz",
+      "integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "4.33.0",
-        "@typescript-eslint/visitor-keys": "4.33.0"
+        "@typescript-eslint/typescript-estree": "7.12.0",
+        "@typescript-eslint/utils": "7.12.0",
+        "debug": "^4.3.4",
+        "ts-api-utils": "^1.3.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.5",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+          "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+          "dev": true,
+          "requires": {
+            "ms": "2.1.2"
+          }
+        }
       }
     },
     "@typescript-eslint/types": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz",
-      "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==",
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz",
+      "integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==",
       "dev": true
     },
     "@typescript-eslint/typescript-estree": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz",
-      "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==",
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz",
+      "integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "4.33.0",
-        "@typescript-eslint/visitor-keys": "4.33.0",
-        "debug": "^4.3.1",
-        "globby": "^11.0.3",
-        "is-glob": "^4.0.1",
-        "semver": "^7.3.5",
-        "tsutils": "^3.21.0"
+        "@typescript-eslint/types": "7.12.0",
+        "@typescript-eslint/visitor-keys": "7.12.0",
+        "debug": "^4.3.4",
+        "globby": "^11.1.0",
+        "is-glob": "^4.0.3",
+        "minimatch": "^9.0.4",
+        "semver": "^7.6.0",
+        "ts-api-utils": "^1.3.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.5",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+          "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+          "dev": true,
+          "requires": {
+            "ms": "2.1.2"
+          }
+        }
+      }
+    },
+    "@typescript-eslint/utils": {
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz",
+      "integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==",
+      "dev": true,
+      "requires": {
+        "@eslint-community/eslint-utils": "^4.4.0",
+        "@typescript-eslint/scope-manager": "7.12.0",
+        "@typescript-eslint/types": "7.12.0",
+        "@typescript-eslint/typescript-estree": "7.12.0"
       }
     },
     "@typescript-eslint/visitor-keys": {
-      "version": "4.33.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz",
-      "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==",
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz",
+      "integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "4.33.0",
-        "eslint-visitor-keys": "^2.0.0"
+        "@typescript-eslint/types": "7.12.0",
+        "eslint-visitor-keys": "^3.4.3"
       }
     },
     "@ungap/promise-all-settled": {
@@ -5776,18 +6493,33 @@
       "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
       "dev": true
     },
+    "@ungap/structured-clone": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
+      "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
+      "dev": true
+    },
     "@vscode/debugadapter": {
-      "version": "1.61.0",
-      "resolved": "https://registry.npmjs.org/@vscode/debugadapter/-/debugadapter-1.61.0.tgz",
-      "integrity": "sha512-VDGLUFDVAdnftUebZe4uQCIFUbJ7rTc2Grps4D/CXl+qyzTZSQLv5VADEOZ6kBYG4SvlnMLql5vPQ0G6XvUCvQ==",
+      "version": "1.65.0",
+      "resolved": "https://registry.npmjs.org/@vscode/debugadapter/-/debugadapter-1.65.0.tgz",
+      "integrity": "sha512-l9jdX0GFoFVAc7O4O8iVnCjO0pgxbx+wJJXCaYSuglGtYwMNcJdc7xm96cuVx4LWzSqneIjvjzbuzZtoVZhZzQ==",
+      "requires": {
+        "@vscode/debugprotocol": "1.65.0"
+      }
+    },
+    "@vscode/debugadapter-testsupport": {
+      "version": "1.65.0",
+      "resolved": "https://registry.npmjs.org/@vscode/debugadapter-testsupport/-/debugadapter-testsupport-1.65.0.tgz",
+      "integrity": "sha512-VwXzZKhBBK2rBemzQbw7rKsaNl0rZbcWm6oMxipz152Ki9LhrTy9QDl6zZlcdvJx23r9WtNxt7qHNt02PPMisg==",
+      "dev": true,
       "requires": {
-        "@vscode/debugprotocol": "1.61.0"
+        "@vscode/debugprotocol": "1.65.0"
       }
     },
     "@vscode/debugprotocol": {
-      "version": "1.61.0",
-      "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.61.0.tgz",
-      "integrity": "sha512-K/kF27jIStVFqlmUaGc2u+Dj8IR7YdEiSqShWr7MWhDudqpAW7uu7XMwoFwjpuC9LSaVwJMIX7EFC5OJ/RmnDQ=="
+      "version": "1.65.0",
+      "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.65.0.tgz",
+      "integrity": "sha512-ejerrPMBXzYms6Ks+Gb7cdXtdncmT0xwIKNsc0c/SxhEa0HVY5jdvLUegYE91p7CQJpCnXOD/r2CvViN8txLLA=="
     },
     "@vscode/dts": {
       "version": "0.4.0",
@@ -5798,216 +6530,185 @@
         "https-proxy-agent": "^7.0.0",
         "minimist": "^1.2.8",
         "prompts": "^2.4.2"
-      },
-      "dependencies": {
-        "agent-base": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
-          "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==",
-          "dev": true,
-          "requires": {
-            "debug": "^4.3.4"
-          }
-        },
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "https-proxy-agent": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz",
-          "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==",
-          "dev": true,
-          "requires": {
-            "agent-base": "^7.0.2",
-            "debug": "4"
-          }
-        }
       }
     },
     "@vscode/test-electron": {
-      "version": "2.3.8",
-      "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.8.tgz",
-      "integrity": "sha512-b4aZZsBKtMGdDljAsOPObnAi7+VWIaYl3ylCz1jTs+oV6BZ4TNHcVNC3xUn0azPeszBmwSBDQYfFESIaUQnrOg==",
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.0.tgz",
+      "integrity": "sha512-yojuDFEjohx6Jb+x949JRNtSn6Wk2FAh4MldLE3ck9cfvCqzwxF32QsNy1T9Oe4oT+ZfFcg0uPUCajJzOmPlTA==",
       "dev": true,
       "requires": {
-        "http-proxy-agent": "^4.0.1",
-        "https-proxy-agent": "^5.0.0",
+        "http-proxy-agent": "^7.0.2",
+        "https-proxy-agent": "^7.0.4",
         "jszip": "^3.10.1",
-        "semver": "^7.5.2"
+        "ora": "^7.0.1",
+        "semver": "^7.6.2"
       }
     },
     "@webassemblyjs/ast": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
-      "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",
+      "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/helper-numbers": "1.11.1",
-        "@webassemblyjs/helper-wasm-bytecode": "1.11.1"
+        "@webassemblyjs/helper-numbers": "1.11.6",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6"
       }
     },
     "@webassemblyjs/floating-point-hex-parser": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz",
-      "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
+      "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",
       "dev": true
     },
     "@webassemblyjs/helper-api-error": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz",
-      "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
+      "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",
       "dev": true
     },
     "@webassemblyjs/helper-buffer": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz",
-      "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",
+      "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==",
       "dev": true
     },
     "@webassemblyjs/helper-numbers": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz",
-      "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
+      "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/floating-point-hex-parser": "1.11.1",
-        "@webassemblyjs/helper-api-error": "1.11.1",
+        "@webassemblyjs/floating-point-hex-parser": "1.11.6",
+        "@webassemblyjs/helper-api-error": "1.11.6",
         "@xtuc/long": "4.2.2"
       }
     },
     "@webassemblyjs/helper-wasm-bytecode": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz",
-      "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
+      "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",
       "dev": true
     },
     "@webassemblyjs/helper-wasm-section": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz",
-      "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",
+      "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/ast": "1.11.1",
-        "@webassemblyjs/helper-buffer": "1.11.1",
-        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
-        "@webassemblyjs/wasm-gen": "1.11.1"
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-buffer": "1.12.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/wasm-gen": "1.12.1"
       }
     },
     "@webassemblyjs/ieee754": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz",
-      "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
+      "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
       "dev": true,
       "requires": {
         "@xtuc/ieee754": "^1.2.0"
       }
     },
     "@webassemblyjs/leb128": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz",
-      "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
+      "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
       "dev": true,
       "requires": {
         "@xtuc/long": "4.2.2"
       }
     },
     "@webassemblyjs/utf8": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz",
-      "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==",
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
+      "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",
       "dev": true
     },
     "@webassemblyjs/wasm-edit": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz",
-      "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz",
+      "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/ast": "1.11.1",
-        "@webassemblyjs/helper-buffer": "1.11.1",
-        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
-        "@webassemblyjs/helper-wasm-section": "1.11.1",
-        "@webassemblyjs/wasm-gen": "1.11.1",
-        "@webassemblyjs/wasm-opt": "1.11.1",
-        "@webassemblyjs/wasm-parser": "1.11.1",
-        "@webassemblyjs/wast-printer": "1.11.1"
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-buffer": "1.12.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/helper-wasm-section": "1.12.1",
+        "@webassemblyjs/wasm-gen": "1.12.1",
+        "@webassemblyjs/wasm-opt": "1.12.1",
+        "@webassemblyjs/wasm-parser": "1.12.1",
+        "@webassemblyjs/wast-printer": "1.12.1"
       }
     },
     "@webassemblyjs/wasm-gen": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz",
-      "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",
+      "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/ast": "1.11.1",
-        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
-        "@webassemblyjs/ieee754": "1.11.1",
-        "@webassemblyjs/leb128": "1.11.1",
-        "@webassemblyjs/utf8": "1.11.1"
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/ieee754": "1.11.6",
+        "@webassemblyjs/leb128": "1.11.6",
+        "@webassemblyjs/utf8": "1.11.6"
       }
     },
     "@webassemblyjs/wasm-opt": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz",
-      "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",
+      "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/ast": "1.11.1",
-        "@webassemblyjs/helper-buffer": "1.11.1",
-        "@webassemblyjs/wasm-gen": "1.11.1",
-        "@webassemblyjs/wasm-parser": "1.11.1"
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-buffer": "1.12.1",
+        "@webassemblyjs/wasm-gen": "1.12.1",
+        "@webassemblyjs/wasm-parser": "1.12.1"
       }
     },
     "@webassemblyjs/wasm-parser": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz",
-      "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",
+      "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/ast": "1.11.1",
-        "@webassemblyjs/helper-api-error": "1.11.1",
-        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
-        "@webassemblyjs/ieee754": "1.11.1",
-        "@webassemblyjs/leb128": "1.11.1",
-        "@webassemblyjs/utf8": "1.11.1"
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-api-error": "1.11.6",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/ieee754": "1.11.6",
+        "@webassemblyjs/leb128": "1.11.6",
+        "@webassemblyjs/utf8": "1.11.6"
       }
     },
     "@webassemblyjs/wast-printer": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz",
-      "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",
+      "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/ast": "1.12.1",
         "@xtuc/long": "4.2.2"
       }
     },
     "@webpack-cli/configtest": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz",
-      "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==",
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz",
+      "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==",
       "dev": true,
       "requires": {}
     },
     "@webpack-cli/info": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz",
-      "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==",
-      "dev": true,
-      "requires": {
-        "envinfo": "^7.7.3"
-      }
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz",
+      "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==",
+      "dev": true,
+      "requires": {}
     },
     "@webpack-cli/serve": {
-      "version": "1.6.1",
-      "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz",
-      "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==",
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz",
+      "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==",
       "dev": true,
       "requires": {}
     },
@@ -6029,11 +6730,18 @@
       "dev": true
     },
     "acorn": {
-      "version": "7.4.1",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
-      "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+      "version": "8.11.3",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
+      "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
       "dev": true
     },
+    "acorn-import-assertions": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
+      "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
+      "dev": true,
+      "requires": {}
+    },
     "acorn-jsx": {
       "version": "5.3.2",
       "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
@@ -6042,12 +6750,23 @@
       "requires": {}
     },
     "agent-base": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
-      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+      "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
       "dev": true,
       "requires": {
-        "debug": "4"
+        "debug": "^4.3.4"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.5",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+          "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+          "dev": true,
+          "requires": {
+            "ms": "2.1.2"
+          }
+        }
       }
     },
     "ajv": {
@@ -6112,34 +6831,41 @@
       }
     },
     "argparse": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
+    "aria-query": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
+      "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
       "dev": true,
       "requires": {
-        "sprintf-js": "~1.0.2"
+        "dequal": "^2.0.3"
       }
     },
-    "aria-query": {
-      "version": "4.2.2",
-      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz",
-      "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==",
+    "array-buffer-byte-length": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
+      "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==",
       "dev": true,
       "requires": {
-        "@babel/runtime": "^7.10.2",
-        "@babel/runtime-corejs3": "^7.10.2"
+        "call-bind": "^1.0.5",
+        "is-array-buffer": "^3.0.4"
       }
     },
     "array-includes": {
-      "version": "3.1.4",
-      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz",
-      "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==",
+      "version": "3.1.8",
+      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
+      "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
       "dev": true,
       "requires": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.1",
-        "get-intrinsic": "^1.1.1",
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-object-atoms": "^1.0.0",
+        "get-intrinsic": "^1.2.4",
         "is-string": "^1.0.7"
       }
     },
@@ -6149,27 +6875,64 @@
       "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
       "dev": true
     },
-    "array.prototype.flat": {
+    "array.prototype.findlastindex": {
       "version": "1.2.5",
-      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz",
-      "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==",
+      "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
+      "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
+        "es-shim-unscopables": "^1.0.2"
+      }
+    },
+    "array.prototype.flat": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
+      "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==",
       "dev": true,
       "requires": {
         "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.0"
+        "define-properties": "^1.2.0",
+        "es-abstract": "^1.22.1",
+        "es-shim-unscopables": "^1.0.0"
       }
     },
-    "ast-types-flow": {
-      "version": "0.0.7",
-      "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
-      "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
-      "dev": true
+    "array.prototype.flatmap": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz",
+      "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.2.0",
+        "es-abstract": "^1.22.1",
+        "es-shim-unscopables": "^1.0.0"
+      }
     },
-    "astral-regex": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
-      "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+    "arraybuffer.prototype.slice": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz",
+      "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==",
+      "dev": true,
+      "requires": {
+        "array-buffer-byte-length": "^1.0.1",
+        "call-bind": "^1.0.5",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.22.3",
+        "es-errors": "^1.2.1",
+        "get-intrinsic": "^1.2.3",
+        "is-array-buffer": "^3.0.4",
+        "is-shared-array-buffer": "^1.0.2"
+      }
+    },
+    "ast-types-flow": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
+      "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
       "dev": true
     },
     "async-hook-jl": {
@@ -6196,27 +6959,39 @@
         }
       }
     },
+    "available-typed-arrays": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+      "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+      "dev": true,
+      "requires": {
+        "possible-typed-array-names": "^1.0.0"
+      }
+    },
     "axe-core": {
-      "version": "4.3.5",
-      "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz",
-      "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==",
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz",
+      "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==",
       "dev": true
     },
     "axobject-query": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
-      "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==",
-      "dev": true
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
+      "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==",
+      "dev": true,
+      "requires": {
+        "dequal": "^2.0.3"
+      }
     },
     "balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
       "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
     },
-    "big.js": {
-      "version": "5.2.2",
-      "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
-      "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
+    "base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
       "dev": true
     },
     "binary-extensions": {
@@ -6230,6 +7005,30 @@
       "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-4.19.0.tgz",
       "integrity": "sha512-DRxnVbOi/1OgA5pA9EDiRT8gvVYeqfuN7TmPfLyt6cyho3KbHCi3EtDQf39TTmGDrR5dZ9CspdXhPkL/j/WGbg=="
     },
+    "bl": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz",
+      "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==",
+      "dev": true,
+      "requires": {
+        "buffer": "^6.0.3",
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.4.0"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.2",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+          "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
     "brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -6241,12 +7040,12 @@
       }
     },
     "braces": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
       "dev": true,
       "requires": {
-        "fill-range": "^7.0.1"
+        "fill-range": "^7.1.1"
       }
     },
     "browser-stdout": {
@@ -6256,16 +7055,25 @@
       "dev": true
     },
     "browserslist": {
-      "version": "4.18.1",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.18.1.tgz",
-      "integrity": "sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ==",
+      "version": "4.23.0",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
+      "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
       "dev": true,
       "requires": {
-        "caniuse-lite": "^1.0.30001280",
-        "electron-to-chromium": "^1.3.896",
-        "escalade": "^3.1.1",
-        "node-releases": "^2.0.1",
-        "picocolors": "^1.0.0"
+        "caniuse-lite": "^1.0.30001587",
+        "electron-to-chromium": "^1.4.668",
+        "node-releases": "^2.0.14",
+        "update-browserslist-db": "^1.0.13"
+      }
+    },
+    "buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "dev": true,
+      "requires": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
       }
     },
     "buffer-from": {
@@ -6275,13 +7083,16 @@
       "dev": true
     },
     "call-bind": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
-      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+      "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
       "dev": true,
       "requires": {
-        "function-bind": "^1.1.1",
-        "get-intrinsic": "^1.0.2"
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "set-function-length": "^1.2.1"
       }
     },
     "callsites": {
@@ -6297,9 +7108,9 @@
       "dev": true
     },
     "caniuse-lite": {
-      "version": "1.0.30001283",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001283.tgz",
-      "integrity": "sha512-9RoKo841j1GQFSJz/nCXOj0sD7tHBtlowjYlrqIUS812x9/emfBLBt6IyMz1zIaYc/eRL8Cs6HPUVi2Hzq4sIg==",
+      "version": "1.0.30001629",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001629.tgz",
+      "integrity": "sha512-c3dl911slnQhmxUIT4HhYzT7wnBK/XYpGnYLOj4nJBaRiw52Ibe7YxlDaAeRECvA786zCuExhxIUJ2K7nHMrBw==",
       "dev": true
     },
     "chalk": {
@@ -6334,6 +7145,21 @@
       "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
       "dev": true
     },
+    "cli-cursor": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz",
+      "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==",
+      "dev": true,
+      "requires": {
+        "restore-cursor": "^4.0.0"
+      }
+    },
+    "cli-spinners": {
+      "version": "2.9.2",
+      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
+      "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
+      "dev": true
+    },
     "cliui": {
       "version": "7.0.4",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -6426,12 +7252,6 @@
       "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.1.tgz",
       "integrity": "sha512-Tnc7E9iKd/b/ff7GFbhwPVzJzPztGrChB8X8GLqoYGdEOG8IpLnK1xPyo3ZoO3HsK6TodJS58VGPOxA+hLHQMg=="
     },
-    "core-js-pure": {
-      "version": "3.19.1",
-      "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.1.tgz",
-      "integrity": "sha512-Q0Knr8Es84vtv62ei6/6jXH/7izKmOrtrxH9WJTHLCMAVeU+8TF8z8Nr08CsH4Ot0oJKzBzJJL9SJBYIv7WlfQ==",
-      "dev": true
-    },
     "core-util-is": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
@@ -6450,11 +7270,44 @@
       }
     },
     "damerau-levenshtein": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz",
-      "integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw==",
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
+      "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
       "dev": true
     },
+    "data-view-buffer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
+      "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.6",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.1"
+      }
+    },
+    "data-view-byte-length": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
+      "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.7",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.1"
+      }
+    },
+    "data-view-byte-offset": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
+      "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.6",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.1"
+      }
+    },
     "debug": {
       "version": "4.3.3",
       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
@@ -6476,15 +7329,34 @@
       "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
       "dev": true
     },
+    "define-data-property": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+      "dev": true,
+      "requires": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.0.1"
+      }
+    },
     "define-properties": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
-      "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+      "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
       "dev": true,
       "requires": {
-        "object-keys": "^1.0.12"
+        "define-data-property": "^1.0.1",
+        "has-property-descriptors": "^1.0.0",
+        "object-keys": "^1.1.1"
       }
     },
+    "dequal": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+      "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+      "dev": true
+    },
     "diagnostic-channel": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz",
@@ -6530,10 +7402,16 @@
         "esutils": "^2.0.2"
       }
     },
+    "eastasianwidth": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+      "dev": true
+    },
     "electron-to-chromium": {
-      "version": "1.4.4",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.4.tgz",
-      "integrity": "sha512-teHtgwcmVcL46jlFvAaqjyiTLWuMrUQO1JqV303JKB4ysXG6m8fXSFhbjal9st0r9mNskI22AraJZorb1VcLVg==",
+      "version": "1.4.794",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.794.tgz",
+      "integrity": "sha512-6FApLtsYhDCY0Vglq3AptsdxQ+PJLc6AxlAM0HjEihUAiOPPbkASEsq9gtxUeZY9o0sJIEa3WnF0vVH4VT4iug==",
       "dev": true
     },
     "emitter-listener": {
@@ -6550,80 +7428,147 @@
       "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
       "dev": true
     },
-    "emojis-list": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
-      "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+    "enhanced-resolve": {
+      "version": "5.17.0",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz",
+      "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.2.4",
+        "tapable": "^2.2.0"
+      }
+    },
+    "envinfo": {
+      "version": "7.13.0",
+      "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz",
+      "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==",
       "dev": true
     },
-    "enhanced-resolve": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
-      "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
+    "es-abstract": {
+      "version": "1.23.3",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
+      "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==",
+      "dev": true,
+      "requires": {
+        "array-buffer-byte-length": "^1.0.1",
+        "arraybuffer.prototype.slice": "^1.0.3",
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.7",
+        "data-view-buffer": "^1.0.1",
+        "data-view-byte-length": "^1.0.1",
+        "data-view-byte-offset": "^1.0.0",
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
+        "es-set-tostringtag": "^2.0.3",
+        "es-to-primitive": "^1.2.1",
+        "function.prototype.name": "^1.1.6",
+        "get-intrinsic": "^1.2.4",
+        "get-symbol-description": "^1.0.2",
+        "globalthis": "^1.0.3",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.2",
+        "has-proto": "^1.0.3",
+        "has-symbols": "^1.0.3",
+        "hasown": "^2.0.2",
+        "internal-slot": "^1.0.7",
+        "is-array-buffer": "^3.0.4",
+        "is-callable": "^1.2.7",
+        "is-data-view": "^1.0.1",
+        "is-negative-zero": "^2.0.3",
+        "is-regex": "^1.1.4",
+        "is-shared-array-buffer": "^1.0.3",
+        "is-string": "^1.0.7",
+        "is-typed-array": "^1.1.13",
+        "is-weakref": "^1.0.2",
+        "object-inspect": "^1.13.1",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.5",
+        "regexp.prototype.flags": "^1.5.2",
+        "safe-array-concat": "^1.1.2",
+        "safe-regex-test": "^1.0.3",
+        "string.prototype.trim": "^1.2.9",
+        "string.prototype.trimend": "^1.0.8",
+        "string.prototype.trimstart": "^1.0.8",
+        "typed-array-buffer": "^1.0.2",
+        "typed-array-byte-length": "^1.0.1",
+        "typed-array-byte-offset": "^1.0.2",
+        "typed-array-length": "^1.0.6",
+        "unbox-primitive": "^1.0.2",
+        "which-typed-array": "^1.1.15"
+      }
+    },
+    "es-define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+      "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
       "dev": true,
       "requires": {
-        "graceful-fs": "^4.1.2",
-        "memory-fs": "^0.5.0",
-        "tapable": "^1.0.0"
+        "get-intrinsic": "^1.2.4"
       }
     },
-    "enquirer": {
-      "version": "2.3.6",
-      "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
-      "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
+    "es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "dev": true
+    },
+    "es-iterator-helpers": {
+      "version": "1.0.19",
+      "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz",
+      "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==",
       "dev": true,
       "requires": {
-        "ansi-colors": "^4.1.1"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.3",
+        "es-errors": "^1.3.0",
+        "es-set-tostringtag": "^2.0.3",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "globalthis": "^1.0.3",
+        "has-property-descriptors": "^1.0.2",
+        "has-proto": "^1.0.3",
+        "has-symbols": "^1.0.3",
+        "internal-slot": "^1.0.7",
+        "iterator.prototype": "^1.1.2",
+        "safe-array-concat": "^1.1.2"
       }
     },
-    "envinfo": {
-      "version": "7.8.1",
-      "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
-      "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==",
+    "es-module-lexer": {
+      "version": "1.5.3",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.3.tgz",
+      "integrity": "sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg==",
       "dev": true
     },
-    "errno": {
-      "version": "0.1.8",
-      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
-      "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
+    "es-object-atoms": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
+      "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
       "dev": true,
       "requires": {
-        "prr": "~1.0.1"
+        "es-errors": "^1.3.0"
       }
     },
-    "es-abstract": {
-      "version": "1.19.1",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz",
-      "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==",
+    "es-set-tostringtag": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
+      "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
       "dev": true,
       "requires": {
-        "call-bind": "^1.0.2",
-        "es-to-primitive": "^1.2.1",
-        "function-bind": "^1.1.1",
-        "get-intrinsic": "^1.1.1",
-        "get-symbol-description": "^1.0.0",
-        "has": "^1.0.3",
-        "has-symbols": "^1.0.2",
-        "internal-slot": "^1.0.3",
-        "is-callable": "^1.2.4",
-        "is-negative-zero": "^2.0.1",
-        "is-regex": "^1.1.4",
-        "is-shared-array-buffer": "^1.0.1",
-        "is-string": "^1.0.7",
-        "is-weakref": "^1.0.1",
-        "object-inspect": "^1.11.0",
-        "object-keys": "^1.1.1",
-        "object.assign": "^4.1.2",
-        "string.prototype.trimend": "^1.0.4",
-        "string.prototype.trimstart": "^1.0.4",
-        "unbox-primitive": "^1.0.1"
+        "get-intrinsic": "^1.2.4",
+        "has-tostringtag": "^1.0.2",
+        "hasown": "^2.0.1"
       }
     },
-    "es-module-lexer": {
-      "version": "0.9.3",
-      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
-      "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==",
-      "dev": true
+    "es-shim-unscopables": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz",
+      "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==",
+      "dev": true,
+      "requires": {
+        "hasown": "^2.0.0"
+      }
     },
     "es-to-primitive": {
       "version": "1.2.1",
@@ -6637,9 +7582,9 @@
       }
     },
     "escalade": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
+      "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
       "dev": true
     },
     "escape-string-regexp": {
@@ -6649,59 +7594,76 @@
       "dev": true
     },
     "eslint": {
-      "version": "7.32.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
-      "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "7.12.11",
-        "@eslint/eslintrc": "^0.4.3",
-        "@humanwhocodes/config-array": "^0.5.0",
-        "ajv": "^6.10.0",
+      "version": "8.57.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
+      "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
+      "dev": true,
+      "requires": {
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@eslint-community/regexpp": "^4.6.1",
+        "@eslint/eslintrc": "^2.1.4",
+        "@eslint/js": "8.57.0",
+        "@humanwhocodes/config-array": "^0.11.14",
+        "@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",
-        "debug": "^4.0.1",
+        "debug": "^4.3.2",
         "doctrine": "^3.0.0",
-        "enquirer": "^2.3.5",
         "escape-string-regexp": "^4.0.0",
-        "eslint-scope": "^5.1.1",
-        "eslint-utils": "^2.1.0",
-        "eslint-visitor-keys": "^2.0.0",
-        "espree": "^7.3.1",
-        "esquery": "^1.4.0",
+        "eslint-scope": "^7.2.2",
+        "eslint-visitor-keys": "^3.4.3",
+        "espree": "^9.6.1",
+        "esquery": "^1.4.2",
         "esutils": "^2.0.2",
         "fast-deep-equal": "^3.1.3",
         "file-entry-cache": "^6.0.1",
-        "functional-red-black-tree": "^1.0.1",
-        "glob-parent": "^5.1.2",
-        "globals": "^13.6.0",
-        "ignore": "^4.0.6",
-        "import-fresh": "^3.0.0",
+        "find-up": "^5.0.0",
+        "glob-parent": "^6.0.2",
+        "globals": "^13.19.0",
+        "graphemer": "^1.4.0",
+        "ignore": "^5.2.0",
         "imurmurhash": "^0.1.4",
         "is-glob": "^4.0.0",
-        "js-yaml": "^3.13.1",
+        "is-path-inside": "^3.0.3",
+        "js-yaml": "^4.1.0",
         "json-stable-stringify-without-jsonify": "^1.0.1",
         "levn": "^0.4.1",
         "lodash.merge": "^4.6.2",
-        "minimatch": "^3.0.4",
+        "minimatch": "^3.1.2",
         "natural-compare": "^1.4.0",
-        "optionator": "^0.9.1",
-        "progress": "^2.0.0",
-        "regexpp": "^3.1.0",
-        "semver": "^7.2.1",
-        "strip-ansi": "^6.0.0",
-        "strip-json-comments": "^3.1.0",
-        "table": "^6.0.9",
-        "text-table": "^0.2.0",
-        "v8-compile-cache": "^2.0.3"
+        "optionator": "^0.9.3",
+        "strip-ansi": "^6.0.1",
+        "text-table": "^0.2.0"
       },
       "dependencies": {
-        "ignore": {
-          "version": "4.0.6",
-          "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
-          "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+        "eslint-scope": {
+          "version": "7.2.2",
+          "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+          "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+          "dev": true,
+          "requires": {
+            "esrecurse": "^4.3.0",
+            "estraverse": "^5.2.0"
+          }
+        },
+        "estraverse": {
+          "version": "5.3.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+          "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
           "dev": true
         },
+        "glob-parent": {
+          "version": "6.0.2",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+          "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+          "dev": true,
+          "requires": {
+            "is-glob": "^4.0.3"
+          }
+        },
         "minimatch": {
           "version": "3.1.2",
           "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -6714,33 +7676,41 @@
       }
     },
     "eslint-config-airbnb-base": {
-      "version": "14.2.1",
-      "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz",
-      "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz",
+      "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==",
       "dev": true,
       "requires": {
         "confusing-browser-globals": "^1.0.10",
         "object.assign": "^4.1.2",
-        "object.entries": "^1.1.2"
+        "object.entries": "^1.1.5",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+          "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+          "dev": true
+        }
       }
     },
     "eslint-config-prettier": {
-      "version": "6.15.0",
-      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz",
-      "integrity": "sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==",
+      "version": "9.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz",
+      "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
       "dev": true,
-      "requires": {
-        "get-stdin": "^6.0.0"
-      }
+      "requires": {}
     },
     "eslint-import-resolver-node": {
-      "version": "0.3.6",
-      "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
-      "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==",
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
+      "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
       "dev": true,
       "requires": {
         "debug": "^3.2.7",
-        "resolve": "^1.20.0"
+        "is-core-module": "^2.13.0",
+        "resolve": "^1.22.4"
       },
       "dependencies": {
         "debug": {
@@ -6755,14 +7725,12 @@
       }
     },
     "eslint-module-utils": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz",
-      "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==",
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz",
+      "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==",
       "dev": true,
       "requires": {
-        "debug": "^3.2.7",
-        "find-up": "^2.1.0",
-        "pkg-dir": "^2.0.0"
+        "debug": "^3.2.7"
       },
       "dependencies": {
         "debug": {
@@ -6777,33 +7745,37 @@
       }
     },
     "eslint-plugin-import": {
-      "version": "2.25.3",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz",
-      "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==",
+      "version": "2.29.1",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz",
+      "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==",
       "dev": true,
       "requires": {
-        "array-includes": "^3.1.4",
-        "array.prototype.flat": "^1.2.5",
-        "debug": "^2.6.9",
+        "array-includes": "^3.1.7",
+        "array.prototype.findlastindex": "^1.2.3",
+        "array.prototype.flat": "^1.3.2",
+        "array.prototype.flatmap": "^1.3.2",
+        "debug": "^3.2.7",
         "doctrine": "^2.1.0",
-        "eslint-import-resolver-node": "^0.3.6",
-        "eslint-module-utils": "^2.7.1",
-        "has": "^1.0.3",
-        "is-core-module": "^2.8.0",
+        "eslint-import-resolver-node": "^0.3.9",
+        "eslint-module-utils": "^2.8.0",
+        "hasown": "^2.0.0",
+        "is-core-module": "^2.13.1",
         "is-glob": "^4.0.3",
-        "minimatch": "^3.0.4",
-        "object.values": "^1.1.5",
-        "resolve": "^1.20.0",
-        "tsconfig-paths": "^3.11.0"
+        "minimatch": "^3.1.2",
+        "object.fromentries": "^2.0.7",
+        "object.groupby": "^1.0.1",
+        "object.values": "^1.1.7",
+        "semver": "^6.3.1",
+        "tsconfig-paths": "^3.15.0"
       },
       "dependencies": {
         "debug": {
-          "version": "2.6.9",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
           "dev": true,
           "requires": {
-            "ms": "2.0.0"
+            "ms": "^2.1.1"
           }
         },
         "doctrine": {
@@ -6824,32 +7796,36 @@
             "brace-expansion": "^1.1.7"
           }
         },
-        "ms": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+        "semver": {
+          "version": "6.3.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+          "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
           "dev": true
         }
       }
     },
     "eslint-plugin-jsx-a11y": {
-      "version": "6.5.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz",
-      "integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==",
-      "dev": true,
-      "requires": {
-        "@babel/runtime": "^7.16.3",
-        "aria-query": "^4.2.2",
-        "array-includes": "^3.1.4",
-        "ast-types-flow": "^0.0.7",
-        "axe-core": "^4.3.5",
-        "axobject-query": "^2.2.0",
-        "damerau-levenshtein": "^1.0.7",
+      "version": "6.8.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz",
+      "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==",
+      "dev": true,
+      "requires": {
+        "@babel/runtime": "^7.23.2",
+        "aria-query": "^5.3.0",
+        "array-includes": "^3.1.7",
+        "array.prototype.flatmap": "^1.3.2",
+        "ast-types-flow": "^0.0.8",
+        "axe-core": "=4.7.0",
+        "axobject-query": "^3.2.1",
+        "damerau-levenshtein": "^1.0.8",
         "emoji-regex": "^9.2.2",
-        "has": "^1.0.3",
-        "jsx-ast-utils": "^3.2.1",
-        "language-tags": "^1.0.5",
-        "minimatch": "^3.0.4"
+        "es-iterator-helpers": "^1.0.15",
+        "hasown": "^2.0.0",
+        "jsx-ast-utils": "^3.3.5",
+        "language-tags": "^1.0.9",
+        "minimatch": "^3.1.2",
+        "object.entries": "^1.1.7",
+        "object.fromentries": "^2.0.7"
       },
       "dependencies": {
         "minimatch": {
@@ -6905,19 +7881,21 @@
       }
     },
     "eslint-plugin-prettier": {
-      "version": "3.4.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz",
-      "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==",
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz",
+      "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==",
       "dev": true,
       "requires": {
-        "prettier-linter-helpers": "^1.0.0"
+        "prettier-linter-helpers": "^1.0.0",
+        "synckit": "^0.8.6"
       }
     },
     "eslint-plugin-promise": {
-      "version": "4.3.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz",
-      "integrity": "sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ==",
-      "dev": true
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.2.0.tgz",
+      "integrity": "sha512-QmAqwizauvnKOlifxyDj2ObfULpHQawlg/zQdgEixur9vl0CvZGv/LCJV2rtj3210QCoeGBzVMfMXqGAOr/4fA==",
+      "dev": true,
+      "requires": {}
     },
     "eslint-scope": {
       "version": "5.1.1",
@@ -6947,40 +7925,26 @@
       }
     },
     "eslint-visitor-keys": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
-      "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
       "dev": true
     },
     "espree": {
-      "version": "7.3.1",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
-      "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
+      "version": "9.6.1",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+      "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
       "dev": true,
       "requires": {
-        "acorn": "^7.4.0",
-        "acorn-jsx": "^5.3.1",
-        "eslint-visitor-keys": "^1.3.0"
-      },
-      "dependencies": {
-        "eslint-visitor-keys": {
-          "version": "1.3.0",
-          "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
-          "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
-          "dev": true
-        }
+        "acorn": "^8.9.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.4.1"
       }
     },
-    "esprima": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-      "dev": true
-    },
     "esquery": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
-      "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
+      "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
       "dev": true,
       "requires": {
         "estraverse": "^5.1.0"
@@ -7029,23 +7993,6 @@
       "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
       "dev": true
     },
-    "execa": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
-      "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
-      "dev": true,
-      "requires": {
-        "cross-spawn": "^7.0.3",
-        "get-stream": "^6.0.0",
-        "human-signals": "^2.1.0",
-        "is-stream": "^2.0.0",
-        "merge-stream": "^2.0.0",
-        "npm-run-path": "^4.0.1",
-        "onetime": "^5.1.2",
-        "signal-exit": "^3.0.3",
-        "strip-final-newline": "^2.0.0"
-      }
-    },
     "fast-deep-equal": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -7059,9 +8006,9 @@
       "dev": true
     },
     "fast-glob": {
-      "version": "3.2.7",
-      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz",
-      "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==",
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+      "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
       "dev": true,
       "requires": {
         "@nodelib/fs.stat": "^2.0.2",
@@ -7080,7 +8027,7 @@
     "fast-levenshtein": {
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
       "dev": true
     },
     "fastest-levenshtein": {
@@ -7090,9 +8037,9 @@
       "dev": true
     },
     "fastq": {
-      "version": "1.13.0",
-      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
-      "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
+      "version": "1.17.1",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+      "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
       "dev": true,
       "requires": {
         "reusify": "^1.0.4"
@@ -7108,21 +8055,22 @@
       }
     },
     "fill-range": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
       "dev": true,
       "requires": {
         "to-regex-range": "^5.0.1"
       }
     },
     "find-up": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
-      "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
       "dev": true,
       "requires": {
-        "locate-path": "^2.0.0"
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
       }
     },
     "flat": {
@@ -7147,6 +8095,15 @@
       "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==",
       "dev": true
     },
+    "for-each": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+      "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+      "dev": true,
+      "requires": {
+        "is-callable": "^1.1.3"
+      }
+    },
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -7161,15 +8118,27 @@
       "optional": true
     },
     "function-bind": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
       "dev": true
     },
-    "functional-red-black-tree": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
-      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+    "function.prototype.name": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
+      "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.2.0",
+        "es-abstract": "^1.22.1",
+        "functions-have-names": "^1.2.3"
+      }
+    },
+    "functions-have-names": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
       "dev": true
     },
     "get-caller-file": {
@@ -7179,36 +8148,27 @@
       "dev": true
     },
     "get-intrinsic": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
-      "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+      "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
       "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3",
-        "has-symbols": "^1.0.1"
-      }
-    },
-    "get-stdin": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
-      "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
-      "dev": true
-    },
-    "get-stream": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
-      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
-      "dev": true
+      "requires": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "has-proto": "^1.0.1",
+        "has-symbols": "^1.0.3",
+        "hasown": "^2.0.0"
+      }
     },
     "get-symbol-description": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
-      "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
+      "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==",
       "dev": true,
       "requires": {
-        "call-bind": "^1.0.2",
-        "get-intrinsic": "^1.1.1"
+        "call-bind": "^1.0.5",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.4"
       }
     },
     "glob": {
@@ -7252,32 +8212,57 @@
       "dev": true
     },
     "globals": {
-      "version": "13.12.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz",
-      "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==",
+      "version": "13.24.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+      "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
       "dev": true,
       "requires": {
         "type-fest": "^0.20.2"
       }
     },
+    "globalthis": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+      "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.2.1",
+        "gopd": "^1.0.1"
+      }
+    },
     "globby": {
-      "version": "11.0.4",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz",
-      "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==",
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
       "dev": true,
       "requires": {
         "array-union": "^2.1.0",
         "dir-glob": "^3.0.1",
-        "fast-glob": "^3.1.1",
-        "ignore": "^5.1.4",
-        "merge2": "^1.3.0",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
         "slash": "^3.0.0"
       }
     },
+    "gopd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+      "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+      "dev": true,
+      "requires": {
+        "get-intrinsic": "^1.1.3"
+      }
+    },
     "graceful-fs": {
-      "version": "4.2.9",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
-      "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+      "dev": true
+    },
+    "graphemer": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+      "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
       "dev": true
     },
     "growl": {
@@ -7286,19 +8271,10 @@
       "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
       "dev": true
     },
-    "has": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
-      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1"
-      }
-    },
     "has-bigints": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz",
-      "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
+      "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
       "dev": true
     },
     "has-flag": {
@@ -7307,19 +8283,43 @@
       "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
       "dev": true
     },
-    "has-symbols": {
+    "has-property-descriptors": {
       "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
-      "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+      "dev": true,
+      "requires": {
+        "es-define-property": "^1.0.0"
+      }
+    },
+    "has-proto": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+      "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+      "dev": true
+    },
+    "has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
       "dev": true
     },
     "has-tostringtag": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
-      "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
       "dev": true,
       "requires": {
-        "has-symbols": "^1.0.2"
+        "has-symbols": "^1.0.3"
+      }
+    },
+    "hasown": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.2"
       }
     },
     "he": {
@@ -7329,32 +8329,36 @@
       "dev": true
     },
     "http-proxy-agent": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
-      "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+      "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
       "dev": true,
       "requires": {
-        "@tootallnate/once": "1",
-        "agent-base": "6",
-        "debug": "4"
+        "agent-base": "^7.1.0",
+        "debug": "^4.3.4"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.5",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+          "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+          "dev": true,
+          "requires": {
+            "ms": "2.1.2"
+          }
+        }
       }
     },
     "https-proxy-agent": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
-      "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz",
+      "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==",
       "dev": true,
       "requires": {
-        "agent-base": "6",
+        "agent-base": "^7.0.2",
         "debug": "4"
       }
     },
-    "human-signals": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
-      "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
-      "dev": true
-    },
     "iconv-lite": {
       "version": "0.6.3",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -7363,10 +8367,16 @@
         "safer-buffer": ">= 2.1.2 < 3.0.0"
       }
     },
+    "ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "dev": true
+    },
     "ignore": {
-      "version": "5.1.9",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz",
-      "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==",
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
+      "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
       "dev": true
     },
     "immediate": {
@@ -7438,12 +8448,6 @@
           "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
           "dev": true
         },
-        "path-exists": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-          "dev": true
-        },
         "pkg-dir": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
@@ -7478,22 +8482,41 @@
       "dev": true
     },
     "internal-slot": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
-      "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
+      "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==",
       "dev": true,
       "requires": {
-        "get-intrinsic": "^1.1.0",
-        "has": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "hasown": "^2.0.0",
         "side-channel": "^1.0.4"
       }
     },
     "interpret": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
-      "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz",
+      "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==",
       "dev": true
     },
+    "is-array-buffer": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
+      "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.2.1"
+      }
+    },
+    "is-async-function": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
+      "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==",
+      "dev": true,
+      "requires": {
+        "has-tostringtag": "^1.0.0"
+      }
+    },
     "is-bigint": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
@@ -7523,18 +8546,27 @@
       }
     },
     "is-callable": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
-      "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+      "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
       "dev": true
     },
     "is-core-module": {
-      "version": "2.8.0",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz",
-      "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==",
+      "version": "2.13.1",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
+      "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
+      "dev": true,
+      "requires": {
+        "hasown": "^2.0.0"
+      }
+    },
+    "is-data-view": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
+      "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
       "dev": true,
       "requires": {
-        "has": "^1.0.3"
+        "is-typed-array": "^1.1.13"
       }
     },
     "is-date-object": {
@@ -7552,12 +8584,30 @@
       "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
       "dev": true
     },
+    "is-finalizationregistry": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz",
+      "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2"
+      }
+    },
     "is-fullwidth-code-point": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
       "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
       "dev": true
     },
+    "is-generator-function": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
+      "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
+      "dev": true,
+      "requires": {
+        "has-tostringtag": "^1.0.0"
+      }
+    },
     "is-glob": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
@@ -7567,10 +8617,22 @@
         "is-extglob": "^2.1.1"
       }
     },
+    "is-interactive": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz",
+      "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==",
+      "dev": true
+    },
+    "is-map": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
+      "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+      "dev": true
+    },
     "is-negative-zero": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
-      "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
+      "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
       "dev": true
     },
     "is-number": {
@@ -7580,14 +8642,20 @@
       "dev": true
     },
     "is-number-object": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz",
-      "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==",
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
+      "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
       "dev": true,
       "requires": {
         "has-tostringtag": "^1.0.0"
       }
     },
+    "is-path-inside": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+      "dev": true
+    },
     "is-plain-obj": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
@@ -7613,17 +8681,20 @@
         "has-tostringtag": "^1.0.0"
       }
     },
-    "is-shared-array-buffer": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz",
-      "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==",
+    "is-set": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
+      "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
       "dev": true
     },
-    "is-stream": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
-      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
-      "dev": true
+    "is-shared-array-buffer": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
+      "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.7"
+      }
     },
     "is-string": {
       "version": "1.0.7",
@@ -7643,21 +8714,52 @@
         "has-symbols": "^1.0.2"
       }
     },
+    "is-typed-array": {
+      "version": "1.1.13",
+      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
+      "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
+      "dev": true,
+      "requires": {
+        "which-typed-array": "^1.1.14"
+      }
+    },
     "is-unicode-supported": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
       "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
       "dev": true
     },
+    "is-weakmap": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
+      "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+      "dev": true
+    },
     "is-weakref": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz",
-      "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
+      "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2"
+      }
+    },
+    "is-weakset": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz",
+      "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==",
       "dev": true,
       "requires": {
-        "call-bind": "^1.0.0"
+        "call-bind": "^1.0.7",
+        "get-intrinsic": "^1.2.4"
       }
     },
+    "isarray": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+      "dev": true
+    },
     "isexe": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -7671,18 +8773,31 @@
       "dev": true
     },
     "istextorbinary": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-6.0.0.tgz",
-      "integrity": "sha512-4j3UqQCa06GAf6QHlN3giz2EeFU7qc6Q5uB/aY7Gmb3xmLDLepDOtsZqkb4sCfJgFvTbLUinNw0kHgHs8XOHoQ==",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-7.0.0.tgz",
+      "integrity": "sha512-RrJZgAttvlKBUoG8zGS2oyl12Exb1PJ6K6rSFH+9tEXadXMT/mRd0Lm4zwQN29jQyM6iGUFzL5HStEmismPNgw==",
+      "requires": {
+        "binaryextensions": "^4.19.0",
+        "textextensions": "^5.16.0"
+      }
+    },
+    "iterator.prototype": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz",
+      "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==",
+      "dev": true,
       "requires": {
-        "binaryextensions": "^4.18.0",
-        "textextensions": "^5.14.0"
+        "define-properties": "^1.2.1",
+        "get-intrinsic": "^1.2.1",
+        "has-symbols": "^1.0.3",
+        "reflect.getprototypeof": "^1.0.4",
+        "set-function-name": "^2.0.1"
       }
     },
     "jest-worker": {
-      "version": "27.4.0",
-      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.0.tgz",
-      "integrity": "sha512-4WuKcUxtzxBoKOUFbt1MtTY9fJwPVD4aN/4Cgxee7OLetPZn5as2bjfZz98XSf2Zq1JFfhqPZpS+43BmWXKgCA==",
+      "version": "27.5.1",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+      "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
       "dev": true,
       "requires": {
         "@types/node": "*",
@@ -7701,20 +8816,13 @@
         }
       }
     },
-    "js-tokens": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-      "dev": true
-    },
     "js-yaml": {
-      "version": "3.14.1",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
-      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
       "dev": true,
       "requires": {
-        "argparse": "^1.0.7",
-        "esprima": "^4.0.0"
+        "argparse": "^2.0.1"
       }
     },
     "json-parse-even-better-errors": {
@@ -7745,13 +8853,15 @@
       }
     },
     "jsx-ast-utils": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz",
-      "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==",
+      "version": "3.3.5",
+      "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
+      "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
       "dev": true,
       "requires": {
-        "array-includes": "^3.1.3",
-        "object.assign": "^4.1.2"
+        "array-includes": "^3.1.6",
+        "array.prototype.flat": "^1.3.1",
+        "object.assign": "^4.1.4",
+        "object.values": "^1.1.6"
       }
     },
     "jszip": {
@@ -7779,18 +8889,18 @@
       "dev": true
     },
     "language-subtag-registry": {
-      "version": "0.3.21",
-      "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
-      "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==",
+      "version": "0.3.23",
+      "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
+      "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==",
       "dev": true
     },
     "language-tags": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
-      "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=",
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz",
+      "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==",
       "dev": true,
       "requires": {
-        "language-subtag-registry": "~0.3.2"
+        "language-subtag-registry": "^0.3.20"
       }
     },
     "levn": {
@@ -7818,25 +8928,13 @@
       "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==",
       "dev": true
     },
-    "loader-utils": {
-      "version": "1.4.2",
-      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
-      "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
-      "dev": true,
-      "requires": {
-        "big.js": "^5.2.2",
-        "emojis-list": "^3.0.0",
-        "json5": "^1.0.1"
-      }
-    },
     "locate-path": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
-      "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
       "dev": true,
       "requires": {
-        "p-locate": "^2.0.0",
-        "path-exists": "^3.0.0"
+        "p-locate": "^5.0.0"
       }
     },
     "lodash.merge": {
@@ -7845,12 +8943,6 @@
       "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
       "dev": true
     },
-    "lodash.truncate": {
-      "version": "4.4.2",
-      "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
-      "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
-      "dev": true
-    },
     "log-symbols": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -7861,25 +8953,6 @@
         "is-unicode-supported": "^0.1.0"
       }
     },
-    "lru-cache": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-      "dev": true,
-      "requires": {
-        "yallist": "^4.0.0"
-      }
-    },
-    "memory-fs": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
-      "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
-      "dev": true,
-      "requires": {
-        "errno": "^0.1.3",
-        "readable-stream": "^2.0.1"
-      }
-    },
     "merge-stream": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -7924,9 +8997,9 @@
       "dev": true
     },
     "minimatch": {
-      "version": "9.0.3",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
-      "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+      "version": "9.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
+      "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
       "requires": {
         "brace-expansion": "^2.0.1"
       },
@@ -7979,22 +9052,6 @@
         "yargs-unparser": "2.0.0"
       },
       "dependencies": {
-        "argparse": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-          "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-          "dev": true
-        },
-        "find-up": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
-          "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^6.0.0",
-            "path-exists": "^4.0.0"
-          }
-        },
         "glob": {
           "version": "7.2.0",
           "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
@@ -8020,24 +9077,6 @@
             }
           }
         },
-        "js-yaml": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-          "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-          "dev": true,
-          "requires": {
-            "argparse": "^2.0.1"
-          }
-        },
-        "locate-path": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
-          "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^5.0.0"
-          }
-        },
         "minimatch": {
           "version": "4.2.1",
           "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz",
@@ -8053,30 +9092,6 @@
           "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
           "dev": true
         },
-        "p-limit": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
-          "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
-          "dev": true,
-          "requires": {
-            "yocto-queue": "^0.1.0"
-          }
-        },
-        "p-locate": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
-          "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^3.0.2"
-          }
-        },
-        "path-exists": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-          "dev": true
-        },
         "supports-color": {
           "version": "8.1.1",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
@@ -8123,9 +9138,9 @@
       "integrity": "sha512-YOMqQ94r/1o95JS3yFye1czAVY6i3xreA6tsNnloLCKJKbfFMxgkhsLH0yYI0vWXBZmEQ80l66ue6UqFAgVv2g=="
     },
     "node-releases": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
-      "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
+      "version": "2.0.14",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
+      "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
       "dev": true
     },
     "normalize-path": {
@@ -8134,19 +9149,10 @@
       "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
       "dev": true
     },
-    "npm-run-path": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
-      "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
-      "dev": true,
-      "requires": {
-        "path-key": "^3.0.0"
-      }
-    },
     "object-inspect": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
-      "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==",
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
+      "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
       "dev": true
     },
     "object-keys": {
@@ -8156,37 +9162,60 @@
       "dev": true
     },
     "object.assign": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
-      "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+      "version": "4.1.5",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
+      "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
       "dev": true,
       "requires": {
-        "call-bind": "^1.0.0",
-        "define-properties": "^1.1.3",
-        "has-symbols": "^1.0.1",
+        "call-bind": "^1.0.5",
+        "define-properties": "^1.2.1",
+        "has-symbols": "^1.0.3",
         "object-keys": "^1.1.1"
       }
     },
     "object.entries": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz",
-      "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==",
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
+      "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
       "dev": true,
       "requires": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.1"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
+      }
+    },
+    "object.fromentries": {
+      "version": "2.0.8",
+      "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
+      "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-object-atoms": "^1.0.0"
+      }
+    },
+    "object.groupby": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
+      "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2"
       }
     },
     "object.values": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz",
-      "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz",
+      "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==",
       "dev": true,
       "requires": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.1"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
       }
     },
     "once": {
@@ -8208,9 +9237,9 @@
       }
     },
     "optionator": {
-      "version": "0.9.1",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
-      "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+      "version": "0.9.4",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+      "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
       "dev": true,
       "requires": {
         "deep-is": "^0.1.3",
@@ -8218,33 +9247,100 @@
         "levn": "^0.4.1",
         "prelude-ls": "^1.2.1",
         "type-check": "^0.4.0",
-        "word-wrap": "^1.2.3"
+        "word-wrap": "^1.2.5"
+      }
+    },
+    "ora": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz",
+      "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==",
+      "dev": true,
+      "requires": {
+        "chalk": "^5.3.0",
+        "cli-cursor": "^4.0.0",
+        "cli-spinners": "^2.9.0",
+        "is-interactive": "^2.0.0",
+        "is-unicode-supported": "^1.3.0",
+        "log-symbols": "^5.1.0",
+        "stdin-discarder": "^0.1.0",
+        "string-width": "^6.1.0",
+        "strip-ansi": "^7.1.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+          "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+          "dev": true
+        },
+        "chalk": {
+          "version": "5.3.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+          "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "10.3.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz",
+          "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==",
+          "dev": true
+        },
+        "is-unicode-supported": {
+          "version": "1.3.0",
+          "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
+          "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+          "dev": true
+        },
+        "log-symbols": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz",
+          "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==",
+          "dev": true,
+          "requires": {
+            "chalk": "^5.0.0",
+            "is-unicode-supported": "^1.1.0"
+          }
+        },
+        "string-width": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz",
+          "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==",
+          "dev": true,
+          "requires": {
+            "eastasianwidth": "^0.2.0",
+            "emoji-regex": "^10.2.1",
+            "strip-ansi": "^7.0.1"
+          }
+        },
+        "strip-ansi": {
+          "version": "7.1.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+          "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^6.0.1"
+          }
+        }
       }
     },
     "p-limit": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
-      "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
       "dev": true,
       "requires": {
-        "p-try": "^1.0.0"
+        "yocto-queue": "^0.1.0"
       }
     },
     "p-locate": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
-      "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
       "dev": true,
       "requires": {
-        "p-limit": "^1.1.0"
+        "p-limit": "^3.0.2"
       }
     },
-    "p-try": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
-      "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
-      "dev": true
-    },
     "pako": {
       "version": "1.0.11",
       "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
@@ -8267,9 +9363,9 @@
       "dev": true
     },
     "path-exists": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-      "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
       "dev": true
     },
     "path-is-absolute": {
@@ -8297,9 +9393,9 @@
       "dev": true
     },
     "picocolors": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
-      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
+      "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
       "dev": true
     },
     "picomatch": {
@@ -8308,14 +9404,11 @@
       "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
       "dev": true
     },
-    "pkg-dir": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
-      "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=",
-      "dev": true,
-      "requires": {
-        "find-up": "^2.1.0"
-      }
+    "possible-typed-array-names": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
+      "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
+      "dev": true
     },
     "prelude-ls": {
       "version": "1.2.1",
@@ -8324,9 +9417,9 @@
       "dev": true
     },
     "prettier": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz",
-      "integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==",
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.1.tgz",
+      "integrity": "sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==",
       "dev": true
     },
     "prettier-linter-helpers": {
@@ -8344,12 +9437,6 @@
       "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
       "dev": true
     },
-    "progress": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
-      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
-      "dev": true
-    },
     "prompts": {
       "version": "2.4.2",
       "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
@@ -8360,12 +9447,6 @@
         "sisteransi": "^1.0.5"
       }
     },
-    "prr": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
-      "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
-      "dev": true
-    },
     "punycode": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
@@ -8426,20 +9507,47 @@
       }
     },
     "rechoir": {
-      "version": "0.7.1",
-      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
-      "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==",
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
+      "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==",
+      "dev": true,
+      "requires": {
+        "resolve": "^1.20.0"
+      }
+    },
+    "reflect.getprototypeof": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
+      "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==",
       "dev": true,
       "requires": {
-        "resolve": "^1.9.0"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.1",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.4",
+        "globalthis": "^1.0.3",
+        "which-builtin-type": "^1.1.3"
       }
     },
     "regenerator-runtime": {
-      "version": "0.13.9",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
-      "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
+      "version": "0.14.1",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+      "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
       "dev": true
     },
+    "regexp.prototype.flags": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
+      "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.6",
+        "define-properties": "^1.2.1",
+        "es-errors": "^1.3.0",
+        "set-function-name": "^2.0.1"
+      }
+    },
     "regexpp": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
@@ -8452,20 +9560,15 @@
       "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
       "dev": true
     },
-    "require-from-string": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
-      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
-      "dev": true
-    },
     "resolve": {
-      "version": "1.20.0",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
-      "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
+      "version": "1.22.8",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+      "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
       "dev": true,
       "requires": {
-        "is-core-module": "^2.2.0",
-        "path-parse": "^1.0.6"
+        "is-core-module": "^2.13.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
       }
     },
     "resolve-cwd": {
@@ -8491,6 +9594,16 @@
       "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
       "dev": true
     },
+    "restore-cursor": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
+      "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
+      "dev": true,
+      "requires": {
+        "onetime": "^5.1.0",
+        "signal-exit": "^3.0.2"
+      }
+    },
     "reusify": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -8515,21 +9628,44 @@
         "queue-microtask": "^1.2.2"
       }
     },
+    "safe-array-concat": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
+      "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.7",
+        "get-intrinsic": "^1.2.4",
+        "has-symbols": "^1.0.3",
+        "isarray": "^2.0.5"
+      }
+    },
     "safe-buffer": {
       "version": "5.2.1",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
       "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
       "dev": true
     },
+    "safe-regex-test": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
+      "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.6",
+        "es-errors": "^1.3.0",
+        "is-regex": "^1.1.4"
+      }
+    },
     "safer-buffer": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
     },
     "schema-utils": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
-      "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
+      "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
       "dev": true,
       "requires": {
         "@types/json-schema": "^7.0.8",
@@ -8538,13 +9674,10 @@
       }
     },
     "semver": {
-      "version": "7.5.4",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
-      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
-      "dev": true,
-      "requires": {
-        "lru-cache": "^6.0.0"
-      }
+      "version": "7.6.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
+      "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
+      "dev": true
     },
     "serialize-javascript": {
       "version": "6.0.0",
@@ -8555,6 +9688,32 @@
         "randombytes": "^2.1.0"
       }
     },
+    "set-function-length": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+      "dev": true,
+      "requires": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.2"
+      }
+    },
+    "set-function-name": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+      "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+      "dev": true,
+      "requires": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "functions-have-names": "^1.2.3",
+        "has-property-descriptors": "^1.0.2"
+      }
+    },
     "setimmediate": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
@@ -8591,20 +9750,21 @@
       "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="
     },
     "side-channel": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
-      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+      "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
       "dev": true,
       "requires": {
-        "call-bind": "^1.0.0",
-        "get-intrinsic": "^1.0.2",
-        "object-inspect": "^1.9.0"
+        "call-bind": "^1.0.7",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.4",
+        "object-inspect": "^1.13.1"
       }
     },
     "signal-exit": {
-      "version": "3.0.6",
-      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
-      "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==",
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+      "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
       "dev": true
     },
     "sisteransi": {
@@ -8619,21 +9779,10 @@
       "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
       "dev": true
     },
-    "slice-ansi": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
-      "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
-      "dev": true,
-      "requires": {
-        "ansi-styles": "^4.0.0",
-        "astral-regex": "^2.0.0",
-        "is-fullwidth-code-point": "^3.0.0"
-      }
-    },
     "source-map": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+      "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
       "dev": true
     },
     "source-map-support": {
@@ -8644,19 +9793,30 @@
       "requires": {
         "buffer-from": "^1.0.0",
         "source-map": "^0.6.0"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
       }
     },
-    "sprintf-js": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
-      "dev": true
-    },
     "stack-chain": {
       "version": "1.3.7",
       "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz",
       "integrity": "sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU="
     },
+    "stdin-discarder": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz",
+      "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==",
+      "dev": true,
+      "requires": {
+        "bl": "^5.0.0"
+      }
+    },
     "string_decoder": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
@@ -8693,24 +9853,38 @@
         }
       }
     },
+    "string.prototype.trim": {
+      "version": "1.2.9",
+      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
+      "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.0",
+        "es-object-atoms": "^1.0.0"
+      }
+    },
     "string.prototype.trimend": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
-      "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
+      "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
       "dev": true,
       "requires": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
       }
     },
     "string.prototype.trimstart": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
-      "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+      "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
       "dev": true,
       "requires": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
       }
     },
     "strip-ansi": {
@@ -8725,13 +9899,7 @@
     "strip-bom": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-      "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
-      "dev": true
-    },
-    "strip-final-newline": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
-      "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+      "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
       "dev": true
     },
     "strip-json-comments": {
@@ -8749,76 +9917,62 @@
         "has-flag": "^4.0.0"
       }
     },
-    "table": {
-      "version": "6.7.3",
-      "resolved": "https://registry.npmjs.org/table/-/table-6.7.3.tgz",
-      "integrity": "sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw==",
+    "supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "dev": true
+    },
+    "synckit": {
+      "version": "0.8.8",
+      "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz",
+      "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==",
       "dev": true,
       "requires": {
-        "ajv": "^8.0.1",
-        "lodash.truncate": "^4.4.2",
-        "slice-ansi": "^4.0.0",
-        "string-width": "^4.2.3",
-        "strip-ansi": "^6.0.1"
-      },
-      "dependencies": {
-        "ajv": {
-          "version": "8.8.2",
-          "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz",
-          "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==",
-          "dev": true,
-          "requires": {
-            "fast-deep-equal": "^3.1.1",
-            "json-schema-traverse": "^1.0.0",
-            "require-from-string": "^2.0.2",
-            "uri-js": "^4.2.2"
-          }
-        },
-        "json-schema-traverse": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
-          "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
-          "dev": true
-        }
+        "@pkgr/core": "^0.1.0",
+        "tslib": "^2.6.2"
       }
     },
     "tapable": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
-      "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+      "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
       "dev": true
     },
     "terser": {
-      "version": "5.14.2",
-      "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz",
-      "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==",
+      "version": "5.31.1",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz",
+      "integrity": "sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==",
       "dev": true,
       "requires": {
-        "@jridgewell/source-map": "^0.3.2",
-        "acorn": "^8.5.0",
+        "@jridgewell/source-map": "^0.3.3",
+        "acorn": "^8.8.2",
         "commander": "^2.20.0",
         "source-map-support": "~0.5.20"
-      },
-      "dependencies": {
-        "acorn": {
-          "version": "8.7.1",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
-          "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
-          "dev": true
-        }
       }
     },
     "terser-webpack-plugin": {
-      "version": "5.2.5",
-      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.5.tgz",
-      "integrity": "sha512-3luOVHku5l0QBeYS8r4CdHYWEGMmIj3H1U64jgkdZzECcSOJAyJ9TjuqcQZvw1Y+4AOBN9SeYJPJmFn2cM4/2g==",
+      "version": "5.3.10",
+      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz",
+      "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==",
       "dev": true,
       "requires": {
-        "jest-worker": "^27.0.6",
+        "@jridgewell/trace-mapping": "^0.3.20",
+        "jest-worker": "^27.4.5",
         "schema-utils": "^3.1.1",
-        "serialize-javascript": "^6.0.0",
-        "source-map": "^0.6.1",
-        "terser": "^5.7.2"
+        "serialize-javascript": "^6.0.1",
+        "terser": "^5.26.0"
+      },
+      "dependencies": {
+        "serialize-javascript": {
+          "version": "6.0.2",
+          "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+          "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
+          "dev": true,
+          "requires": {
+            "randombytes": "^2.1.0"
+          }
+        }
       }
     },
     "text-table": {
@@ -8841,110 +9995,44 @@
         "is-number": "^7.0.0"
       }
     },
+    "ts-api-utils": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
+      "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
+      "dev": true,
+      "requires": {}
+    },
     "ts-loader": {
-      "version": "7.0.5",
-      "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-7.0.5.tgz",
-      "integrity": "sha512-zXypEIT6k3oTc+OZNx/cqElrsbBtYqDknf48OZos0NQ3RTt045fBIU8RRSu+suObBzYB355aIPGOe/3kj9h7Ig==",
+      "version": "9.5.1",
+      "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz",
+      "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==",
       "dev": true,
       "requires": {
-        "chalk": "^2.3.0",
-        "enhanced-resolve": "^4.0.0",
-        "loader-utils": "^1.0.2",
+        "chalk": "^4.1.0",
+        "enhanced-resolve": "^5.0.0",
         "micromatch": "^4.0.0",
-        "semver": "^6.0.0"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^1.9.0"
-          }
-        },
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
-        "color-convert": {
-          "version": "1.9.3",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-          "dev": true,
-          "requires": {
-            "color-name": "1.1.3"
-          }
-        },
-        "color-name": {
-          "version": "1.1.3",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-          "dev": true
-        },
-        "escape-string-regexp": {
-          "version": "1.0.5",
-          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-          "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-          "dev": true
-        },
-        "semver": {
-          "version": "6.3.1",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
-          "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
+        "semver": "^7.3.4",
+        "source-map": "^0.7.4"
       }
     },
     "tsconfig-paths": {
-      "version": "3.12.0",
-      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz",
-      "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==",
+      "version": "3.15.0",
+      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
+      "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
       "dev": true,
       "requires": {
         "@types/json5": "^0.0.29",
-        "json5": "^1.0.1",
-        "minimist": "^1.2.0",
+        "json5": "^1.0.2",
+        "minimist": "^1.2.6",
         "strip-bom": "^3.0.0"
       }
     },
     "tslib": {
-      "version": "1.14.1",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
-      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "version": "2.6.3",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
+      "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
       "dev": true
     },
-    "tsutils": {
-      "version": "3.21.0",
-      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
-      "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
-      "dev": true,
-      "requires": {
-        "tslib": "^1.8.1"
-      }
-    },
     "type-check": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -8960,24 +10048,86 @@
       "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
       "dev": true
     },
+    "typed-array-buffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
+      "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.7",
+        "es-errors": "^1.3.0",
+        "is-typed-array": "^1.1.13"
+      }
+    },
+    "typed-array-byte-length": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz",
+      "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.7",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "has-proto": "^1.0.3",
+        "is-typed-array": "^1.1.13"
+      }
+    },
+    "typed-array-byte-offset": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz",
+      "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==",
+      "dev": true,
+      "requires": {
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.7",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "has-proto": "^1.0.3",
+        "is-typed-array": "^1.1.13"
+      }
+    },
+    "typed-array-length": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz",
+      "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.7",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "has-proto": "^1.0.3",
+        "is-typed-array": "^1.1.13",
+        "possible-typed-array-names": "^1.0.0"
+      }
+    },
     "typescript": {
-      "version": "4.5.2",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz",
-      "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==",
+      "version": "5.4.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+      "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
       "dev": true
     },
     "unbox-primitive": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
-      "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
+      "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
       "dev": true,
       "requires": {
-        "function-bind": "^1.1.1",
-        "has-bigints": "^1.0.1",
-        "has-symbols": "^1.0.2",
+        "call-bind": "^1.0.2",
+        "has-bigints": "^1.0.2",
+        "has-symbols": "^1.0.3",
         "which-boxed-primitive": "^1.0.2"
       }
     },
+    "update-browserslist-db": {
+      "version": "1.0.16",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz",
+      "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==",
+      "dev": true,
+      "requires": {
+        "escalade": "^3.1.2",
+        "picocolors": "^1.0.1"
+      }
+    },
     "uri-js": {
       "version": "4.4.1",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -8993,32 +10143,11 @@
       "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
       "dev": true
     },
-    "v8-compile-cache": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
-      "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
-      "dev": true
-    },
     "vscode-cache": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/vscode-cache/-/vscode-cache-0.3.0.tgz",
       "integrity": "sha1-fMOWZOvZnTcDAwaLibxMlWFGZ8A="
     },
-    "vscode-debugadapter-testsupport": {
-      "version": "1.50.0",
-      "resolved": "https://registry.npmjs.org/vscode-debugadapter-testsupport/-/vscode-debugadapter-testsupport-1.50.0.tgz",
-      "integrity": "sha512-stS8yE8le59FLeKvCvdSY6PoYtmUXMxR1WiAW2JS65Sg7ip+yQm+WMKQZz8Dat0vtUF4ALcaKf/P+KjPTdzVww==",
-      "dev": true,
-      "requires": {
-        "vscode-debugprotocol": "1.50.1"
-      }
-    },
-    "vscode-debugprotocol": {
-      "version": "1.50.1",
-      "resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.50.1.tgz",
-      "integrity": "sha512-kIHIipklHnSjBm2KkRqTJLKL2FMZlJl0+/qpJt2y62YOamMNwcxNATnXXRgAwnzKKRMweqp93tJ83UTJ8+O7SQ==",
-      "dev": true
-    },
     "vscode-extension-telemetry": {
       "version": "0.1.7",
       "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.7.tgz",
@@ -9028,9 +10157,9 @@
       }
     },
     "watchpack": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
-      "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz",
+      "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==",
       "dev": true,
       "requires": {
         "glob-to-regexp": "^0.4.1",
@@ -9038,92 +10167,62 @@
       }
     },
     "webpack": {
-      "version": "5.76.0",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz",
-      "integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==",
+      "version": "5.91.0",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz",
+      "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==",
       "dev": true,
       "requires": {
         "@types/eslint-scope": "^3.7.3",
-        "@types/estree": "^0.0.51",
-        "@webassemblyjs/ast": "1.11.1",
-        "@webassemblyjs/wasm-edit": "1.11.1",
-        "@webassemblyjs/wasm-parser": "1.11.1",
+        "@types/estree": "^1.0.5",
+        "@webassemblyjs/ast": "^1.12.1",
+        "@webassemblyjs/wasm-edit": "^1.12.1",
+        "@webassemblyjs/wasm-parser": "^1.12.1",
         "acorn": "^8.7.1",
-        "acorn-import-assertions": "^1.7.6",
-        "browserslist": "^4.14.5",
+        "acorn-import-assertions": "^1.9.0",
+        "browserslist": "^4.21.10",
         "chrome-trace-event": "^1.0.2",
-        "enhanced-resolve": "^5.10.0",
-        "es-module-lexer": "^0.9.0",
+        "enhanced-resolve": "^5.16.0",
+        "es-module-lexer": "^1.2.1",
         "eslint-scope": "5.1.1",
         "events": "^3.2.0",
         "glob-to-regexp": "^0.4.1",
-        "graceful-fs": "^4.2.9",
+        "graceful-fs": "^4.2.11",
         "json-parse-even-better-errors": "^2.3.1",
         "loader-runner": "^4.2.0",
         "mime-types": "^2.1.27",
         "neo-async": "^2.6.2",
-        "schema-utils": "^3.1.0",
+        "schema-utils": "^3.2.0",
         "tapable": "^2.1.1",
-        "terser-webpack-plugin": "^5.1.3",
-        "watchpack": "^2.4.0",
+        "terser-webpack-plugin": "^5.3.10",
+        "watchpack": "^2.4.1",
         "webpack-sources": "^3.2.3"
-      },
-      "dependencies": {
-        "acorn": {
-          "version": "8.8.2",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
-          "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
-          "dev": true
-        },
-        "acorn-import-assertions": {
-          "version": "1.8.0",
-          "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
-          "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
-          "dev": true,
-          "requires": {}
-        },
-        "enhanced-resolve": {
-          "version": "5.12.0",
-          "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
-          "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==",
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.2.4",
-            "tapable": "^2.2.0"
-          }
-        },
-        "tapable": {
-          "version": "2.2.1",
-          "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
-          "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
-          "dev": true
-        }
       }
     },
     "webpack-cli": {
-      "version": "4.9.2",
-      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz",
-      "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz",
+      "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
       "dev": true,
       "requires": {
         "@discoveryjs/json-ext": "^0.5.0",
-        "@webpack-cli/configtest": "^1.1.1",
-        "@webpack-cli/info": "^1.4.1",
-        "@webpack-cli/serve": "^1.6.1",
+        "@webpack-cli/configtest": "^2.1.1",
+        "@webpack-cli/info": "^2.0.2",
+        "@webpack-cli/serve": "^2.0.5",
         "colorette": "^2.0.14",
-        "commander": "^7.0.0",
-        "execa": "^5.0.0",
+        "commander": "^10.0.1",
+        "cross-spawn": "^7.0.3",
+        "envinfo": "^7.7.3",
         "fastest-levenshtein": "^1.0.12",
         "import-local": "^3.0.2",
-        "interpret": "^2.2.0",
-        "rechoir": "^0.7.0",
+        "interpret": "^3.1.1",
+        "rechoir": "^0.8.0",
         "webpack-merge": "^5.7.3"
       },
       "dependencies": {
         "commander": {
-          "version": "7.2.0",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
-          "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+          "version": "10.0.1",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+          "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
           "dev": true
         }
       }
@@ -9166,6 +10265,51 @@
         "is-symbol": "^1.0.3"
       }
     },
+    "which-builtin-type": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz",
+      "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==",
+      "dev": true,
+      "requires": {
+        "function.prototype.name": "^1.1.5",
+        "has-tostringtag": "^1.0.0",
+        "is-async-function": "^2.0.0",
+        "is-date-object": "^1.0.5",
+        "is-finalizationregistry": "^1.0.2",
+        "is-generator-function": "^1.0.10",
+        "is-regex": "^1.1.4",
+        "is-weakref": "^1.0.2",
+        "isarray": "^2.0.5",
+        "which-boxed-primitive": "^1.0.2",
+        "which-collection": "^1.0.1",
+        "which-typed-array": "^1.1.9"
+      }
+    },
+    "which-collection": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
+      "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+      "dev": true,
+      "requires": {
+        "is-map": "^2.0.3",
+        "is-set": "^2.0.3",
+        "is-weakmap": "^2.0.2",
+        "is-weakset": "^2.0.3"
+      }
+    },
+    "which-typed-array": {
+      "version": "1.1.15",
+      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
+      "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==",
+      "dev": true,
+      "requires": {
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.7",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "has-tostringtag": "^1.0.2"
+      }
+    },
     "wildcard": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
@@ -9173,9 +10317,9 @@
       "dev": true
     },
     "word-wrap": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
-      "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+      "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
       "dev": true
     },
     "workerpool": {
@@ -9202,9 +10346,9 @@
       "dev": true
     },
     "ws": {
-      "version": "8.14.2",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz",
-      "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==",
+      "version": "8.17.1",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+      "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
       "requires": {}
     },
     "y18n": {
@@ -9213,12 +10357,6 @@
       "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
       "dev": true
     },
-    "yallist": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-      "dev": true
-    },
     "yargs": {
       "version": "16.2.0",
       "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
diff --git a/package.json b/package.json
index b3e086a9..1f905bb5 100644
--- a/package.json
+++ b/package.json
@@ -89,12 +89,7 @@
       {
         "view": "ObjectScriptProjectsExplorer",
         "contents": "To view or edit projects, create a virtual workspace folder to [edit or view code directly on an InterSystems server](https://docs.intersystems.com/components/csp/docbook/DocBook.UI.Page.cls?KEY=GVSCO_ssworkflow).\n[Add Server Namespace to Workspace](command:vscode-objectscript.addServerNamespaceToWorkspace)",
-        "when": "vscode-objectscript.projectsExplorerRootCount == 0 && workspaceFolderCount <= 0"
-      },
-      {
-        "view": "ObjectScriptProjectsExplorer",
-        "contents": "To view or edit projects, create a virtual workspace folder to [edit or view code directly on an InterSystems server](https://docs.intersystems.com/components/csp/docbook/DocBook.UI.Page.cls?KEY=GVSCO_ssworkflow).\n[Add Server Namespace to Workspace](command:vscode-objectscript.addServerNamespaceToWorkspace)\nOr connect a local workspace folder to an [InterSystems server](https://docs.intersystems.com/components/csp/docbook/DocBook.UI.Page.cls?KEY=GVSCO_ssworkflow).\n[Choose Server and Namespace](command:vscode-objectscript.connectFolderToServerNamespace)",
-        "when": "vscode-objectscript.projectsExplorerRootCount == 0 && workspaceFolderCount > 0"
+        "when": "vscode-objectscript.projectsExplorerRootCount == 0"
       }
     ],
     "menus": {
@@ -113,7 +108,7 @@
         },
         {
           "command": "vscode-objectscript.refreshLocalFile",
-          "when": "resourceScheme == file && editorLangId =~ /^objectscript/ && vscode-objectscript.connectActive"
+          "when": "!(resourceScheme =~ /^isfs(-readonly)?$/) && editorLangId =~ /^objectscript/ && vscode-objectscript.connectActive"
         },
         {
           "command": "vscode-objectscript.compileWithFlags",
@@ -197,7 +192,7 @@
         },
         {
           "command": "vscode-objectscript.serverCommands.sourceControl",
-          "when": "vscode-objectscript.connectActive && resourceScheme == isfs || (vscode-objectscript.connectActive && !editorIsOpen)"
+          "when": "(vscode-objectscript.connectActive && resourceScheme == isfs) || (vscode-objectscript.connectActive && !editorIsOpen)"
         },
         {
           "command": "vscode-objectscript.serverCommands.contextSourceControl",
@@ -211,14 +206,6 @@
           "command": "vscode-objectscript.serverCommands.contextOther",
           "when": "false"
         },
-        {
-          "command": "vscode-objectscript.hideExplorerForWorkspace",
-          "when": "config.objectscript.showExplorer"
-        },
-        {
-          "command": "vscode-objectscript.showExplorerForWorkspace",
-          "when": "!config.objectscript.showExplorer"
-        },
         {
           "command": "vscode-objectscript.jumpToTagAndOffset",
           "when": "editorLangId =~ /^objectscript(-int)?$/"
@@ -384,12 +371,12 @@
         },
         {
           "command": "vscode-objectscript.serverCommands.contextSourceControl",
-          "when": "view =~ /^ObjectScript(Projects)?Explorer$/ && viewItem =~ /^dataNode:/",
+          "when": "view == ObjectScriptProjectsExplorer && viewItem =~ /^dataNode:/",
           "group": "9_objectscript_servercommand@1"
         },
         {
           "command": "vscode-objectscript.serverCommands.contextOther",
-          "when": "view =~ /^ObjectScript(Projects)?Explorer$/ && viewItem =~ /^dataNode:/",
+          "when": "view == ObjectScriptProjectsExplorer && viewItem =~ /^dataNode:/",
           "group": "9_objectscript_servercommand@2"
         },
         {
@@ -486,7 +473,7 @@
         },
         {
           "command": "vscode-objectscript.editOthers",
-          "when": "resourceScheme == file && editorLangId =~ /^objectscript/ && vscode-objectscript.connectActive",
+          "when": "!(resourceScheme =~ /^isfs(-readonly)?$/) && editorLangId =~ /^objectscript/ && vscode-objectscript.connectActive",
           "group": "objectscript@2"
         },
         {
@@ -574,12 +561,12 @@
         },
         {
           "command": "vscode-objectscript.compileFolder",
-          "when": "vscode-objectscript.connectActive && resourceScheme == file",
+          "when": "vscode-objectscript.connectActive && !(resourceScheme =~ /^isfs(-readonly)?$/)",
           "group": "objectscript_modify@1"
         },
         {
           "command": "vscode-objectscript.importFolder",
-          "when": "vscode-objectscript.connectActive && resourceScheme == file",
+          "when": "vscode-objectscript.connectActive && !(resourceScheme =~ /^isfs(-readonly)?$/)",
           "group": "objectscript_modify@1"
         },
         {
@@ -1006,16 +993,6 @@
         "command": "vscode-objectscript.connectFolderToServerNamespace",
         "title": "Connect Folder to Server Namespace..."
       },
-      {
-        "category": "ObjectScript",
-        "command": "vscode-objectscript.hideExplorerForWorkspace",
-        "title": "Hide Explorer for Workspace"
-      },
-      {
-        "category": "ObjectScript",
-        "command": "vscode-objectscript.showExplorerForWorkspace",
-        "title": "Show Explorer for Workspace"
-      },
       {
         "category": "ObjectScript",
         "command": "vscode-objectscript.compileOnly",
@@ -1347,8 +1324,6 @@
             "filter": "",
             "exactFilter": "",
             "category": "*",
-            "noStorage": false,
-            "dontExportIfNoChanges": false,
             "maxConcurrentConnections": 0,
             "mapped": true
           },
@@ -1417,14 +1392,6 @@
                 "object"
               ]
             },
-            "noStorage": {
-              "description": "Strip the storage definition on export. Can be useful when working across multiple systems.",
-              "type": "boolean"
-            },
-            "dontExportIfNoChanges": {
-              "description": "Do not rewrite the local file if the content is identical to what came from the server.",
-              "type": "boolean"
-            },
             "maxConcurrentConnections": {
               "description": "Maximum number of concurrent export connections. (0 = unlimited)",
               "type": "number"
@@ -1435,11 +1402,6 @@
             }
           }
         },
-        "objectscript.showExplorer": {
-          "type": "boolean",
-          "default": true,
-          "description": "Show the InterSystems Explorer view."
-        },
         "objectscript.compileFlags": {
           "type": "string",
           "default": "cuk",
@@ -1532,7 +1494,7 @@
         "objectscript.explorer.alwaysShowServerCopy": {
           "description": "Always show the server copy of a document opened from the InterSystems Explorer.",
           "type": "boolean",
-          "default": false
+          "default": true
         },
         "objectscript.projects.webAppFileExtensions": {
           "markdownDescription": "When browsing a virtual workspace folder that has a project query parameter, all files with these extensions will be automatically treated as web application files. Extensions added here will be appended to the default list and should **NOT** include a dot. See the [Settings Reference documentation page](https://docs.intersystems.com/components/csp/docbook/DocBook.UI.Page.cls?KEY=GVSCO_settings#GVSCO_settings_objectscript) for a list of extensions included by default.",
@@ -1648,13 +1610,13 @@
           "id": "ObjectScriptExplorer",
           "name": "Explorer",
           "contextualTitle": "InterSystems",
-          "when": "workspaceFolderCount != 0 && config.objectscript.showExplorer == true"
+          "when": "vscode-objectscript.showExplorer"
         },
         {
           "id": "ObjectScriptProjectsExplorer",
           "name": "Projects",
           "contextualTitle": "InterSystems",
-          "when": "workspaceFolderCount != 0"
+          "when": "vscode-objectscript.showProjectsExplorer"
         }
       ]
     },
@@ -1812,41 +1774,41 @@
     "@types/vscode": "1.91.0",
     "@types/ws": "8.5.4",
     "@types/xmldom": "^0.1.29",
-    "@typescript-eslint/eslint-plugin": "^4.32.0",
-    "@typescript-eslint/parser": "^4.32.0",
+    "@typescript-eslint/eslint-plugin": "^7.12.0",
+    "@typescript-eslint/parser": "^7.12.0",
     "@vscode/dts": "^0.4.0",
-    "@vscode/test-electron": "^2.3.8",
-    "eslint": "^7.32.0",
-    "eslint-config-airbnb-base": "^14.2.1",
-    "eslint-config-prettier": "^6.11.0",
-    "eslint-plugin-import": "^2.24.2",
-    "eslint-plugin-jsx-a11y": "^6.3.1",
+    "@vscode/test-electron": "^2.4.0",
+    "eslint": "^8.56.0",
+    "eslint-config-airbnb-base": "^15.0.0",
+    "eslint-config-prettier": "^9.1.0",
+    "eslint-plugin-import": "^2.29.1",
+    "eslint-plugin-jsx-a11y": "^6.8.0",
     "eslint-plugin-node": "^11.1.0",
-    "eslint-plugin-prettier": "^3.1.4",
-    "eslint-plugin-promise": "^4.2.1",
+    "eslint-plugin-prettier": "^5.1.3",
+    "eslint-plugin-promise": "^6.2.0",
     "glob": "^7.1.6",
     "mocha": "^9.1.3",
     "path-browserify": "^1.0.1",
-    "prettier": "^2.0.5",
-    "ts-loader": "^7.0.5",
-    "typescript": "^4.4.3",
-    "vscode-debugadapter-testsupport": "^1.41.0",
-    "webpack": "^5.76.0",
-    "webpack-cli": "^4.5.0"
+    "prettier": "^3.3.1",
+    "ts-loader": "^9.5.1",
+    "typescript": "^5.4.5",
+    "@vscode/debugadapter-testsupport": "^1.65.0",
+    "webpack": "^5.91.0",
+    "webpack-cli": "^5.1.4"
   },
   "dependencies": {
     "@xmldom/xmldom": "^0.8.8",
     "core-js": "^3.6.5",
     "iconv-lite": "^0.6.0",
-    "istextorbinary": "^6.0.0",
+    "istextorbinary": "^7.0.0",
     "minimatch": "^9.0.3",
     "node-cmd": "^5.0.0",
     "node-fetch-cjs": "3.1.1",
     "vscode-cache": "^0.3.0",
-    "@vscode/debugadapter": "^1.61.0",
-    "@vscode/debugprotocol": "^1.61.0",
+    "@vscode/debugadapter": "^1.65.0",
+    "@vscode/debugprotocol": "^1.65.0",
     "vscode-extension-telemetry": "^0.1.6",
-    "ws": "^8.14.2"
+    "ws": "^8.17.1"
   },
   "extensionDependencies": [
     "intersystems-community.servermanager"
diff --git a/src/api/atelier.d.ts b/src/api/atelier.d.ts
index c76ea9f5..f79e92b0 100644
--- a/src/api/atelier.d.ts
+++ b/src/api/atelier.d.ts
@@ -67,14 +67,6 @@ export interface SearchResult {
   matches: SearchMatch[];
 }
 
-export interface DocSearchResult {
-  name: string;
-  cat: "RTN" | "CLS" | "CSP" | "OTH";
-  ts: string;
-  db: string;
-  gen: boolean;
-}
-
 export interface AtelierJob {
   pid: number;
   namespace: string;
@@ -83,12 +75,6 @@ export interface AtelierJob {
   device: string;
 }
 
-export interface DeleteStatus {
-  name: string;
-  db: string;
-  status: string;
-}
-
 interface AsyncCompileRequest {
   request: "compile";
   documents: string[];
diff --git a/src/api/index.ts b/src/api/index.ts
index e128e35e..9bb056c7 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -235,8 +235,8 @@ export class AtelierAPI {
       (docker
         ? "docker" + (dockerService ? `:${dockerService}:${port}` : "")
         : serverName
-        ? serverName
-        : `${host}:${port}`) + `[${ns}]`
+          ? serverName
+          : `${host}:${port}`) + `[${ns}]`
     );
   }
 
@@ -581,8 +581,6 @@ export class AtelierAPI {
 
   // v1+
   public actionQuery(query: string, parameters: string[]): Promise<Atelier.Response> {
-    // outputChannel.appendLine('SQL: ' + query);
-    // outputChannel.appendLine('SQLPARAMS: ' + JSON.stringify(parameters));
     return this.request(1, "POST", `${this.ns}/action/query`, {
       parameters,
       query,
@@ -668,6 +666,7 @@ export class AtelierAPI {
       outputChannel.appendLine(
         "\nWARNING: Compilation was cancelled. Partially-compiled documents may result in unexpected behavior."
       );
+      outputChannel.show(true);
     }
     let cancelResp = await this.cancelAsync(id);
     while (cancelResp.retryafter) {
diff --git a/src/commands/addServerNamespaceToWorkspace.ts b/src/commands/addServerNamespaceToWorkspace.ts
index 527c1134..e5f339e2 100644
--- a/src/commands/addServerNamespaceToWorkspace.ts
+++ b/src/commands/addServerNamespaceToWorkspace.ts
@@ -9,7 +9,7 @@ import {
   filesystemSchemas,
   smExtensionId,
 } from "../extension";
-import { cspAppsForUri, outputChannel } from "../utils";
+import { cspAppsForUri, handleError, notIsfs } from "../utils";
 import { pickProject } from "./project";
 
 /**
@@ -53,12 +53,9 @@ async function pickNamespaceOnServer(serverName: string): Promise<string> {
   const allNamespaces: string[] | undefined = await api
     .serverInfo(false)
     .then((data) => data.result.content.namespaces)
-    .catch((reason) => {
+    .catch((error) => {
       // Notify user about serverInfo failure
-      vscode.window.showErrorMessage(
-        reason.errorText || `Failed to fetch namespace list from server at ${connDisplayString}`,
-        "Dismiss"
-      );
+      handleError(error, `Failed to fetch namespace list from server at ${connDisplayString}.`);
       return undefined;
     });
   // Clear the panel entry created by the connection
@@ -113,27 +110,35 @@ export async function addServerNamespaceToWorkspace(resource?: vscode.Uri): Prom
       return;
     }
   }
-  // Prompt the user for edit or read-only
-  const mode = await vscode.window.showQuickPick(
-    [
-      {
-        value: FILESYSTEM_SCHEMA,
-        label: `$(pencil) Edit Code in ${namespace}`,
-        detail: "Documents opened in this folder will be editable.",
-      },
-      {
-        value: FILESYSTEM_READONLY_SCHEMA,
-        label: `$(lock) View Code in ${namespace}`,
-        detail: "Documents opened in this folder will be read-only.",
-      },
-    ],
-    { placeHolder: "Choose the type of access", ignoreFocusOut: true }
-  );
-  if (!mode) {
-    return;
+  const wsFolders = vscode.workspace.workspaceFolders ?? [];
+  let scheme: string;
+  if (wsFolders.length && wsFolders.some((wf) => notIsfs(wf.uri))) {
+    // Don't allow the creation of an editable ISFS folder
+    // if the workspace contains non-ISFS folders already
+    scheme = FILESYSTEM_READONLY_SCHEMA;
+  } else {
+    // Prompt the user for edit or read-only
+    scheme = await vscode.window
+      .showQuickPick(
+        [
+          {
+            value: FILESYSTEM_SCHEMA,
+            label: `$(pencil) Edit Code in ${namespace}`,
+            detail: "Documents opened in this folder will be editable.",
+          },
+          {
+            value: FILESYSTEM_READONLY_SCHEMA,
+            label: `$(lock) View Code in ${namespace}`,
+            detail: "Documents opened in this folder will be read-only.",
+          },
+        ],
+        { placeHolder: "Choose the type of access", ignoreFocusOut: true }
+      )
+      .then((mode) => mode?.value);
   }
+  if (!scheme) return;
   // Prompt the user to fill in the uri
-  const uri = await modifyWsFolderUri(vscode.Uri.parse(`${mode.value}://${serverName}:${namespace}/`));
+  const uri = await modifyWsFolderUri(vscode.Uri.parse(`${scheme}://${serverName}:${namespace}/`));
   if (!uri) {
     return;
   }
@@ -142,7 +147,7 @@ export async function addServerNamespaceToWorkspace(resource?: vscode.Uri): Prom
   const project = params.get("project");
   const csp = params.has("csp");
   const name = `${project ? `${project} - ` : ""}${serverName}:${namespace}${csp ? " web files" : ""}${
-    mode.value == FILESYSTEM_READONLY_SCHEMA && !project ? " (read-only)" : ""
+    scheme == FILESYSTEM_READONLY_SCHEMA && !project ? " (read-only)" : ""
   }`;
   // Append it to the workspace
   const added = vscode.workspace.updateWorkspaceFolders(
@@ -155,7 +160,7 @@ export async function addServerNamespaceToWorkspace(resource?: vscode.Uri): Prom
   // Handle failure
   if (!added) {
     vscode.window
-      .showErrorMessage("Folder not added. Maybe it already exists in the workspace.", "Retry", "Close")
+      .showErrorMessage("Folder not added. Maybe it already exists in the workspace.", "Retry", "Dismiss")
       .then((value) => {
         if (value === "Retry") {
           vscode.commands.executeCommand("vscode-objectscript.addServerNamespaceToWorkspace");
@@ -182,9 +187,7 @@ export async function getServerManagerApi(): Promise<any> {
 
 /** Prompt the user to fill in the `path` and `query` of `uri`. */
 async function modifyWsFolderUri(uri: vscode.Uri): Promise<vscode.Uri | undefined> {
-  if (!filesystemSchemas.includes(uri.scheme)) {
-    return;
-  }
+  if (notIsfs(uri)) return;
   const params = new URLSearchParams(uri.query);
   const api = new AtelierAPI(uri);
 
@@ -248,17 +251,7 @@ async function modifyWsFolderUri(uri: vscode.Uri): Promise<vscode.Uri | undefine
         .getCSPApps()
         .then((data) => data.result.content ?? [])
         .catch((error) => {
-          if (error && error.errorText && error.errorText !== "") {
-            outputChannel.appendLine(error.errorText);
-          } else {
-            outputChannel.appendLine(
-              typeof error == "string" ? error : error instanceof Error ? error.message : JSON.stringify(error)
-            );
-          }
-          vscode.window.showErrorMessage(
-            "Failed to fetch web application list. Check 'ObjectScript' output channel for details.",
-            "Dismiss"
-          );
+          handleError(error, "Failed to fetch web application list.");
           return;
         });
       if (cspApps == undefined) {
@@ -404,7 +397,7 @@ export async function modifyWsFolder(wsFolderUri?: vscode.Uri): Promise<void> {
     if (!wsFolder) {
       return;
     }
-    if (!filesystemSchemas.includes(wsFolder.uri.scheme)) {
+    if (notIsfs(wsFolder.uri)) {
       vscode.window.showErrorMessage(
         `Workspace folder '${wsFolder.name}' does not have scheme 'isfs' or 'isfs-readonly'.`,
         "Dismiss"
diff --git a/src/commands/compile.ts b/src/commands/compile.ts
index 6ede2aee..55f62b58 100644
--- a/src/commands/compile.ts
+++ b/src/commands/compile.ts
@@ -19,7 +19,9 @@ import {
   CurrentFile,
   currentFileFromContent,
   CurrentTextFile,
+  handleError,
   isClassDeployed,
+  notIsfs,
   notNull,
   outputChannel,
   routineNameTypeRegex,
@@ -80,7 +82,7 @@ export async function checkChangedOnServer(file: CurrentTextFile | CurrentBinary
   return mtime;
 }
 
-async function importFile(
+export async function importFile(
   file: CurrentTextFile | CurrentBinaryFile,
   ignoreConflict?: boolean,
   skipDeplCheck = false
@@ -115,7 +117,11 @@ async function importFile(
     }
   }
   const mtime = await checkChangedOnServer(file);
-  ignoreConflict = ignoreConflict || mtime < 0 || (file.uri.scheme === "file" && config("overwriteServerChanges"));
+  ignoreConflict =
+    ignoreConflict ||
+    mtime < 0 ||
+    (notIsfs(file.uri) &&
+      vscode.workspace.getConfiguration("objectscript", file.uri).get<boolean>("overwriteServerChanges"));
   return api
     .putDoc(
       file.name,
@@ -189,22 +195,7 @@ What do you want to do?`,
             return Promise.reject();
           });
       } else {
-        if (error && error.errorText && error.errorText !== "") {
-          outputChannel.appendLine("\n" + error.errorText);
-          vscode.window
-            .showErrorMessage(
-              `Failed to save file '${file.name}' on the server. Check 'ObjectScript' output channel for details.`,
-              "Show",
-              "Dismiss"
-            )
-            .then((action) => {
-              if (action === "Show") {
-                outputChannel.show(true);
-              }
-            });
-        } else {
-          vscode.window.showErrorMessage(`Failed to save file '${file.name}' on the server.`, "Dismiss");
-        }
+        handleError(error, `Failed to save file '${file.name}' on the server.`);
         return Promise.reject();
       }
     });
@@ -220,7 +211,7 @@ function updateOthers(others: string[], baseUri: vscode.Uri) {
     const uri = DocumentContentProvider.getUri(item, undefined, undefined, undefined, workspaceFolder?.uri);
     if (filesystemSchemas.includes(uri.scheme)) {
       fileSystemProvider.fireFileChanged(uri);
-    } else {
+    } else if (uri.scheme == OBJECTSCRIPT_FILE_SCHEMA) {
       documentContentProvider.update(uri);
     }
   });
@@ -239,7 +230,7 @@ export async function loadChanges(files: (CurrentTextFile | CurrentBinaryFile)[]
         const file = files.find((f) => f.name == doc.name);
         const mtime = Number(new Date(doc.ts + "Z"));
         workspaceState.update(`${file.uniqueId}:mtime`, mtime > 0 ? mtime : undefined);
-        if (file.uri.scheme === "file") {
+        if (notIsfs(file.uri)) {
           const content = await api.getDoc(file.name).then((data) => data.result.content);
           await vscode.workspace.fs.writeFile(
             file.uri,
@@ -255,7 +246,11 @@ export async function loadChanges(files: (CurrentTextFile | CurrentBinaryFile)[]
 }
 
 export async function compile(docs: CurrentFile[], flags?: string): Promise<any> {
-  flags = flags || config("compileFlags");
+  const conf = vscode.workspace.getConfiguration(
+    "objectscript",
+    vscode.workspace.getWorkspaceFolder(docs[0].uri) || docs[0].uri
+  );
+  flags = flags || conf.get("compileFlags");
   const api = new AtelierAPI(docs[0].uri);
   return vscode.window
     .withProgress(
@@ -275,24 +270,17 @@ export async function compile(docs: CurrentFile[], flags?: string): Promise<any>
             const info = docs.length > 1 ? "" : `${docs[0].name}: `;
             if (data.status && data.status.errors && data.status.errors.length) {
               throw new Error(`${info}Compile error`);
-            } else if (!config("suppressCompileMessages")) {
+            } else if (!conf.get("suppressCompileMessages")) {
               vscode.window.showInformationMessage(`${info}Compilation succeeded.`, "Dismiss");
             }
             return docs;
           })
           .catch(() => {
-            if (!config("suppressCompileErrorMessages")) {
-              vscode.window
-                .showErrorMessage(
-                  "Compilation failed. Check 'ObjectScript' output channel for details.",
-                  "Show",
-                  "Dismiss"
-                )
-                .then((action) => {
-                  if (action === "Show") {
-                    outputChannel.show(true);
-                  }
-                });
+            if (!conf.get("suppressCompileErrorMessages")) {
+              vscode.window.showErrorMessage(
+                "Compilation failed. Check the 'ObjectScript' Output channel for details.",
+                "Dismiss"
+              );
             }
             // Always fetch server changes, even when compile failed or got cancelled
             return docs;
@@ -312,7 +300,7 @@ export async function importAndCompile(
   }
 
   // Do nothing if it is a local file and objectscript.conn.active is false
-  if (file.uri.scheme === "file" && !config("conn").active) {
+  if (notIsfs(file.uri) && !config("conn").active) {
     return;
   }
 
@@ -359,7 +347,7 @@ export async function compileOnly(askFlags = false, document?: vscode.TextDocume
   }
 
   // Do nothing if it is a local file and objectscript.conn.active is false
-  if (file.uri.scheme === "file" && !config("conn").active) {
+  if (notIsfs(file.uri) && !config("conn").active) {
     return;
   }
 
@@ -419,17 +407,10 @@ export async function namespaceCompile(askFlags = false): Promise<any> {
         })
         .catch(() => {
           if (!config("suppressCompileErrorMessages")) {
-            vscode.window
-              .showErrorMessage(
-                `Compiling namespace ${api.ns} failed. Check 'ObjectScript' output channel for details.`,
-                "Show",
-                "Dismiss"
-              )
-              .then((action) => {
-                if (action === "Show") {
-                  outputChannel.show(true);
-                }
-              });
+            vscode.window.showErrorMessage(
+              `Compiling namespace '${api.ns}' failed. Check the 'ObjectScript' Output channel for details.`,
+              "Dismiss"
+            );
           }
         })
         .then(() => {
@@ -442,7 +423,7 @@ export async function namespaceCompile(askFlags = false): Promise<any> {
 
 async function importFiles(files: vscode.Uri[], noCompile = false) {
   const toCompile: CurrentFile[] = [];
-  await Promise.all<void>(
+  await Promise.allSettled<void>(
     files.map(
       throttleRequests((uri: vscode.Uri) => {
         return vscode.workspace.fs
@@ -526,17 +507,10 @@ export async function compileExplorerItems(nodes: NodeBase[]): Promise<any> {
         })
         .catch(() => {
           if (!config("suppressCompileErrorMessages")) {
-            vscode.window
-              .showErrorMessage(
-                `Compilation failed. Check 'ObjectScript' output channel for details.`,
-                "Show",
-                "Dismiss"
-              )
-              .then((action) => {
-                if (action === "Show") {
-                  outputChannel.show(true);
-                }
-              });
+            vscode.window.showErrorMessage(
+              "Compilation failed. Check the 'ObjectScript' Output channel for details.",
+              "Dismiss"
+            );
           }
         })
   );
@@ -551,8 +525,7 @@ async function importFileFromContent(
   skipDeplCheck = false
 ): Promise<void> {
   if (name.split(".").pop().toLowerCase() === "cls" && !skipDeplCheck) {
-    const result = await api.actionIndex([name]);
-    if (result.result.content[0].content.depl) {
+    if (await isClassDeployed(name, api)) {
       vscode.window.showErrorMessage(`Cannot import ${name} because it is deployed on the server.`, "Dismiss");
       return Promise.reject();
     }
@@ -588,22 +561,7 @@ async function importFileFromContent(
             }
           });
       } else {
-        if (error && error.errorText && error.errorText !== "") {
-          outputChannel.appendLine("\n" + error.errorText);
-          vscode.window
-            .showErrorMessage(
-              `Failed to save file '${name}' on the server. Check 'ObjectScript' output channel for details.`,
-              "Show",
-              "Dismiss"
-            )
-            .then((action) => {
-              if (action === "Show") {
-                outputChannel.show(true);
-              }
-            });
-        } else {
-          vscode.window.showErrorMessage(`Failed to save file '${name}' on the server.`, "Dismiss");
-        }
+        handleError(error, `Failed to save file '${name}' on the server.`);
         return Promise.reject();
       }
     });
@@ -643,17 +601,10 @@ async function promptForCompile(imported: string[], api: AtelierAPI, refresh: bo
                 })
                 .catch(() => {
                   if (!config("suppressCompileErrorMessages")) {
-                    vscode.window
-                      .showErrorMessage(
-                        "Compilation failed. Check 'ObjectScript' output channel for details.",
-                        "Show",
-                        "Dismiss"
-                      )
-                      .then((action) => {
-                        if (action === "Show") {
-                          outputChannel.show(true);
-                        }
-                      });
+                    vscode.window.showErrorMessage(
+                      "Compilation failed. Check the 'ObjectScript' Output channel for details.",
+                      "Dismiss"
+                    );
                   }
                 })
                 .finally(() => {
@@ -953,12 +904,6 @@ export async function importXMLFiles(): Promise<any> {
       promptForCompile([...new Set(imported)], api, filesystemSchemas.includes(connectionUri.scheme));
     }
   } catch (error) {
-    let errorMsg = "Error executing 'Import XML Files...' command.";
-    if (error && error.errorText && error.errorText !== "") {
-      outputChannel.appendLine("\n" + error.errorText);
-      outputChannel.show(true);
-      errorMsg += " Check 'ObjectScript' output channel for details.";
-    }
-    vscode.window.showErrorMessage(errorMsg, "Dismiss");
+    handleError(error, "Error executing 'Import XML Files...' command.");
   }
 }
diff --git a/src/commands/connectFolderToServerNamespace.ts b/src/commands/connectFolderToServerNamespace.ts
index ab5f6334..5f55339c 100644
--- a/src/commands/connectFolderToServerNamespace.ts
+++ b/src/commands/connectFolderToServerNamespace.ts
@@ -1,6 +1,7 @@
 import * as vscode from "vscode";
 import { AtelierAPI } from "../api";
 import { panel, resolveConnectionSpec, getResolvedConnectionSpec, smExtensionId } from "../extension";
+import { notIsfs } from "../utils";
 
 interface ConnSettings {
   server: string;
@@ -19,7 +20,7 @@ export async function connectFolderToServerNamespace(): Promise<void> {
   // Which folder?
   const allFolders = vscode.workspace.workspaceFolders;
   const items: vscode.QuickPickItem[] = allFolders
-    .filter((folder) => folder.uri.scheme === "file")
+    .filter((folder) => notIsfs(folder.uri))
     .map((folder) => {
       const config = vscode.workspace.getConfiguration("objectscript", folder);
       const conn: ConnSettings = config.get("conn");
diff --git a/src/commands/delete.ts b/src/commands/delete.ts
index 36f70941..3d4bc47a 100644
--- a/src/commands/delete.ts
+++ b/src/commands/delete.ts
@@ -4,8 +4,8 @@ import { AtelierAPI } from "../api";
 import { PackageNode } from "../explorer/models/packageNode";
 import { RootNode } from "../explorer/models/rootNode";
 import { NodeBase } from "../explorer/models/nodeBase";
-import { explorerProvider } from "../extension";
-import { outputChannel } from "../utils";
+import { FILESYSTEM_SCHEMA, explorerProvider } from "../extension";
+import { outputChannel, uriOfWorkspaceFolder } from "../utils";
 import { OtherStudioAction, fireOtherStudioAction } from "./studio";
 import { DocumentContentProvider } from "../providers/DocumentContentProvider";
 import { UserAction } from "../api/atelier";
@@ -15,11 +15,13 @@ function deleteList(items: string[], workspaceFolder: string, namespace: string)
     vscode.window.showWarningMessage("Nothing to delete");
   }
 
+  const wsFolderUri = uriOfWorkspaceFolder(workspaceFolder);
   const api = new AtelierAPI(workspaceFolder);
   api.setNamespace(namespace);
   return Promise.all(items.map((item) => api.deleteDoc(item))).then((files) => {
     files.forEach((file) => {
-      if (file.result.ext) {
+      if (file.result.ext && wsFolderUri?.scheme == FILESYSTEM_SCHEMA) {
+        // Only process source control output if we're in an isfs folder
         const uri = DocumentContentProvider.getUri(file.result.name);
         fireOtherStudioAction(OtherStudioAction.DeletedDocument, uri, <UserAction>file.result.ext);
       }
diff --git a/src/commands/export.ts b/src/commands/export.ts
index 00e8b994..6ac22d14 100644
--- a/src/commands/export.ts
+++ b/src/commands/export.ts
@@ -5,9 +5,11 @@ import { config, explorerProvider, OBJECTSCRIPT_FILE_SCHEMA, schemas, workspaceS
 import {
   currentFile,
   currentFileFromContent,
-  fileExists,
+  handleError,
   notNull,
   outputChannel,
+  stringifyError,
+  throttleRequests,
   uriOfWorkspaceFolder,
 } from "../utils";
 import { NodeBase } from "../explorer/models/nodeBase";
@@ -87,34 +89,15 @@ export const getFileName = (
   }
 };
 
-export const getFolderName = (folder: string, name: string, split: boolean, cat: string = null): string => {
-  const folderNameArray: string[] = name.split(".");
-  if (split) {
-    return [folder, cat, ...folderNameArray].filter(notNull).join(path.sep);
-  }
-  return [folder, cat, name].filter(notNull).join(path.sep);
-};
-
-export async function exportFile(
-  workspaceFolder: string,
-  namespace: string,
-  name: string,
-  fileName: string
-): Promise<void> {
-  if (!config("conn", workspaceFolder).active) {
-    return Promise.reject("Connection not active");
-  }
-  const api = new AtelierAPI(workspaceFolder);
+async function exportFile(wsFolderUri: vscode.Uri, namespace: string, name: string, fileName: string): Promise<void> {
+  const api = new AtelierAPI(wsFolderUri);
   api.setNamespace(namespace);
-  const log = (status) => outputChannel.appendLine(`export "${name}" as "${fileName}" - ${status}`);
-  const fileUri = vscode.Uri.file(fileName);
-  const foldersUri = vscode.Uri.file(path.dirname(fileName));
-  try {
-    if (!(await fileExists(foldersUri))) {
-      // Only attempt to create directories that don't exist
-      await vscode.workspace.fs.createDirectory(foldersUri);
-    }
+  let fileUri = vscode.Uri.file(fileName);
+  if (wsFolderUri.scheme != "file") fileUri = wsFolderUri.with({ path: fileUri.path });
+  const log = (status: string) =>
+    outputChannel.appendLine(`Export '${name}' to '${fileUri.toString(true)}' - ${status}`);
 
+  try {
     const data = await api.getDoc(name);
     if (!data || !data.result) {
       throw new Error("Received malformed JSON object from server fetching document");
@@ -127,127 +110,59 @@ export async function exportFile(
       const file = currentFileFromContent(fileUri, contentString);
       const serverTime = Number(new Date(data.result.ts + "Z"));
       await workspaceState.update(`${file.uniqueId}:mtime`, serverTime);
-      return;
     };
 
-    const { noStorage, dontExportIfNoChanges } = config("export");
-
-    const storageResult: { found: boolean; content?: string } = await new Promise((resolve, reject) => {
-      if (noStorage) {
-        // get only the storage xml for the doc.
-        api
-          .getDoc(name + "?storageOnly=1")
-          .then((storageData) => {
-            if (!storageData || !storageData.result) {
-              reject(new Error("Received malformed JSON object from server fetching storage only"));
-            }
-            const storageContent = storageData.result.content;
-
-            if (storageContent.length > 1 && storageContent[0] && storageContent.length < content.length) {
-              const storageContentString = storageContent.join("\n");
-              const contentString = content.join("\n");
-
-              // find and replace the docs storage section with ''
-              resolve({
-                content: contentString.replace(storageContentString, ""),
-                found: contentString.indexOf(storageContentString) >= 0,
-              });
-            } else {
-              resolve({ found: false });
-            }
-          })
-          .catch((error) => reject(error));
-      } else {
-        resolve({ found: false });
-      }
-    });
-
     if (Buffer.isBuffer(content)) {
       // This is a binary file
-      let isSkipped = "";
-      if (dontExportIfNoChanges && (await fileExists(fileUri))) {
-        const existingContent = await vscode.workspace.fs.readFile(fileUri);
-        if (!content.equals(existingContent)) {
-          await vscode.workspace.fs.writeFile(fileUri, content);
-          await recordMtime();
-        } else {
-          isSkipped = " => skipped - no changes.";
-        }
-      } else {
-        await vscode.workspace.fs.writeFile(fileUri, content);
-        await recordMtime();
-      }
-      log(`Success ${isSkipped}`);
+      await vscode.workspace.fs.writeFile(fileUri, content);
+      await recordMtime();
+      log("Success");
     } else {
       // This is a text file
-      let joinedContent = content.join("\n");
-      let isSkipped = "";
-
-      if (storageResult.found) {
-        joinedContent = storageResult.content;
-      }
-
-      if (dontExportIfNoChanges && (await fileExists(fileUri))) {
-        const existingContent = new TextDecoder().decode(await vscode.workspace.fs.readFile(fileUri));
-        // stringify to harmonise the text encoding.
-        if (JSON.stringify(joinedContent) !== JSON.stringify(existingContent)) {
-          await vscode.workspace.fs.writeFile(fileUri, new TextEncoder().encode(joinedContent));
-          await recordMtime();
-        } else {
-          isSkipped = " => skipped - no changes.";
-        }
-      } else {
-        await vscode.workspace.fs.writeFile(fileUri, new TextEncoder().encode(joinedContent));
-        await recordMtime();
-      }
-
-      log(`Success ${isSkipped}`);
+      const joinedContent = content.join("\n");
+      await vscode.workspace.fs.writeFile(fileUri, new TextEncoder().encode(joinedContent));
+      await recordMtime();
+      log("Success");
     }
   } catch (error) {
-    const errorStr = typeof error == "string" ? error : error instanceof Error ? error.message : JSON.stringify(error);
-    log(`ERROR${errorStr.length ? `: ${errorStr}` : ""}`);
-    throw errorStr;
+    const errorStr = stringifyError(error);
+    log(errorStr == "" ? "ERROR" : errorStr);
   }
 }
 
 export async function exportList(files: string[], workspaceFolder: string, namespace: string): Promise<any> {
   if (!files || !files.length) {
-    vscode.window.showWarningMessage("Nothing to export");
+    vscode.window.showWarningMessage("No documents to export.", "Dismiss");
+    return;
   }
-  const { atelier, folder, addCategory, map } = config("export", workspaceFolder);
-
-  if (!workspaceFolder) {
-    // No workspace folders are open
+  const wsFolderUri = uriOfWorkspaceFolder(workspaceFolder);
+  if (!workspaceFolder || !wsFolderUri) return;
+  if (!vscode.workspace.fs.isWritableFileSystem(wsFolderUri.scheme)) {
+    vscode.window.showErrorMessage(`Cannot export to read-only file system '${wsFolderUri.scheme}'.`, "Dismiss");
     return;
   }
-  const root = [
-    uriOfWorkspaceFolder(workspaceFolder).fsPath,
-    typeof folder === "string" && folder.length ? folder : null,
-  ]
-    .filter(notNull)
-    .join(path.sep);
-  const run = async (fileList) => {
-    const errors = [];
-    for (const file of fileList) {
-      await exportFile(workspaceFolder, namespace, file, getFileName(root, file, atelier, addCategory, map)).catch(
-        (error) => {
-          errors.push(`${file} - ${error}`);
-        }
-      );
-    }
-    outputChannel.appendLine(`Exported items: ${fileList.length - errors.length}`);
-    if (errors.length) {
-      outputChannel.appendLine(`Items failed to export: \n${errors.join("\n")}`);
-    }
-  };
+  if (!new AtelierAPI(wsFolderUri).active) {
+    vscode.window.showErrorMessage("Exporting documents requires an active server connection.", "Dismiss");
+    return;
+  }
+
+  const { atelier, folder, addCategory, map } = config("export", workspaceFolder);
+  const root = wsFolderUri.fsPath + (folder.length ? path.sep + folder : "");
+  outputChannel.show(true);
   return vscode.window.withProgress(
     {
-      title: "Export items",
+      title: `Exporting ${files.length == 1 ? files[0] : files.length + " documents"}`,
       location: vscode.ProgressLocation.Notification,
+      cancellable: false,
     },
-    () => {
-      return run(files);
-    }
+    () =>
+      Promise.allSettled<void>(
+        files.map(
+          throttleRequests((file: string) =>
+            exportFile(wsFolderUri, namespace, file, getFileName(root, file, atelier, addCategory, map))
+          )
+        )
+      )
   );
 }
 
@@ -277,7 +192,6 @@ export async function exportAll(): Promise<any> {
     return;
   }
   const api = new AtelierAPI(workspaceFolder);
-  outputChannel.show(true);
   const { category, generated, filter, exactFilter, mapped } = config("export", workspaceFolder);
   // Replicate the behavior of getDocNames() but use StudioOpenDialog for better performance
   let filterStr = "";
@@ -459,12 +373,6 @@ export async function exportDocumentsToXMLFile(): Promise<void> {
       }
     }
   } catch (error) {
-    let errorMsg = "Error executing 'Export Documents to XML File...' command.";
-    if (error && error.errorText && error.errorText !== "") {
-      outputChannel.appendLine("\n" + error.errorText);
-      outputChannel.show(true);
-      errorMsg += " Check 'ObjectScript' output channel for details.";
-    }
-    vscode.window.showErrorMessage(errorMsg, "Dismiss");
+    handleError(error, "Error executing 'Export Documents to XML File...' command.");
   }
 }
diff --git a/src/commands/jumpToTagAndOffset.ts b/src/commands/jumpToTagAndOffset.ts
index bbad2fbf..4179de40 100644
--- a/src/commands/jumpToTagAndOffset.ts
+++ b/src/commands/jumpToTagAndOffset.ts
@@ -1,6 +1,6 @@
 import * as vscode from "vscode";
 import { DocumentContentProvider } from "../providers/DocumentContentProvider";
-import { outputChannel } from "../utils";
+import { handleError } from "../utils";
 
 export async function jumpToTagAndOffset(): Promise<void> {
   const editor = vscode.window.activeTextEditor;
@@ -101,13 +101,6 @@ export async function openErrorLocation(): Promise<void> {
     // Show the document
     await vscode.window.showTextDocument(uri, { preview: false, selection });
   } catch (error) {
-    outputChannel.appendLine(
-      typeof error == "string" ? error : error instanceof Error ? error.message : JSON.stringify(error)
-    );
-    outputChannel.show(true);
-    vscode.window.showErrorMessage(
-      `Failed to open routine '${routine}.int'. Check 'ObjectScript' Output channel for details.`,
-      "Dismiss"
-    );
+    handleError(error, `Failed to open routine '${routine}.int'.`);
   }
 }
diff --git a/src/commands/newFile.ts b/src/commands/newFile.ts
index 58c35d0f..e4e6c94c 100644
--- a/src/commands/newFile.ts
+++ b/src/commands/newFile.ts
@@ -1,11 +1,12 @@
 import * as vscode from "vscode";
 import path = require("path");
 import { AtelierAPI } from "../api";
-import { config, FILESYSTEM_READONLY_SCHEMA, FILESYSTEM_SCHEMA } from "../extension";
+import { FILESYSTEM_SCHEMA } from "../extension";
 import { DocumentContentProvider } from "../providers/DocumentContentProvider";
-import { fileExists, notNull, outputChannel } from "../utils";
+import { handleError } from "../utils";
 import { getFileName } from "./export";
 import { importFolder } from "./compile";
+import { getUrisForDocument } from "../utils/documentIndex";
 
 interface InputStepItem extends vscode.QuickPickItem {
   value?: string;
@@ -156,11 +157,15 @@ async function multiStepInput(steps: InputStepOptions[]): Promise<string[] | und
 
 /** Use the export settings to determine the local URI */
 function getLocalUri(cls: string, wsFolder: vscode.WorkspaceFolder): vscode.Uri {
-  const { atelier, folder, addCategory, map } = config("export", wsFolder.name);
-  const root = [wsFolder.uri.fsPath, typeof folder === "string" && folder.length ? folder : null]
-    .filter(notNull)
-    .join(path.sep);
-  const fileName = getFileName(root, `${cls}.cls`, atelier, addCategory, map);
+  const conf = vscode.workspace.getConfiguration("objectscript.export", wsFolder);
+  const confFolder = conf.get("folder", "");
+  const fileName = getFileName(
+    wsFolder.uri.fsPath + (confFolder.length ? path.sep + confFolder : ""),
+    `${cls}.cls`,
+    conf.get("atelier"),
+    conf.get("addCategory"),
+    conf.get("map")
+  );
   let clsUri = vscode.Uri.file(fileName);
   if (wsFolder.uri.scheme != "file") {
     clsUri = wsFolder.uri.with({ path: clsUri.path });
@@ -249,7 +254,7 @@ export async function newFile(type: NewFileType): Promise<void> {
     if (!wsFolder) {
       return;
     }
-    if (wsFolder.uri.scheme == FILESYSTEM_READONLY_SCHEMA) {
+    if (!vscode.workspace.fs.isWritableFileSystem(wsFolder.uri.scheme)) {
       vscode.window.showErrorMessage(`Workspace folder '${wsFolder.name}' is read-only.`, "Dismiss");
       return;
     }
@@ -417,10 +422,8 @@ export async function newFile(type: NewFileType): Promise<void> {
           if (classes.length && classes.includes(value.toLowerCase())) {
             return "A class with this name already exists on the server";
           }
-          if (wsFolder.uri.scheme != FILESYSTEM_SCHEMA) {
-            return fileExists(getLocalUri(value, wsFolder)).then((exists) =>
-              exists ? `A class with this name already exists in workspace folder '${wsFolder.name}'` : undefined
-            );
+          if (wsFolder.uri.scheme != FILESYSTEM_SCHEMA && getUrisForDocument(`${value}.cls`, wsFolder).length) {
+            return `A class with this name already exists in workspace folder '${wsFolder.name}'`;
           }
         },
       },
@@ -819,8 +822,8 @@ ${
   kpiType == "sql"
     ? `/// Return a SQL statement to execute.\nMethod %OnGetSQL(ByRef pSQL As %String)`
     : kpiType == "mdx"
-    ? `/// Return an MDX statement to execute.\nMethod %OnGetMDX(ByRef pMDX As %String)`
-    : `/// Get the data for this KPI manually.\nMethod %OnExecute()`
+      ? `/// Return an MDX statement to execute.\nMethod %OnGetMDX(ByRef pMDX As %String)`
+      : `/// Get the data for this KPI manually.\nMethod %OnExecute()`
 } As %Status
 {
   Return $$$OK
@@ -839,19 +842,29 @@ ClassMethod %OnDashboardAction(pAction As %String, pContext As %ZEN.proxyObject)
 `;
     }
 
-    // Generate the file's URI
+    // Determine the file's URI
     let clsUri: vscode.Uri;
     if (wsFolder.uri.scheme == FILESYSTEM_SCHEMA) {
+      // Generate the URI
       clsUri = DocumentContentProvider.getUri(`${cls}.cls`, undefined, undefined, undefined, wsFolder.uri);
     } else {
-      // Use the export settings to determine the URI
-      clsUri = getLocalUri(cls, wsFolder);
+      // Ask the user for the URI
+      clsUri = await vscode.window.showSaveDialog({
+        defaultUri: getLocalUri(cls, wsFolder), // Use the export settings to determine the default URI
+        filters: {
+          Classes: ["cls"],
+        },
+      });
     }
 
     if (clsUri && clsContent) {
       // Write the file content
       await vscode.workspace.fs.writeFile(clsUri, new TextEncoder().encode(clsContent.trimStart()));
-      if (clsUri.scheme != FILESYSTEM_SCHEMA && api && config("importOnSave", wsFolder.name)) {
+      if (
+        clsUri.scheme != FILESYSTEM_SCHEMA &&
+        api &&
+        vscode.workspace.getConfiguration("objectscript", wsFolder).get("importOnSave")
+      ) {
         // Save this local file on the server
         await importFolder(clsUri, true);
       }
@@ -859,12 +872,6 @@ ClassMethod %OnDashboardAction(pAction As %String, pContext As %ZEN.proxyObject)
       vscode.window.showTextDocument(clsUri, { preview: false });
     }
   } catch (error) {
-    outputChannel.appendLine(
-      typeof error == "string" ? error : error instanceof Error ? error.message : JSON.stringify(error)
-    );
-    vscode.window.showErrorMessage(
-      `An error occurred while creating a ${type} class. Check 'ObjectScript' Output channel for details.`,
-      "Dismiss"
-    );
+    handleError(error, `An error occurred while creating a ${type} class.`);
   }
 }
diff --git a/src/commands/project.ts b/src/commands/project.ts
index 8211f48e..1f033072 100644
--- a/src/commands/project.ts
+++ b/src/commands/project.ts
@@ -9,7 +9,7 @@ import { RoutineNode } from "../explorer/models/routineNode";
 import { config, filesystemSchemas, projectsExplorerProvider, schemas } from "../extension";
 import { compareConns } from "../providers/DocumentContentProvider";
 import { isCSPFile } from "../providers/FileSystemProvider/FileSystemProvider";
-import { notNull, outputChannel } from "../utils";
+import { handleError, notIsfs, notNull } from "../utils";
 import { pickServerAndNamespace } from "./addServerNamespaceToWorkspace";
 import { exportList } from "./export";
 import { OtherStudioAction, StudioActions } from "./studio";
@@ -131,13 +131,7 @@ export async function createProject(node: NodeBase | undefined, api?: AtelierAPI
           desc,
         ]);
       } catch (error) {
-        let message = `Failed to create project '${name}'.`;
-        if (error && error.errorText && error.errorText !== "") {
-          outputChannel.appendLine("\n" + error.errorText);
-          outputChannel.show(true);
-          message += " Check 'ObjectScript' output channel for details.";
-        }
-        vscode.window.showErrorMessage(message, "Dismiss");
+        handleError(error, `Failed to create project '${name}'.`);
         return;
       }
 
@@ -147,13 +141,7 @@ export async function createProject(node: NodeBase | undefined, api?: AtelierAPI
         await studioActions.fireProjectUserAction(api, name, OtherStudioAction.CreatedNewDocument);
         await studioActions.fireProjectUserAction(api, name, OtherStudioAction.FirstTimeDocumentSave);
       } catch (error) {
-        let message = `Source control actions failed for project '${name}'.`;
-        if (error && error.errorText && error.errorText !== "") {
-          outputChannel.appendLine("\n" + error.errorText);
-          outputChannel.show(true);
-          message += " Check 'ObjectScript' output channel for details.";
-        }
-        vscode.window.showErrorMessage(message, "Dismiss");
+        handleError(error, `Source control actions failed for project '${name}'.`);
       }
 
       // Refresh the explorer
@@ -189,26 +177,15 @@ export async function deleteProject(node: ProjectNode | undefined): Promise<any>
     // Delete the project
     await api.actionQuery("DELETE FROM %Studio.Project WHERE Name = ?", [project]);
   } catch (error) {
-    let message = `Failed to delete project '${project}'.`;
-    if (error && error.errorText && error.errorText !== "") {
-      outputChannel.appendLine("\n" + error.errorText);
-      outputChannel.show(true);
-      message += " Check 'ObjectScript' output channel for details.";
-    }
-    return vscode.window.showErrorMessage(message, "Dismiss");
+    handleError(error, `Failed to delete project '${project}'.`);
+    return;
   }
 
   // Technically a project is a "document", so tell the server that we deleted it
   try {
     await new StudioActions().fireProjectUserAction(api, project, OtherStudioAction.DeletedDocument);
   } catch (error) {
-    let message = `'DeletedDocument' source control action failed for project '${project}'.`;
-    if (error && error.errorText && error.errorText !== "") {
-      outputChannel.appendLine("\n" + error.errorText);
-      outputChannel.show(true);
-      message += " Check 'ObjectScript' output channel for details.";
-    }
-    vscode.window.showErrorMessage(message, "Dismiss");
+    handleError(error, `'DeletedDocument' source control action failed for project '${project}'.`);
   }
 
   // Refresh the explorer
@@ -513,13 +490,7 @@ async function pickAdditions(
         })
         .catch((error) => {
           quickPick.hide();
-          let message = `Failed to get namespace contents.`;
-          if (error && error.errorText && error.errorText !== "") {
-            outputChannel.appendLine("\n" + error.errorText);
-            outputChannel.show(true);
-            message += " Check 'ObjectScript' output channel for details.";
-          }
-          vscode.window.showErrorMessage(message, "Dismiss");
+          handleError(error, "Failed to get namespace contents.");
         });
     };
     const expandItem = (itemIdx: number): Promise<void> => {
@@ -566,13 +537,7 @@ async function pickAdditions(
           })
           .catch((error) => {
             quickPick.hide();
-            let message = `Failed to get namespace contents.`;
-            if (error && error.errorText && error.errorText !== "") {
-              outputChannel.appendLine("\n" + error.errorText);
-              outputChannel.show(true);
-              message += " Check 'ObjectScript' output channel for details.";
-            }
-            vscode.window.showErrorMessage(message, "Dismiss");
+            handleError(error, "Failed to get namespace contents.");
           });
       }
     };
@@ -920,13 +885,8 @@ export async function modifyProject(
       });
     }
   } catch (error) {
-    let message = `Failed to modify project '${project}'.`;
-    if (error && error.errorText && error.errorText !== "") {
-      outputChannel.appendLine("\n" + error.errorText);
-      outputChannel.show(true);
-      message += " Check 'ObjectScript' output channel for details.";
-    }
-    return vscode.window.showErrorMessage(message, "Dismiss");
+    handleError(error, `Failed to modify project '${project}'.`);
+    return;
   }
 
   if (add.length || remove.length) {
@@ -945,7 +905,7 @@ export async function exportProjectContents(node: ProjectNode | undefined): Prom
   const api = new AtelierAPI(node.workspaceFolderUri);
   api.setNamespace(node.namespace);
   const project = node.label;
-  if (node.workspaceFolderUri.scheme == "file") {
+  if (notIsfs(node.workspaceFolderUri)) {
     workspaceFolder = node.workspaceFolder;
   } else {
     const conn = config("conn", node.workspaceFolder);
@@ -1002,6 +962,7 @@ export async function exportProjectContents(node: ProjectNode | undefined): Prom
 
 export async function compileProjectContents(node: ProjectNode): Promise<any> {
   const { workspaceFolderUri, namespace, label } = node;
+  const conf = vscode.workspace.getConfiguration("objectscript", workspaceFolderUri);
   const api = new AtelierAPI(workspaceFolderUri);
   api.setNamespace(namespace);
   const compileList: string[] = await api
@@ -1026,23 +987,16 @@ export async function compileProjectContents(node: ProjectNode): Promise<any> {
         .then((data) => {
           if (data.status && data.status.errors && data.status.errors.length) {
             throw new Error("Compile error");
-          } else if (!config("suppressCompileMessages")) {
+          } else if (!conf.get("suppressCompileMessages")) {
             vscode.window.showInformationMessage("Compilation succeeded.", "Dismiss");
           }
         })
         .catch(() => {
-          if (!config("suppressCompileErrorMessages")) {
-            vscode.window
-              .showErrorMessage(
-                `Compilation failed. Check 'ObjectScript' output channel for details.`,
-                "Show",
-                "Dismiss"
-              )
-              .then((action) => {
-                if (action === "Show") {
-                  outputChannel.show(true);
-                }
-              });
+          if (!conf.get("suppressCompileErrorMessages")) {
+            vscode.window.showErrorMessage(
+              "Compilation failed. Check the 'ObjectScript' Output channel for details.",
+              "Dismiss"
+            );
           }
         })
   );
@@ -1134,14 +1088,7 @@ export async function addIsfsFileToProject(
       });
     }
   } catch (error) {
-    let message = `Failed to modify project '${project}'.`;
-    if (error && error.errorText && error.errorText !== "") {
-      outputChannel.appendLine("\n" + error.errorText);
-      outputChannel.show(true);
-      message += " Check 'ObjectScript' output channel for details.";
-    }
-    vscode.window.showErrorMessage(message, "Dismiss");
-    return;
+    handleError(error, `Failed to modify project '${project}'.`);
   }
 }
 
@@ -1245,12 +1192,6 @@ export async function modifyProjectMetadata(nodeOrUri: NodeBase | vscode.Uri | u
     // Refesh the explorer
     projectsExplorerProvider.refresh();
   } catch (error) {
-    let message = `Failed to modify metadata of project '${project}'.`;
-    if (error && error.errorText && error.errorText !== "") {
-      outputChannel.appendLine("\n" + error.errorText);
-      outputChannel.show(true);
-      message += " Check 'ObjectScript' output channel for details.";
-    }
-    vscode.window.showErrorMessage(message, "Dismiss");
+    handleError(error, `Failed to modify metadata of project '${project}'.`);
   }
 }
diff --git a/src/commands/restDebugPanel.ts b/src/commands/restDebugPanel.ts
index 234e6079..36b1b293 100644
--- a/src/commands/restDebugPanel.ts
+++ b/src/commands/restDebugPanel.ts
@@ -5,7 +5,7 @@ import * as httpsModule from "https";
 
 import * as vscode from "vscode";
 import { AtelierAPI } from "../api";
-import { cspAppsForUri, outputChannel } from "../utils";
+import { cspAppsForUri, handleError } from "../utils";
 import { iscIcon } from "../extension";
 
 interface WebviewMessage {
@@ -91,13 +91,7 @@ export class RESTDebugPanel {
       .actionQuery("CALL %CSP.Apps_CSPAppList()", [])
       .then((data) => data.result.content.map((obj) => obj.AppUrl))
       .catch((error) => {
-        let errorMsg = "Failed to fetch the list of web applications from the server.";
-        if (error && error.errorText && error.errorText !== "") {
-          outputChannel.appendLine("\n" + error.errorText);
-          outputChannel.show(true);
-          errorMsg += " Check 'ObjectScript' output channel for details.";
-        }
-        vscode.window.showErrorMessage(errorMsg, "Dismiss");
+        handleError(error, "Failed to fetch the list of web applications from the server.");
         return null;
       });
     if (allWebApps == null) {
@@ -440,13 +434,7 @@ export class RESTDebugPanel {
               body: hasBody ? message.bodyContent : undefined,
               headers,
             }).catch((error) => {
-              outputChannel.appendLine(
-                typeof error == "string" ? error : error instanceof Error ? error.message : JSON.stringify(error)
-              );
-              vscode.window.showErrorMessage(
-                "Failed to send debuggee REST request. Check 'ObjectScript' Output channel for details.",
-                "Dismiss"
-              );
+              handleError(error, "Failed to send debuggee REST request.");
               vscode.debug.stopDebugging(vscode.debug.activeDebugSession);
             });
 
@@ -461,13 +449,8 @@ export class RESTDebugPanel {
               cspDebugId,
             });
           } catch (error) {
-            let errorMsg = "Failed to start debugging.";
-            if (error && error.errorText && error.errorText !== "") {
-              outputChannel.appendLine("\n" + error.errorText);
-              outputChannel.show(true);
-              errorMsg += " Check 'ObjectScript' output channel for details.";
-            }
-            return vscode.window.showErrorMessage(errorMsg, "Dismiss");
+            handleError(error, "Failed to start debugging.");
+            return;
           }
         }
       },
diff --git a/src/commands/serverActions.ts b/src/commands/serverActions.ts
index 276b90bd..17b1390c 100644
--- a/src/commands/serverActions.ts
+++ b/src/commands/serverActions.ts
@@ -13,7 +13,8 @@ import {
   shellWithDocker,
   currentFile,
   uriOfWorkspaceFolder,
-  outputChannel,
+  notIsfs,
+  handleError,
 } from "../utils";
 import { mainCommandMenu, mainSourceControlMenu } from "./studio";
 import { AtelierAPI } from "../api";
@@ -45,8 +46,9 @@ export async function serverActions(): Promise<void> {
       detail: "Force attempt to connect to the server",
     });
 
-    // Switching namespace makes only sense if the user has a local folder open and not a server-side folder!
-    if (uriOfWorkspaceFolder()?.scheme === "file") {
+    // Switching namespace makes only sense for non-ISFS folders
+    const wsUri = uriOfWorkspaceFolder();
+    if (wsUri && notIsfs(wsUri)) {
       actions.push({
         id: "switchNamespace",
         label: "Switch Namespace",
@@ -78,13 +80,7 @@ export async function serverActions(): Promise<void> {
           .serverInfo(false)
           .then((data) => data.result.content.namespaces)
           .catch((error) => {
-            let message = `Failed to fetch a list of namespaces.`;
-            if (error && error.errorText && error.errorText !== "") {
-              outputChannel.appendLine("\n" + error.errorText);
-              outputChannel.show(true);
-              message += " Check 'ObjectScript' output channel for details.";
-            }
-            vscode.window.showErrorMessage(message, "Dismiss");
+            handleError(error, "Failed to fetch a list of namespaces.");
             return undefined;
           });
 
@@ -240,13 +236,7 @@ export async function serverActions(): Promise<void> {
             )
             .then((data) => data.result.content)
             .catch((error) => {
-              let message = "Failed to fetch list of Studio Add-ins.";
-              if (error && error.errorText && error.errorText !== "") {
-                outputChannel.appendLine("\n" + error.errorText);
-                outputChannel.show(true);
-                message += " Check 'ObjectScript' output channel for details.";
-              }
-              vscode.window.showErrorMessage(message, "Dismiss");
+              handleError(error, "Failed to fetch list of Studio Add-ins.");
               return undefined;
             });
           if (addins != undefined) {
diff --git a/src/commands/studio.ts b/src/commands/studio.ts
index da4bf96e..ea856cdc 100644
--- a/src/commands/studio.ts
+++ b/src/commands/studio.ts
@@ -1,7 +1,7 @@
 import * as vscode from "vscode";
 import { AtelierAPI } from "../api";
-import { config, filesystemSchemas, iscIcon } from "../extension";
-import { outputChannel, outputConsole, getServerName } from "../utils";
+import { config, iscIcon } from "../extension";
+import { outputChannel, outputConsole, getServerName, notIsfs, handleError } from "../utils";
 import { DocumentContentProvider } from "../providers/DocumentContentProvider";
 import { ClassNode } from "../explorer/models/classNode";
 import { PackageNode } from "../explorer/models/packageNode";
@@ -129,7 +129,7 @@ export class StudioActions {
     const { target, errorText } = userAction;
     if (errorText !== "") {
       outputChannel.appendLine(errorText);
-      outputChannel.show();
+      outputChannel.show(true);
     }
     if (config().studioActionDebugOutput) {
       outputChannel.appendLine(JSON.stringify(userAction));
@@ -371,18 +371,11 @@ export class StudioActions {
               }
             })
             .then(() => resolve())
-            .catch((err) => {
-              outputChannel.appendLine(
-                `Executing Studio Action "${action.label}" on ${this.api.config.host}:${this.api.config.port}${
-                  this.api.config.pathPrefix
-                }[${this.api.config.ns}] failed${
-                  err.errorText && err.errorText !== "" ? " with the following error:" : "."
-                }`
+            .catch((error) => {
+              handleError(
+                error,
+                `Executing Studio Action "${action.label}" on ${this.api.config.host}:${this.api.config.port}${this.api.config.pathPrefix}[${this.api.config.ns}] failed.`
               );
-              if (err.errorText && err.errorText !== "") {
-                outputChannel.appendLine("\n" + err.errorText);
-              }
-              outputChannel.show(true);
               reject();
             });
         })
@@ -520,9 +513,7 @@ export async function mainSourceControlMenu(uri?: vscode.Uri): Promise<void> {
 
 async function _mainMenu(sourceControl: boolean, uri?: vscode.Uri): Promise<void> {
   uri = uri || vscode.window.activeTextEditor?.document.uri;
-  if (uri && !filesystemSchemas.includes(uri.scheme)) {
-    return;
-  }
+  if (uri && notIsfs(uri)) return;
   const studioActions = new StudioActions(uri);
   if (studioActions) {
     if (await studioActions.isSourceControlEnabled()) {
@@ -549,9 +540,7 @@ export async function contextSourceControlMenu(
 
 export async function _contextMenu(sourceControl: boolean, node: PackageNode | ClassNode | RoutineNode): Promise<void> {
   const nodeOrUri = node || vscode.window.activeTextEditor?.document.uri;
-  if (!nodeOrUri || (nodeOrUri instanceof vscode.Uri && !filesystemSchemas.includes(nodeOrUri.scheme))) {
-    return;
-  }
+  if (!nodeOrUri || (nodeOrUri instanceof vscode.Uri && notIsfs(nodeOrUri))) return;
   const studioActions = new StudioActions(nodeOrUri);
   if (studioActions) {
     if (await studioActions.isSourceControlEnabled()) {
diff --git a/src/commands/studioMigration.ts b/src/commands/studioMigration.ts
index 31c8bfa8..3527e15f 100644
--- a/src/commands/studioMigration.ts
+++ b/src/commands/studioMigration.ts
@@ -3,8 +3,8 @@ import cmd = require("node-cmd");
 import util = require("util");
 import { gte } from "semver";
 
-import { fileExists, outputChannel } from "../utils";
-import { clsLangId, cspLangId, incLangId, intLangId, macLangId } from "../extension";
+import { fileExists, handleError } from "../utils";
+import { clsLangId, cspLangId, incLangId, intLangId, lsExtensionId, macLangId } from "../extension";
 
 /** Run a command using `node-cmd` and return a Promise */
 const runCmd = util.promisify(cmd.run);
@@ -117,8 +117,8 @@ export async function loadStudioSnippets(): Promise<void> {
                       parts[1] == "5"
                         ? cspLangId
                         : parts[1] == "3"
-                        ? clsLangId
-                        : `${macLangId},${intLangId},${incLangId},${clsLangId},${cspLangId}`,
+                          ? clsLangId
+                          : `${macLangId},${intLangId},${incLangId},${clsLangId},${cspLangId}`,
                   };
                 }
               });
@@ -155,15 +155,7 @@ export async function loadStudioSnippets(): Promise<void> {
           vscode.window.showInformationMessage(uriOrReason, "Dismiss");
         }
       },
-      (error) => {
-        outputChannel.appendLine(
-          typeof error == "string" ? error : error instanceof Error ? error.message : JSON.stringify(error)
-        );
-        vscode.window.showErrorMessage(
-          "An error occurred while loading Studio snippets. Check 'ObjectScript' Output channel for details.",
-          "Dismiss"
-        );
-      }
+      (error) => handleError(error, "An error occurred while loading Studio snippets.")
     );
 }
 
@@ -183,7 +175,7 @@ export async function loadStudioColors(languageServerExt: vscode.Extension<any>
   // Check that the Language Server is installed
   if (!languageServerExt) {
     vscode.window.showErrorMessage(
-      "Loading Studio syntax colors requires the [InterSystems Language Server extension](https://marketplace.visualstudio.com/items?itemName=${extId}).",
+      `Loading Studio syntax colors requires the [InterSystems Language Server extension](https://marketplace.visualstudio.com/items?itemName=${lsExtensionId}).`,
       "Dismiss"
     );
     return;
@@ -359,14 +351,6 @@ export async function loadStudioColors(languageServerExt: vscode.Extension<any>
             }
           });
       },
-      (error) => {
-        outputChannel.appendLine(
-          typeof error == "string" ? error : error instanceof Error ? error.message : JSON.stringify(error)
-        );
-        vscode.window.showErrorMessage(
-          "An error occurred while loading Studio syntax colors. Check 'ObjectScript' Output channel for details.",
-          "Dismiss"
-        );
-      }
+      (error) => handleError(error, "An error occurred while loading Studio syntax colors.")
     );
 }
diff --git a/src/commands/superclass.ts b/src/commands/superclass.ts
index 4ea92082..b7b279d4 100644
--- a/src/commands/superclass.ts
+++ b/src/commands/superclass.ts
@@ -1,15 +1,12 @@
 import * as vscode from "vscode";
 import { config } from "../extension";
 import { DocumentContentProvider } from "../providers/DocumentContentProvider";
-import { currentFile } from "../utils";
+import { currentFile, notIsfs } from "../utils";
 import { ClassDefinition } from "../utils/classDefinition";
 
 export async function superclass(): Promise<void> {
   const file = currentFile();
-  if (file.uri.scheme === "file" && !config("conn").active) {
-    return;
-  }
-  if (!file || !file.name.toLowerCase().endsWith(".cls")) {
+  if (!file || !file.name.toLowerCase().endsWith(".cls") || (notIsfs(file.uri) && !config("conn").active)) {
     return;
   }
 
diff --git a/src/commands/unitTest.ts b/src/commands/unitTest.ts
index dccceab4..7a8b61a3 100644
--- a/src/commands/unitTest.ts
+++ b/src/commands/unitTest.ts
@@ -1,7 +1,14 @@
 import * as vscode from "vscode";
 import * as Atelier from "../api/atelier";
 import { clsLangId, extensionId, filesystemSchemas, lsExtensionId } from "../extension";
-import { getFileText, methodOffsetToLine, outputChannel, stripClassMemberNameQuotes, uriIsParentOf } from "../utils";
+import {
+  getFileText,
+  handleError,
+  methodOffsetToLine,
+  notIsfs,
+  stripClassMemberNameQuotes,
+  uriIsParentOf,
+} from "../utils";
 import { fileSpecFromURI } from "../utils/FileProviderUtil";
 import { AtelierAPI } from "../api";
 import { DocumentContentProvider } from "../providers/DocumentContentProvider";
@@ -51,18 +58,6 @@ const methodIdSeparator = "\\\\\\";
 
 const textDecoder = new TextDecoder();
 
-/** Write the string represenation of `error` to `outputChannel` and show it */
-function outputErrorAsString(error: any): void {
-  if (error && error.errorText && error.errorText !== "") {
-    outputChannel.appendLine(error.errorText);
-  } else {
-    outputChannel.appendLine(
-      typeof error == "string" ? error : error instanceof Error ? error.message : JSON.stringify(error)
-    );
-  }
-  outputChannel.show(true);
-}
-
 /** Find the root `TestItem` for `uri` */
 function rootItemForItem(testController: vscode.TestController, uri: vscode.Uri): vscode.TestItem | undefined {
   let rootItem: vscode.TestItem;
@@ -175,44 +170,43 @@ function createRootItemsForWorkspaceFolder(
   folder: vscode.WorkspaceFolder
 ): vscode.TestItem[] {
   let newItems: vscode.TestItem[] = [];
-  if ([...filesystemSchemas, "file"].includes(folder.uri.scheme)) {
-    const api = new AtelierAPI(folder.uri);
-    // Must have an active server connection to a non-%SYS namespace and Atelier API version 8 or above
-    const errorMsg =
-      !api.active || api.ns == ""
-        ? "Server connection is inactive"
-        : api.ns == "%SYS"
+  const api = new AtelierAPI(folder.uri);
+  // Must have an active server connection to a non-%SYS namespace and Atelier API version 8 or above
+  const errorMsg =
+    !api.active || api.ns == ""
+      ? "Server connection is inactive"
+      : api.ns == "%SYS"
         ? "Connected to the %SYS namespace"
         : api.config.apiVersion < 8
-        ? "Must be connected to InterSystems IRIS version 2023.3 or above"
-        : folder.uri.scheme != "file" && ["", "1"].includes(new URLSearchParams(folder.uri.query).get("csp"))
-        ? "Web application folder"
-        : undefined;
-    let itemUris: vscode.Uri[];
-    if (folder.uri.scheme == "file") {
-      const roots = relativeTestRootsForUri(folder.uri);
-      const baseUri = folder.uri.with({ path: `${folder.uri.path}${!folder.uri.path.endsWith("/") ? "/" : ""}` });
-      itemUris = roots.map((root) => baseUri.with({ path: `${baseUri.path}${root}` }));
+          ? "Must be connected to InterSystems IRIS version 2023.3 or above"
+          : filesystemSchemas.includes(folder.uri.scheme) &&
+              ["", "1"].includes(new URLSearchParams(folder.uri.query).get("csp"))
+            ? "Web application folder"
+            : undefined;
+  let itemUris: vscode.Uri[];
+  if (notIsfs(folder.uri)) {
+    const roots = relativeTestRootsForUri(folder.uri);
+    const baseUri = folder.uri.with({ path: `${folder.uri.path}${!folder.uri.path.endsWith("/") ? "/" : ""}` });
+    itemUris = roots.map((root) => baseUri.with({ path: `${baseUri.path}${root}` }));
+  } else {
+    itemUris = [folder.uri];
+  }
+  newItems = itemUris.map((uri) => {
+    const newItem = testController.createTestItem(uri.toString(), folder.name, uri);
+    if (notIsfs(uri)) {
+      // Add the root as the description
+      newItem.description = uri.path.slice(folder.uri.path.length + (!folder.uri.path.endsWith("/") ? 1 : 0));
+      newItem.sortText = newItem.label + newItem.description;
+    }
+    if (errorMsg != undefined) {
+      // Show the user why we can't run tests from this folder
+      newItem.canResolveChildren = false;
+      newItem.error = errorMsg;
     } else {
-      itemUris = [folder.uri];
+      newItem.canResolveChildren = true;
     }
-    newItems = itemUris.map((uri) => {
-      const newItem = testController.createTestItem(uri.toString(), folder.name, uri);
-      if (uri.scheme == "file") {
-        // Add the root as the description
-        newItem.description = uri.path.slice(folder.uri.path.length + (!folder.uri.path.endsWith("/") ? 1 : 0));
-        newItem.sortText = newItem.label + newItem.description;
-      }
-      if (errorMsg != undefined) {
-        // Show the user why we can't run tests from this folder
-        newItem.canResolveChildren = false;
-        newItem.error = errorMsg;
-      } else {
-        newItem.canResolveChildren = true;
-      }
-      return newItem;
-    });
-  }
+    return newItem;
+  });
   return newItems;
 }
 
@@ -439,7 +433,7 @@ async function runHandler(
     const autoloadFolder: string = autoload.get("folder");
     const autoloadXml: boolean = autoload.get("xml");
     const autoloadUdl: boolean = autoload.get("udl");
-    const autoloadEnabled: boolean = autoloadFolder != "" && (autoloadXml || autoloadUdl) && root.uri.scheme == "file";
+    const autoloadEnabled: boolean = autoloadFolder != "" && (autoloadXml || autoloadUdl) && notIsfs(root.uri);
     const autoloadProcessed: string[] = [];
 
     // Process every test that was queued
@@ -517,7 +511,7 @@ async function runHandler(
                 class: cls,
                 methods: [test.label],
               });
-              if (test.parent.uri.scheme == "file") {
+              if (notIsfs(test.parent.uri)) {
                 // Add this class to the list to load
                 if (asyncRequest.load == undefined) asyncRequest.load = [];
                 asyncRequest.load.push({
@@ -554,7 +548,7 @@ async function runHandler(
                 delete clsObj.methods;
               }
             }
-            if (test.uri.scheme == "file") {
+            if (notIsfs(test.uri)) {
               // Add this class to the list to load
               if (asyncRequest.load == undefined) asyncRequest.load = [];
               asyncRequest.load.push({
@@ -576,11 +570,7 @@ async function runHandler(
       return;
     }
   } catch (error) {
-    outputErrorAsString(error);
-    vscode.window.showErrorMessage(
-      `Error determining tests to ${action}. Check 'ObjectScript' output channel for details.`,
-      "Dismiss"
-    );
+    handleError(error, `Error determining tests to ${action}.`);
     return;
   }
 
@@ -595,11 +585,7 @@ async function runHandler(
   // Send the queue request
   const api = new AtelierAPI(root.uri);
   const queueResp: Atelier.Response<any> = await api.queueAsync(asyncRequest, true).catch((error) => {
-    outputErrorAsString(error);
-    vscode.window.showErrorMessage(
-      `Error creating job to ${action} tests. Check 'ObjectScript' output channel for details.`,
-      "Dismiss"
-    );
+    handleError(error, `Error creating job to ${action} tests.`);
     return undefined;
   });
   if (!queueResp) return;
@@ -738,10 +724,9 @@ async function runHandler(
                             if (locationUri) {
                               if (!documentSymbols.has(locationUri.toString())) {
                                 const newSymbols = await vscode.commands
-                                  .executeCommand<vscode.DocumentSymbol[]>(
-                                    "vscode.executeDocumentSymbolProvider",
-                                    locationUri
-                                  )
+                                  .executeCommand<
+                                    vscode.DocumentSymbol[]
+                                  >("vscode.executeDocumentSymbolProvider", locationUri)
                                   .then(
                                     (r) => r[0]?.children,
                                     () => undefined
@@ -921,11 +906,7 @@ async function runHandler(
     };
     await processUnitTestResults();
   } catch (error) {
-    outputErrorAsString(error);
-    vscode.window.showErrorMessage(
-      `Error ${action}${debug ? "g" : "n"}ing tests. Check 'ObjectScript' output channel for details.`,
-      "Dismiss"
-    );
+    handleError(error, `Error ${action}${debug ? "g" : "n"}ing tests.`);
   }
   testRun.end();
 }
@@ -951,7 +932,7 @@ export function setUpTestController(): vscode.Disposable[] {
         // Compute items for the Test* methods in this class
         await addTestItemsForClass(testController, item);
       } else {
-        if (item.uri.scheme == "file") {
+        if (notIsfs(item.uri)) {
           // Read the local directory for non-autoload subdirectories and classes
           const autoload = vscode.workspace.getConfiguration("objectscript.unitTest.autoload", item.uri);
           const autoloadFolder: string = autoload.get("folder");
@@ -975,9 +956,9 @@ export function setUpTestController(): vscode.Disposable[] {
         }
       }
     } catch (error) {
-      outputErrorAsString(error);
+      handleError(error);
       item.error = new vscode.MarkdownString(
-        "Error fetching children. Check `ObjectScript` output channel for details."
+        "Error fetching children. Check the `ObjectScript` Output channel for details."
       );
     }
     item.busy = false;
@@ -1096,7 +1077,7 @@ export function setUpTestController(): vscode.Disposable[] {
       const replace: vscode.TestItem[] = [];
       testController.items.forEach((item) => {
         if (
-          (item.uri.scheme == "file" && e.affectsConfiguration("objectscript.unitTest", item.uri)) ||
+          (notIsfs(item.uri) && e.affectsConfiguration("objectscript.unitTest", item.uri)) ||
           e.affectsConfiguration("objectscript.conn", item.uri) ||
           e.affectsConfiguration("intersystems.servers", item.uri)
         ) {
diff --git a/src/commands/viewOthers.ts b/src/commands/viewOthers.ts
index 555f1299..5a759896 100644
--- a/src/commands/viewOthers.ts
+++ b/src/commands/viewOthers.ts
@@ -1,17 +1,11 @@
 import * as vscode from "vscode";
 import { AtelierAPI } from "../api";
-import { config } from "../extension";
 import { DocumentContentProvider } from "../providers/DocumentContentProvider";
-import { currentFile, outputChannel } from "../utils";
+import { currentFile, handleError } from "../utils";
 
 export async function viewOthers(forceEditable = false): Promise<void> {
   const file = currentFile();
-  if (!file) {
-    return;
-  }
-  if (file.uri.scheme === "file" && !config("conn").active) {
-    return;
-  }
+  if (!file) return;
 
   const open = async (item: string, forceEditable: boolean) => {
     const colonidx: number = item.indexOf(":");
@@ -103,6 +97,7 @@ export async function viewOthers(forceEditable = false): Promise<void> {
   };
 
   const api = new AtelierAPI(file.uri);
+  if (!api.active) return;
   let indexarg: string = file.name;
   const cursorpos: vscode.Position = vscode.window.activeTextEditor.selection.active;
   const fileExt: string = file.name.split(".").pop().toLowerCase();
@@ -197,22 +192,5 @@ export async function viewOthers(forceEditable = false): Promise<void> {
         });
       }
     })
-    .catch((err) => {
-      if (err.errorText && err.errorText !== "") {
-        outputChannel.appendLine("\n" + err.errorText);
-        vscode.window
-          .showErrorMessage(
-            `Failed to get other documents. Check 'ObjectScript' output channel for details.`,
-            "Show",
-            "Dismiss"
-          )
-          .then((action) => {
-            if (action === "Show") {
-              outputChannel.show(true);
-            }
-          });
-      } else {
-        vscode.window.showErrorMessage(`Failed to get other documents.`, "Dismiss");
-      }
-    });
+    .catch((error) => handleError(error, "Failed to get other documents."));
 }
diff --git a/src/commands/webSocketTerminal.ts b/src/commands/webSocketTerminal.ts
index ff138793..5bacbbad 100644
--- a/src/commands/webSocketTerminal.ts
+++ b/src/commands/webSocketTerminal.ts
@@ -2,7 +2,7 @@ import * as vscode from "vscode";
 import WebSocket = require("ws");
 
 import { AtelierAPI } from "../api";
-import { connectionTarget, currentFile, outputChannel } from "../utils";
+import { connectionTarget, currentFile, handleError, notIsfs, outputChannel } from "../utils";
 import { config, iscIcon, resolveConnectionSpec } from "../extension";
 
 const keys = {
@@ -167,15 +167,8 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
         },
       });
     } catch (error) {
-      outputChannel.appendLine(
-        typeof error == "string" ? error : error instanceof Error ? error.message : JSON.stringify(error)
-      );
+      handleError(error, "Failed to initialize WebSocket Terminal.");
       outputChannel.appendLine("Check that the InterSystems server's web server supports WebSockets.");
-      outputChannel.show(true);
-      vscode.window.showErrorMessage(
-        "Failed to initialize WebSocket Terminal. Check 'ObjectScript' Output channel for details.",
-        "Dismiss"
-      );
       this._closeEmitter.fire();
       return;
     }
@@ -187,12 +180,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
     this._socket
       .on("error", (error) => {
         // Log the error and close
-        outputChannel.appendLine(`WebSocket error: ${error.toString()}`);
-        outputChannel.show(true);
-        vscode.window.showErrorMessage(
-          "WebSocket Terminal failed. Check 'ObjectScript' Output channel for details.",
-          "Dismiss"
-        );
+        handleError(`WebSocket error: ${error.toString()}`, "WebSocket Terminal failed.");
         this._closeEmitter.fire();
       })
       .on("close", () => {
@@ -209,12 +197,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
         switch (message.type) {
           case "error":
             // Log the error and close
-            outputChannel.appendLine(message.text);
-            outputChannel.show(true);
-            vscode.window.showErrorMessage(
-              "WebSocket Terminal failed. Check 'ObjectScript' Output channel for details.",
-              "Dismiss"
-            );
+            handleError(message.text, "WebSocket Terminal failed.");
             this._closeEmitter.fire();
             break;
           case "output":
@@ -661,10 +644,10 @@ async function workspaceUriForTerminal(throwErrors = false) {
 export async function launchWebSocketTerminal(targetUri?: vscode.Uri): Promise<void> {
   // Determine the server to connect to
   if (targetUri) {
-    // Uri passed as command argument might be for a server we haven't yet resolve connection details such as password,
-    // so make sure that happens now if needed
+    // Uri passed as command argument might be for a server we haven't yet resolved
+    // connection details such as password, so make sure that happens now if needed
     const { configName } = connectionTarget(targetUri);
-    const serverName = targetUri.scheme === "file" ? config("conn", configName).server : configName;
+    const serverName = notIsfs(targetUri) ? config("conn", configName).server : configName;
     await resolveConnectionSpec(serverName);
   } else {
     targetUri = currentFile()?.uri;
diff --git a/src/commands/xmlToUdl.ts b/src/commands/xmlToUdl.ts
index 07d18406..058fe086 100644
--- a/src/commands/xmlToUdl.ts
+++ b/src/commands/xmlToUdl.ts
@@ -1,7 +1,8 @@
 import * as vscode from "vscode";
-import { config, filesystemSchemas, OBJECTSCRIPTXML_FILE_SCHEMA, xmlContentProvider } from "../extension";
+import path = require("path");
+import { config, OBJECTSCRIPTXML_FILE_SCHEMA, xmlContentProvider } from "../extension";
 import { AtelierAPI } from "../api";
-import { fileExists, outputChannel } from "../utils";
+import { fileExists, handleError, notIsfs, outputChannel } from "../utils";
 import { getFileName } from "./export";
 
 const exportHeader = /^\s*<Export generator="(Cache|IRIS)" version="\d+"/;
@@ -9,11 +10,7 @@ const exportHeader = /^\s*<Export generator="(Cache|IRIS)" version="\d+"/;
 export async function previewXMLAsUDL(textEditor: vscode.TextEditor, auto = false): Promise<void> {
   const uri = textEditor.document.uri;
   const content = textEditor.document.getText();
-  if (
-    !filesystemSchemas.includes(uri.scheme) &&
-    uri.path.toLowerCase().endsWith("xml") &&
-    textEditor.document.lineCount > 2
-  ) {
+  if (notIsfs(uri) && uri.path.toLowerCase().endsWith("xml") && textEditor.document.lineCount > 2) {
     if (exportHeader.test(textEditor.document.lineAt(1).text)) {
       const api = new AtelierAPI(uri);
       if (!api.active) return;
@@ -75,13 +72,7 @@ export async function previewXMLAsUDL(textEditor: vscode.TextEditor, auto = fals
         // Remove the UDL text from the content provider's cache
         xmlContentProvider.removeUdlDocsForFile(uri.toString());
       } catch (error) {
-        let errorMsg = "Error executing 'Preview XML as UDL' command.";
-        if (error && error.errorText && error.errorText !== "") {
-          outputChannel.appendLine("\n" + error.errorText);
-          outputChannel.show(true);
-          errorMsg += " Check 'ObjectScript' output channel for details.";
-        }
-        vscode.window.showErrorMessage(errorMsg, "Dismiss");
+        handleError(error, "Error executing 'Preview XML as UDL' command.");
       }
     } else if (!auto) {
       vscode.window.showErrorMessage(`XML file '${uri.toString(true)}' is not an InterSystems export.`, "Dismiss");
@@ -94,11 +85,7 @@ export async function extractXMLFileContents(xmlUri?: vscode.Uri): Promise<void>
   if (!xmlUri && vscode.window.activeTextEditor) {
     // Check if the active text editor contains an XML file
     const activeDoc = vscode.window.activeTextEditor.document;
-    if (
-      !filesystemSchemas.includes(activeDoc.uri.scheme) &&
-      activeDoc.uri.path.toLowerCase().endsWith("xml") &&
-      activeDoc.lineCount > 2
-    ) {
+    if (notIsfs(activeDoc.uri) && activeDoc.uri.path.toLowerCase().endsWith("xml") && activeDoc.lineCount > 2) {
       // The active text editor contains an XML file, so process it
       xmlUri = activeDoc.uri;
     }
@@ -110,9 +97,7 @@ export async function extractXMLFileContents(xmlUri?: vscode.Uri): Promise<void>
       wsFolder = vscode.workspace.getWorkspaceFolder(xmlUri);
     } else {
       // Can only run this command on non-isfs folders with an active server connection
-      const options = vscode.workspace.workspaceFolders.filter(
-        (f) => !filesystemSchemas.includes(f.uri.scheme) && new AtelierAPI(f.uri).active
-      );
+      const options = vscode.workspace.workspaceFolders.filter((f) => notIsfs(f.uri) && new AtelierAPI(f.uri).active);
       if (options.length == 0) {
         vscode.window.showErrorMessage(
           "'Extract Documents from XML File...' command requires a non-isfs workspace folder with an active server connection.",
@@ -195,7 +180,8 @@ export async function extractXMLFileContents(xmlUri?: vscode.Uri): Promise<void>
     const docWhitelist = docsToExtract.map((d) => d.label);
     // Write the UDL files
     const { atelier, folder, addCategory, map } = config("export", wsFolder.name);
-    const rootFolder = wsFolder.uri.path + (typeof folder == "string" && folder.length ? `/${folder}` : "");
+    const rootFolder =
+      wsFolder.uri.path + (typeof folder == "string" && folder.length ? `/${folder.replaceAll(path.sep, "/")}` : "");
     const textEncoder = new TextEncoder();
     let errs = 0;
     for (const udlDoc of udlDocs) {
@@ -210,24 +196,18 @@ export async function extractXMLFileContents(xmlUri?: vscode.Uri): Promise<void>
         await vscode.workspace.fs.writeFile(fileUri, textEncoder.encode(udlDoc.content.join("\n")));
       } catch (error) {
         outputChannel.appendLine(
-          typeof error == "string" ? error : error instanceof Error ? error.message : JSON.stringify(error)
+          typeof error == "string" ? error : error instanceof Error ? error.toString() : JSON.stringify(error)
         );
         errs++;
       }
     }
     if (errs) {
       vscode.window.showErrorMessage(
-        `Failed to write ${errs} file${errs > 1 ? "s" : ""}. Check 'ObjectScript' output channel for details.`,
+        `Failed to write ${errs} file${errs > 1 ? "s" : ""}. Check the 'ObjectScript' Output channel for details.`,
         "Dismiss"
       );
     }
   } catch (error) {
-    let errorMsg = "Error executing 'Extract Documents from XML File...' command.";
-    if (error && error.errorText && error.errorText !== "") {
-      outputChannel.appendLine("\n" + error.errorText);
-      outputChannel.show(true);
-      errorMsg += " Check 'ObjectScript' output channel for details.";
-    }
-    vscode.window.showErrorMessage(errorMsg, "Dismiss");
+    handleError(error, "Error executing 'Extract Documents from XML File...' command.");
   }
 }
diff --git a/src/explorer/explorer.ts b/src/explorer/explorer.ts
index 6835d296..0b10d9e6 100644
--- a/src/explorer/explorer.ts
+++ b/src/explorer/explorer.ts
@@ -4,7 +4,7 @@ import { NodeBase } from "./models/nodeBase";
 import { AtelierAPI } from "../api";
 import { config, documentContentProvider, OBJECTSCRIPT_FILE_SCHEMA, projectsExplorerProvider } from "../extension";
 import { WorkspaceNode } from "./models/workspaceNode";
-import { outputChannel } from "../utils";
+import { handleError, notIsfs } from "../utils";
 import { DocumentContentProvider } from "../providers/DocumentContentProvider";
 import { StudioActions, OtherStudioAction } from "../commands/studio";
 
@@ -12,7 +12,7 @@ import { StudioActions, OtherStudioAction } from "../commands/studio";
 export function getLeafNodeUri(node: NodeBase, forceServerCopy = false): vscode.Uri {
   if (node.workspaceFolder == undefined) {
     // Should only be the case for leaf nodes in the projects explorer
-    // that are children of an extra server namepsace node
+    // that are children of an extra server namespace node
     return DocumentContentProvider.getUri(
       node.fullName,
       undefined,
@@ -108,10 +108,10 @@ export function registerExplorerOpen(): vscode.Disposable {
               const prjType = prjFileName.includes("/")
                 ? "CSP"
                 : ext == "cls"
-                ? "CLS"
-                : ["mac", "int", "inc"].includes(ext)
-                ? "MAC"
-                : "OTH";
+                  ? "CLS"
+                  : ["mac", "int", "inc"].includes(ext)
+                    ? "MAC"
+                    : "OTH";
               if (prjType == "OTH") {
                 await api.actionQuery(
                   "DELETE FROM %Studio.ProjectItem WHERE Project = ? AND Name = ? AND Type NOT IN ('CLS','PKG','MAC','CSP','DIR','GBL')",
@@ -130,23 +130,15 @@ export function registerExplorerOpen(): vscode.Disposable {
                   // Swallow error because VS Code doesn't care about the timestamp
                 });
             } catch (error) {
-              let message = `Failed to remove '${fullName}' from project '${project}'.`;
-              if (error && error.errorText && error.errorText !== "") {
-                outputChannel.appendLine("\n" + error.errorText);
-                outputChannel.show(true);
-                message += " Check 'ObjectScript' output channel for details.";
-              }
-              return vscode.window.showErrorMessage(message, "Dismiss");
+              handleError(error, `Failed to remove '${fullName}' from project '${project}'.`);
+              return;
             }
 
             // Refresh the explorer
             projectsExplorerProvider.refresh();
           }
         } else {
-          outputChannel.appendLine(
-            typeof error == "string" ? error : error instanceof Error ? error.message : JSON.stringify(error)
-          );
-          outputChannel.show();
+          handleError(error);
         }
       }
     }
@@ -238,7 +230,7 @@ export class ObjectScriptExplorerProvider implements vscode.TreeDataProvider<Nod
 
     const workspaceFolders = vscode.workspace.workspaceFolders || [];
     workspaceFolders
-      .filter((workspaceFolder) => workspaceFolder.uri && workspaceFolder.uri.scheme === "file")
+      .filter((workspaceFolder) => workspaceFolder.uri && notIsfs(workspaceFolder.uri))
       .forEach((workspaceFolder) => {
         const conn: any = config("conn", workspaceFolder.name);
         if (conn.active && conn.ns) {
diff --git a/src/explorer/models/classNode.ts b/src/explorer/models/classNode.ts
index 33a55f7e..d842cbd3 100644
--- a/src/explorer/models/classNode.ts
+++ b/src/explorer/models/classNode.ts
@@ -2,6 +2,7 @@ import * as vscode from "vscode";
 import { NodeBase, NodeOptions } from "./nodeBase";
 import { config } from "../../extension";
 import { getLeafNodeUri } from "../explorer";
+import { notIsfs } from "../../utils";
 
 export class ClassNode extends NodeBase {
   public static readonly contextValue: string = "dataNode:classNode";
@@ -12,7 +13,7 @@ export class ClassNode extends NodeBase {
   public getTreeItem(): vscode.TreeItem {
     const displayName: string = this.label;
     const itemUri = getLeafNodeUri(this);
-    const isLocalFile = itemUri.scheme === "file";
+    const isLocalFile = notIsfs(itemUri);
     const showServerCopy: boolean = config("explorer.alwaysShowServerCopy", this.workspaceFolder);
     const serverCopyUri = getLeafNodeUri(this, true);
 
diff --git a/src/explorer/models/cspFileNode.ts b/src/explorer/models/cspFileNode.ts
index 5fb5d858..b8993894 100644
--- a/src/explorer/models/cspFileNode.ts
+++ b/src/explorer/models/cspFileNode.ts
@@ -2,6 +2,7 @@ import * as vscode from "vscode";
 import { NodeBase, NodeOptions } from "./nodeBase";
 import { config } from "../../extension";
 import { getLeafNodeUri } from "../explorer";
+import { notIsfs } from "../../utils";
 
 export class CSPFileNode extends NodeBase {
   public static readonly contextValue: string = "dataNode:cspFileNode";
@@ -12,7 +13,7 @@ export class CSPFileNode extends NodeBase {
   public getTreeItem(): vscode.TreeItem {
     const displayName: string = this.label;
     const itemUri = getLeafNodeUri(this);
-    const isLocalFile = itemUri.scheme === "file";
+    const isLocalFile = notIsfs(itemUri);
     const showServerCopy: boolean = config("explorer.alwaysShowServerCopy", this.workspaceFolder);
     const serverCopyUri = getLeafNodeUri(this, true);
 
diff --git a/src/explorer/models/packageNode.ts b/src/explorer/models/packageNode.ts
index b8898aa9..2145dc84 100644
--- a/src/explorer/models/packageNode.ts
+++ b/src/explorer/models/packageNode.ts
@@ -1,8 +1,6 @@
 import * as vscode from "vscode";
 import { RootNode } from "./rootNode";
 import { NodeOptions } from "./nodeBase";
-import { DocumentContentProvider } from "../../providers/DocumentContentProvider";
-import { config } from "../../extension";
 
 export class PackageNode extends RootNode {
   public constructor(label: string, fullName: string, category: string, options: NodeOptions) {
@@ -11,13 +9,9 @@ export class PackageNode extends RootNode {
 
   public getTreeItem(): vscode.TreeItem {
     const displayName: string = this.label;
-    const localFolderPath = DocumentContentProvider.getAsFolder(this.fullName, this.workspaceFolder, "cls");
-    const localUri = localFolderPath ? vscode.Uri.file(localFolderPath) : undefined;
-    const showServerCopy: boolean = config("explorer.alwaysShowServerCopy", this.workspaceFolder);
 
     return {
       collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
-      resourceUri: !this.extraNode && !showServerCopy ? localUri : undefined,
       contextValue: this.contextValue,
       label: `${displayName}`,
       tooltip: this.fullName,
diff --git a/src/explorer/models/rootNode.ts b/src/explorer/models/rootNode.ts
index a74771bc..37d3a500 100644
--- a/src/explorer/models/rootNode.ts
+++ b/src/explorer/models/rootNode.ts
@@ -70,7 +70,7 @@ export class RootNode extends NodeBase {
         spec = "*.cls";
         break;
       case "RTN":
-        spec = "*.mac,*.int,*.bas";
+        spec = "*.mac,*.int,*.bas,*.mvb,*.mvi";
         break;
       case "INC":
         spec = "*.inc";
@@ -82,7 +82,7 @@ export class RootNode extends NodeBase {
         spec = "*";
         break;
       case "OTH":
-        spec = "*.other";
+        spec = "*.other,'*.bpl,'*.dtl";
         break;
       default:
         return;
diff --git a/src/explorer/models/routineNode.ts b/src/explorer/models/routineNode.ts
index 755f4c31..28622619 100644
--- a/src/explorer/models/routineNode.ts
+++ b/src/explorer/models/routineNode.ts
@@ -2,6 +2,7 @@ import * as vscode from "vscode";
 import { NodeBase, NodeOptions } from "./nodeBase";
 import { config } from "../../extension";
 import { getLeafNodeUri } from "../explorer";
+import { notIsfs } from "../../utils";
 
 export class RoutineNode extends NodeBase {
   public static readonly contextValue: string = "dataNode:routineNode";
@@ -12,7 +13,7 @@ export class RoutineNode extends NodeBase {
   public getTreeItem(): vscode.TreeItem {
     const displayName: string = this.label;
     const itemUri = getLeafNodeUri(this);
-    const isLocalFile = itemUri.scheme === "file";
+    const isLocalFile = notIsfs(itemUri);
     const showServerCopy: boolean = config("explorer.alwaysShowServerCopy", this.workspaceFolder);
     const serverCopyUri = getLeafNodeUri(this, true);
 
diff --git a/src/explorer/projectsExplorer.ts b/src/explorer/projectsExplorer.ts
index fda7df54..1fb36df9 100644
--- a/src/explorer/projectsExplorer.ts
+++ b/src/explorer/projectsExplorer.ts
@@ -2,6 +2,7 @@ import * as vscode from "vscode";
 import { AtelierAPI } from "../api";
 import { NodeBase } from "./models/nodeBase";
 import { ProjectsServerNsNode } from "./models/projectsServerNsNode";
+import { notIsfs } from "../utils";
 
 export class ProjectsExplorerProvider implements vscode.TreeDataProvider<NodeBase> {
   public onDidChangeTreeData: vscode.Event<NodeBase>;
@@ -67,17 +68,19 @@ export class ProjectsExplorerProvider implements vscode.TreeDataProvider<NodeBas
     const workspaceFolders = vscode.workspace.workspaceFolders || [];
     const alreadyAdded: string[] = [];
     // Add the workspace root nodes
-    workspaceFolders.forEach((workspaceFolder) => {
-      const conn = new AtelierAPI(workspaceFolder.uri).config;
-      if (conn.active && conn.ns) {
-        node = new ProjectsServerNsNode(workspaceFolder.name, this._onDidChangeTreeData, workspaceFolder.uri);
-        const label = <string>node.getTreeItem().label;
-        if (!alreadyAdded.includes(label)) {
-          alreadyAdded.push(label);
-          rootNodes.push(node);
+    workspaceFolders
+      .filter((workspaceFolder) => workspaceFolder.uri && !notIsfs(workspaceFolder.uri))
+      .forEach((workspaceFolder) => {
+        const conn = new AtelierAPI(workspaceFolder.uri).config;
+        if (conn.active && conn.ns) {
+          node = new ProjectsServerNsNode(workspaceFolder.name, this._onDidChangeTreeData, workspaceFolder.uri);
+          const label = <string>node.getTreeItem().label;
+          if (!alreadyAdded.includes(label)) {
+            alreadyAdded.push(label);
+            rootNodes.push(node);
+          }
         }
-      }
-    });
+      });
     // Add the extra root nodes
     this._extraRoots.forEach((authority) => {
       node = new ProjectsServerNsNode(
diff --git a/src/extension.ts b/src/extension.ts
index 0163e90f..ce5912e8 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -98,9 +98,10 @@ import {
   workspaceFolderOfUri,
   uriOfWorkspaceFolder,
   isUnauthenticated,
+  notIsfs,
+  handleError,
 } from "./utils";
 import { ObjectScriptDiagnosticProvider } from "./providers/ObjectScriptDiagnosticProvider";
-import { DocumentRangeFormattingEditProvider } from "./providers/DocumentRangeFormattingEditProvider";
 import { DocumentLinkProvider } from "./providers/DocumentLinkProvider";
 
 /* proposed */
@@ -140,6 +141,12 @@ import { modifyWsFolder } from "./commands/addServerNamespaceToWorkspace";
 import { WebSocketTerminalProfileProvider, launchWebSocketTerminal } from "./commands/webSocketTerminal";
 import { setUpTestController } from "./commands/unitTest";
 import { pickDocument } from "./utils/documentPicker";
+import {
+  disposeDocumentIndex,
+  indexWorkspaceFolder,
+  removeIndexOfWorkspaceFolder,
+  updateIndexForDocument,
+} from "./utils/documentIndex";
 
 const packageJson = vscode.extensions.getExtension(extensionId).packageJSON;
 const extensionVersion = packageJson.version;
@@ -256,6 +263,13 @@ export function getResolvedConnectionSpec(key: string, dflt: any): any {
  */
 export const cspApps: Map<string, string[]> = new Map();
 
+/**
+ * A map of all Studio Abstract Document extensions in a server-namespace.
+ * The key is either `serverName:ns`, or `host:port/pathPrefix:ns`, lowercase.
+ * The value is lowercase array of file extensions, without the dot.
+ */
+export const otherDocExts: Map<string, string[]> = new Map();
+
 export async function checkConnection(
   clearCookies = false,
   uri?: vscode.Uri,
@@ -307,7 +321,7 @@ export async function checkConnection(
       if (withDocker) {
         if (!dockerPort) {
           const errorMessage = `Something is wrong with your docker-compose connection settings, or your service is not running.`;
-          outputChannel.appendError(errorMessage);
+          handleError(errorMessage);
           panel.text = `${PANEL_LABEL} $(error)`;
           panel.tooltip = `ERROR - ${errorMessage}`;
           return;
@@ -322,7 +336,7 @@ export async function checkConnection(
         _onDidChangeConnection.fire();
       }
     } catch (error) {
-      outputChannel.appendError(error);
+      handleError(error);
       workspaceState.update(wsKey + ":docker", true);
       panel.text = `${PANEL_LABEL} $(error)`;
       panel.tooltip = error;
@@ -339,7 +353,7 @@ export async function checkConnection(
 
   if (!api.config.host || !api.config.port || !api.config.ns) {
     const message = "'host', 'port' and 'ns' must be specified.";
-    outputChannel.appendError(message);
+    handleError(message);
     panel.text = `${PANEL_LABEL} $(error)`;
     panel.tooltip = `ERROR - ${message}`;
     if (!api.externalServer) {
@@ -373,6 +387,15 @@ export async function checkConnection(
     if (!cspApps.has(key)) {
       cspApps.set(key, await api.getCSPApps().then((data) => data.result.content || []));
     }
+    if (!otherDocExts.has(key)) {
+      otherDocExts.set(
+        key,
+        await api
+          .actionQuery("SELECT Extension FROM %Library.RoutineMgr_DocumentTypes()", [])
+          .then((data) => data.result?.content?.map((e) => e.Extension) ?? [])
+          .catch(() => [])
+      );
+    }
     if (!api.externalServer) {
       await setConnectionState(configName, true);
     }
@@ -481,7 +504,7 @@ export async function checkConnection(
       } else {
         errorMessage = `${message}\nCheck your server details in Settings (${connInfo}).`;
       }
-      outputChannel.appendError(errorMessage);
+      handleError(errorMessage);
       panel.text = `${connInfo} $(error)`;
       panel.tooltip = `ERROR - ${message}`;
       throw error;
@@ -626,6 +649,27 @@ async function systemModeWarning(wsFolders: readonly vscode.WorkspaceFolder[]):
   }
 }
 
+/**
+ * Set when clause context keys so the ObjectScript Explorer and
+ * Projects Explorer views are correctly shown or hidden depending
+ * on the folders in this workspace
+ */
+function setExplorerContextKeys(): void {
+  const wsFolders = vscode.workspace.workspaceFolders ?? [];
+  // Need to show both views if there are no folders in
+  // this workspace so the "viewsWelcome" messages are shown
+  vscode.commands.executeCommand(
+    "setContext",
+    "vscode-objectscript.showExplorer",
+    wsFolders.length == 0 || wsFolders.some((wf) => notIsfs(wf.uri))
+  );
+  vscode.commands.executeCommand(
+    "setContext",
+    "vscode-objectscript.showProjectsExplorer",
+    wsFolders.length == 0 || wsFolders.some((wf) => filesystemSchemas.includes(wf.uri.scheme))
+  );
+}
+
 /** The URIs of all classes that have been opened. Used when `objectscript.openClassContracted` is true */
 let openedClasses: string[];
 
@@ -687,13 +731,16 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
 
   const debugAdapterFactory = new ObjectScriptDebugAdapterDescriptorFactory();
 
+  // Show or hide explorer views as needed
+  setExplorerContextKeys();
+
   // Check one time (flushing cookies) each connection that is used by the workspace.
   // This gets any prompting for missing credentials done upfront, for simplicity.
   const toCheck = new Map<string, vscode.Uri>();
   vscode.workspace.workspaceFolders?.map((workspaceFolder) => {
     const uri = workspaceFolder.uri;
     const { configName } = connectionTarget(uri);
-    const serverName = uri.scheme === "file" ? config("conn", configName).server : configName;
+    const serverName = notIsfs(uri) ? config("conn", configName).server : configName;
     toCheck.set(serverName, uri);
   });
   for await (const oneToCheck of toCheck) {
@@ -775,10 +822,6 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
         documentSelector(clsLangId, macLangId, intLangId, incLangId),
         new DocumentFormattingEditProvider()
       ),
-      vscode.languages.registerDocumentRangeFormattingEditProvider(
-        documentSelector(clsLangId, macLangId, intLangId, incLangId),
-        new DocumentRangeFormattingEditProvider()
-      ),
       vscode.languages.registerDefinitionProvider(
         documentSelector(clsLangId, macLangId, intLangId, incLangId),
         new ObjectScriptDefinitionProvider()
@@ -831,6 +874,9 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
 
   iscIcon = vscode.Uri.joinPath(context.extensionUri, "images", "fileIcon.svg");
 
+  // Index documents in all local workspace folders
+  for (const wf of vscode.workspace.workspaceFolders ?? []) indexWorkspaceFolder(wf);
+
   macLangConf = vscode.languages.setLanguageConfiguration(macLangId, getLanguageConfiguration(macLangId));
   incLangConf = vscode.languages.setLanguageConfiguration(incLangId, getLanguageConfiguration(incLangId));
   intLangConf = vscode.languages.setLanguageConfiguration(intLangId, getLanguageConfiguration(intLangId));
@@ -860,6 +906,13 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
       if (!event.document.isDirty) {
         checkChangedOnServer(currentFile(event.document));
       }
+      if (
+        [clsLangId, macLangId, intLangId, incLangId].includes(event.document.languageId) &&
+        notIsfs(event.document.uri)
+      ) {
+        // Update the local workspace folder index to incorporate this change
+        updateIndexForDocument(event.document.uri);
+      }
     }),
     vscode.window.onDidChangeActiveTextEditor(async (editor) => {
       if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 1) {
@@ -881,21 +934,14 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
     vscode.commands.registerCommand("vscode-objectscript.compileAllWithFlags", () => namespaceCompile(true)),
     vscode.commands.registerCommand("vscode-objectscript.refreshLocalFile", async () => {
       const file = currentFile();
-      if (!file) {
-        return;
-      }
-
+      if (!file) return;
       try {
         await loadChanges([file]);
       } catch (error) {
-        let message = `Failed to overwrite file from server '${file.fileName}'.`;
-        if (error && error.errorText && error.errorText !== "") {
-          outputChannel.appendLine("\n" + error.errorText);
-          outputChannel.show(true);
-          message += " Check 'ObjectScript' output channel for details.";
-        }
-        vscode.window.showErrorMessage(message, "Dismiss");
-        return;
+        handleError(
+          error,
+          `Failed to overwrite contents of file '${file.uri.toString(true)}' with server copy of '${file.fileName}'.`
+        );
       }
     }),
     vscode.commands.registerCommand("vscode-objectscript.compileFolder", (_file, files) =>
@@ -937,8 +983,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
       const api = new AtelierAPI(vscode.window.activeTextEditor?.document.uri);
 
       const list = await api.getJobs(system).then(async (jobData) => {
-        // NOTE: We do not know if the current user has permissions to other namespaces
-        // so lets only fetch the job info for the current namespace
+        // We do not know if the current user has permissions in other namespaces,
+        // so only fetch the job info for the current namespace
         const currNamespaceJobs: { [k: string]: string } = await api
           .actionQuery("SELECT Job, ConfigName FROM Ens.Job_Enumerate() WHERE State = 'Alive'", [])
           .then((data) => Object.fromEntries(data.result.content.map((x) => [x.Job, x.ConfigName])))
@@ -1045,17 +1091,6 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
     vscode.commands.registerCommand("vscode-objectscript.connectFolderToServerNamespace", () => {
       connectFolderToServerNamespace();
     }),
-    vscode.commands.registerCommand("vscode-objectscript.hideExplorerForWorkspace", () => {
-      vscode.workspace
-        .getConfiguration("objectscript")
-        .update("showExplorer", false, vscode.ConfigurationTarget.Workspace);
-    }),
-    vscode.commands.registerCommand("vscode-objectscript.showExplorerForWorkspace", () => {
-      vscode.workspace
-        .getConfiguration("objectscript")
-        .update("showExplorer", true, vscode.ConfigurationTarget.Workspace);
-    }),
-
     vscode.workspace.registerTextDocumentContentProvider(OBJECTSCRIPT_FILE_SCHEMA, documentContentProvider),
     vscode.workspace.registerTextDocumentContentProvider(OBJECTSCRIPTXML_FILE_SCHEMA, xmlContentProvider),
     vscode.workspace.registerFileSystemProvider(FILESYSTEM_SCHEMA, fileSystemProvider, {
@@ -1093,7 +1128,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
       if (!config("autoAdjustName")) return;
       return Promise.all(
         e.files
-          .filter((uri) => !filesystemSchemas.includes(uri.scheme))
+          .filter(notIsfs)
           .filter((uri) => ["cls", "inc", "int", "mac"].includes(uri.path.split(".").pop().toLowerCase()))
           .map(async (uri) => {
             // Determine the file name
@@ -1180,9 +1215,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
       },
       supportsMultipleEditorsPerDocument: false,
     }),
-    vscode.workspace.onDidChangeWorkspaceFolders(async ({ added, removed }) => {
-      const folders = vscode.workspace.workspaceFolders;
-
+    vscode.workspace.onDidChangeWorkspaceFolders(async ({ added }) => {
       // Make sure we have a resolved connection spec for the targets of all added folders
       const toCheck = new Map<string, vscode.Uri>();
       added.map((workspaceFolder) => {
@@ -1193,21 +1226,9 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
       for await (const oneToCheck of toCheck) {
         const configName = oneToCheck[0];
         const uri = oneToCheck[1];
-        const serverName = uri.scheme === "file" ? config("conn", configName).server : configName;
+        const serverName = notIsfs(uri) ? config("conn", configName).server : configName;
         await resolveConnectionSpec(serverName);
       }
-
-      // If it was just the addition of the first folder, and this is one of the isfs types, hide the ObjectScript Explorer for this workspace
-      if (
-        folders?.length === 1 &&
-        added?.length === 1 &&
-        removed?.length === 0 &&
-        filesystemSchemas.includes(added[0].uri.scheme)
-      ) {
-        vscode.workspace
-          .getConfiguration("objectscript")
-          .update("showExplorer", false, vscode.ConfigurationTarget.Workspace);
-      }
     }),
     vscode.workspace.onDidChangeConfiguration(async ({ affectsConfiguration }) => {
       if (affectsConfiguration("objectscript.conn") || affectsConfiguration("intersystems.servers")) {
@@ -1265,16 +1286,17 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
         // Saving is handled by a different event listener
         return;
       }
-      if (!schemas.includes(file.uri.scheme) && !config("importOnSave")) {
+      const conf = vscode.workspace.getConfiguration("objectscript", file.uri);
+      if (notIsfs(file.uri) && !conf.get("importOnSave")) {
         // Don't save this local file on the server
         return;
       }
       if (schemas.includes(file.uri.scheme) || languages.includes(file.languageId)) {
         if (documentBeingProcessed !== file) {
-          return importAndCompile(false, file, config("compileOnSave"));
+          return importAndCompile(false, file, conf.get("compileOnSave"));
         }
-      } else if (file.uri.scheme === "file") {
-        if (isImportableLocalFile(file) && new AtelierAPI(file.uri).active) {
+      } else if (notIsfs(file.uri)) {
+        if (isImportableLocalFile(file.uri) && new AtelierAPI(file.uri).active) {
           // This local file is part of a CSP application
           // or matches our export settings, so import it on save
           return importFileOrFolder(file.uri, true);
@@ -1377,6 +1399,11 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
       proposedApiPrompt(proposed.length > 0, e.added);
       // Warn about SystemMode
       systemModeWarning(e.added);
+      // Update the local workspace folder index
+      for (const a of e.added) indexWorkspaceFolder(a);
+      for (const r of e.removed) removeIndexOfWorkspaceFolder(r);
+      // Show or hide explorer views as needed
+      setExplorerContextKeys();
     }),
     vscode.commands.registerCommand("vscode-objectscript.importXMLFiles", importXMLFiles),
     vscode.commands.registerCommand("vscode-objectscript.exportToXMLFile", exportDocumentsToXMLFile),
@@ -1521,4 +1548,5 @@ export function deactivate(): void {
   macLangConf?.dispose();
   incLangConf?.dispose();
   intLangConf?.dispose();
+  disposeDocumentIndex();
 }
diff --git a/src/languageConfiguration.ts b/src/languageConfiguration.ts
index e41aef61..93b9513f 100644
--- a/src/languageConfiguration.ts
+++ b/src/languageConfiguration.ts
@@ -14,8 +14,8 @@ export function getLanguageConfiguration(lang: string): vscode.LanguageConfigura
         lang == "objectscript-class"
           ? "//"
           : ["objectscript", "objectscript-macros"].includes(lang)
-          ? conf.get("commentToken")
-          : conf.get("intCommentToken"),
+            ? conf.get("commentToken")
+            : conf.get("intCommentToken"),
       blockComment: ["/*", "*/"],
     },
     autoClosingPairs: [
diff --git a/src/providers/DocumentContentProvider.ts b/src/providers/DocumentContentProvider.ts
index 07910d30..27fd7f4e 100644
--- a/src/providers/DocumentContentProvider.ts
+++ b/src/providers/DocumentContentProvider.ts
@@ -3,9 +3,10 @@ import * as path from "path";
 import * as vscode from "vscode";
 import { AtelierAPI } from "../api";
 
-import { getFileName, getFolderName } from "../commands/export";
+import { getFileName } from "../commands/export";
 import { config, FILESYSTEM_SCHEMA, FILESYSTEM_READONLY_SCHEMA, OBJECTSCRIPT_FILE_SCHEMA } from "../extension";
-import { currentWorkspaceFolder, uriOfWorkspaceFolder } from "../utils";
+import { currentWorkspaceFolder, notIsfs, uriOfWorkspaceFolder } from "../utils";
+import { getUrisForDocument } from "../utils/documentIndex";
 
 export function compareConns(
   conn1: { ns: any; server: any; host: any; port: any },
@@ -30,29 +31,73 @@ export class DocumentContentProvider implements vscode.TextDocumentContentProvid
     return this.onDidChangeEvent.event;
   }
 
-  public static getAsFile(name: string, workspaceFolder: string): string {
-    const { atelier, folder, addCategory, map } = config("export", workspaceFolder);
-
-    if (!workspaceFolder) {
-      return;
-    }
-    const root = [uriOfWorkspaceFolder(workspaceFolder).fsPath, folder].join(path.sep);
-    const fileName = getFileName(root, name, atelier, addCategory, map);
-    if (fs.existsSync(fileName)) {
-      return fs.realpathSync.native(fileName);
-    }
-  }
-
-  public static getAsFolder(name: string, workspaceFolder: string, category?: string): string {
-    const { atelier, folder, addCategory } = config("export", workspaceFolder);
-
-    if (!workspaceFolder) {
-      return;
-    }
-    const root = [uriOfWorkspaceFolder(workspaceFolder).fsPath, folder].join(path.sep);
-    const folderName = getFolderName(root, name, atelier, addCategory ? category : null);
-    if (fs.existsSync(folderName)) {
-      return fs.realpathSync.native(folderName);
+  /** Returns the `Uri` of `name` in `workspaceFolder` if it exists */
+  private static findLocalUri(name: string, workspaceFolder: string): vscode.Uri {
+    if (!workspaceFolder) return;
+    const wsFolder = vscode.workspace.workspaceFolders.find((wf) => wf.name == workspaceFolder);
+    if (!wsFolder) return;
+    if (!notIsfs(wsFolder.uri)) return;
+    const conf = vscode.workspace.getConfiguration("objectscript.export", wsFolder);
+    const confFolder = conf.get("folder", "");
+    if (["cls", "mac", "int", "inc"].includes(name.split(".").pop().toLowerCase())) {
+      // Use the document index to find the local URI
+      const uris = getUrisForDocument(name, wsFolder);
+      switch (uris.length) {
+        case 0:
+          // Document doesn't exist in a file
+          return;
+        case 1:
+          // Document exists in exactly one file
+          return uris[0];
+        default: {
+          // Document exists in multiple files, so try to "break the tie" by
+          // finding the URI that's "closest" to a point of reference
+          let referenceUriParts: string[];
+          if (
+            vscode.window.activeTextEditor &&
+            vscode.workspace.getWorkspaceFolder(vscode.window.activeTextEditor.document.uri)?.uri.toString() ==
+              wsFolder.uri.toString()
+          ) {
+            // Use the active editor's document for comparison
+            const base = vscode.window.activeTextEditor.document.uri.path.slice(wsFolder.uri.path.length);
+            referenceUriParts = base.split("/").slice(base.startsWith("/") ? 1 : 0, -1);
+          } else {
+            // Use the export settings for comparison
+            const base = getFileName(confFolder, name, conf.get("atelier"), conf.get("addCategory"), conf.get("map"));
+            referenceUriParts = base.split(path.sep).slice(base.startsWith(path.sep) ? 1 : 0, -1);
+          }
+          return uris.sort((a, b) => {
+            const aParts = a.path.split("/").slice(0, -1);
+            const bParts = b.path.split("/").slice(0, -1);
+            let aSame = 0,
+              bSame = 0,
+              aDone = false,
+              bDone = false;
+            for (let i = 0; i < referenceUriParts.length; i++) {
+              if (!aDone && aParts[i] != referenceUriParts[i]) aDone = true;
+              if (!bDone && bParts[i] != referenceUriParts[i]) bDone = true;
+              if (aDone && bDone) break;
+              if (!aDone) aSame++;
+              if (!bDone) bSame++;
+            }
+            if (aSame == bSame) {
+              return aParts.slice(aSame).length - bParts.slice(bSame).length;
+            } else {
+              return bSame - aSame;
+            }
+          })[0];
+        }
+      }
+    } else if (wsFolder.uri.scheme == "file") {
+      // Fall back to our old mechanism which only works for "file" scheme
+      const fileName = getFileName(
+        wsFolder.uri.fsPath + (confFolder.length ? path.sep + confFolder : ""),
+        name,
+        conf.get("atelier"),
+        conf.get("addCategory"),
+        conf.get("map")
+      );
+      if (fs.existsSync(fileName)) return vscode.Uri.file(fileName);
     }
   }
 
@@ -71,6 +116,11 @@ export class DocumentContentProvider implements vscode.TextDocumentContentProvid
     if (!wFolderUri) {
       workspaceFolder = workspaceFolder && workspaceFolder !== "" ? workspaceFolder : currentWorkspaceFolder();
       wFolderUri = uriOfWorkspaceFolder(workspaceFolder);
+    } else if (!workspaceFolder) {
+      // Make sure workspaceFolder is set correctly if only wFolderUri was passed
+      workspaceFolder = vscode.workspace.workspaceFolders.find(
+        (wf) => wf.uri.toString() == wFolderUri.toString()
+      )?.name;
     }
     let uri: vscode.Uri;
     if (wFolderUri && (wFolderUri.scheme === FILESYSTEM_SCHEMA || wFolderUri.scheme === FILESYSTEM_READONLY_SCHEMA)) {
@@ -111,11 +161,11 @@ export class DocumentContentProvider implements vscode.TextDocumentContentProvid
       const conn = config("conn", workspaceFolder);
       if (!forceServerCopy) {
         // Look for the document in the local file system
-        const localFile = this.getAsFile(name, workspaceFolder);
+        const localFile = this.findLocalUri(name, workspaceFolder);
         if (localFile && (!namespace || namespace === conn.ns)) {
           // Exists as a local file and we aren't viewing a different namespace on the same server,
-          // so return a file:// uri that will open the local file.
-          return vscode.Uri.file(localFile);
+          // so return a uri that will open the local file.
+          return localFile;
         } else {
           // The local file doesn't exist in this folder, so check any other
           // local folders in this workspace if it's a multi-root workspace
@@ -123,15 +173,13 @@ export class DocumentContentProvider implements vscode.TextDocumentContentProvid
           if (wFolders && wFolders.length > 1) {
             // This is a multi-root workspace
             for (const wFolder of wFolders) {
-              if (wFolder.uri.scheme === "file" && wFolder.name !== workspaceFolder) {
+              if (notIsfs(wFolder.uri) && wFolder.name != workspaceFolder) {
                 // This isn't the folder that we checked originally
                 const wFolderConn = config("conn", wFolder.name);
                 if (compareConns(conn, wFolderConn) && (!namespace || namespace === wFolderConn.ns)) {
                   // This folder is connected to the same server:ns combination as the original folder
-                  const wFolderFile = this.getAsFile(name, wFolder.name);
-                  if (wFolderFile) {
-                    return vscode.Uri.file(wFolderFile);
-                  }
+                  const wFolderFile = this.findLocalUri(name, wFolder.name);
+                  if (wFolderFile) return wFolderFile;
                 }
               }
             }
diff --git a/src/providers/DocumentRangeFormattingEditProvider.ts b/src/providers/DocumentRangeFormattingEditProvider.ts
deleted file mode 100644
index 99ad59c3..00000000
--- a/src/providers/DocumentRangeFormattingEditProvider.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import * as vscode from "vscode";
-
-export class DocumentRangeFormattingEditProvider implements vscode.DocumentRangeFormattingEditProvider {
-  public provideDocumentRangeFormattingEdits(
-    document: vscode.TextDocument,
-    range: vscode.Range,
-    options: vscode.FormattingOptions,
-    token: vscode.CancellationToken
-  ): vscode.ProviderResult<vscode.TextEdit[]> {
-    return null;
-  }
-}
diff --git a/src/providers/FileSystemProvider/FileSystemProvider.ts b/src/providers/FileSystemProvider/FileSystemProvider.ts
index a9a8ed55..60db9577 100644
--- a/src/providers/FileSystemProvider/FileSystemProvider.ts
+++ b/src/providers/FileSystemProvider/FileSystemProvider.ts
@@ -8,10 +8,13 @@ import { projectContentsFromUri, studioOpenDialogFromURI } from "../../utils/Fil
 import {
   classNameRegex,
   isClassDeployed,
+  notIsfs,
   notNull,
   outputChannel,
+  handleError,
   redirectDotvscodeRoot,
   workspaceFolderOfUri,
+  stringifyError,
 } from "../../utils/index";
 import {
   config,
@@ -43,7 +46,7 @@ export function generateFileContent(
     const preamble: string[] = [];
 
     if (sourceLines.length) {
-      if (uri.scheme == "file" && (fileName.includes(path.sep) || fileName.includes(" "))) {
+      if (notIsfs(uri) && (fileName.includes(path.sep) || fileName.includes(" "))) {
         // We couldn't resolve a class name from the file path,
         // so keep the source text unchanged.
         content = sourceLines;
@@ -75,7 +78,7 @@ export function generateFileContent(
       enc: false,
     };
   } else if (["int", "inc", "mac"].includes(fileExt) && !csp) {
-    if (sourceLines.length && uri.scheme == "file" && (fileName.includes(path.sep) || fileName.includes(" "))) {
+    if (sourceLines.length && notIsfs(uri) && (fileName.includes(path.sep) || fileName.includes(" "))) {
       // We couldn't resolve a routine name from the file path,
       // so keep the source text unchanged.
       return {
@@ -269,10 +272,10 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
               const folder = !csp
                 ? uri.path.replace(/\/$/, "").replace(/\//g, ".")
                 : uri.path === "/"
-                ? ""
-                : uri.path.endsWith("/")
-                ? uri.path
-                : uri.path + "/";
+                  ? ""
+                  : uri.path.endsWith("/")
+                    ? uri.path
+                    : uri.path + "/";
               const fullName = folder === "" ? entry.Name : csp ? folder + entry.Name : folder + "/" + entry.Name;
               parent.entries.set(entry.Name, new Directory(entry.Name, fullName));
             }
@@ -298,10 +301,10 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
     const folder = !csp
       ? uri.path.replace(/\/$/, "").replace(/\//g, ".")
       : uri.path === "/"
-      ? ""
-      : uri.path.endsWith("/")
-      ? uri.path
-      : uri.path + "/";
+        ? ""
+        : uri.path.endsWith("/")
+          ? uri.path
+          : uri.path + "/";
     // get all web apps that have a filepath (Studio dialog used below returns REST ones too)
     const cspApps = csp ? await api.getCSPApps().then((data) => data.result.content || []) : [];
     const cspSubfolderMap = new Map<string, vscode.FileType>();
@@ -323,10 +326,10 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
             item.Type == 10
               ? csp && !item.Name.includes("/") // ignore web apps here because there may be REST ones
               : item.Type == 9 // class package
-              ? !csp
-              : csp
-              ? item.Type == 5 // web app file
-              : true
+                ? !csp
+                : csp
+                  ? item.Type == 5 // web app file
+                  : true
           )
           .map((item: { Name: string; Type: number }) => {
             const name = item.Name;
@@ -355,15 +358,13 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
       })
       .catch((error) => {
         if (error) {
-          console.log(error);
           if (error.errorText.includes(" #5540:")) {
-            const nsUpper = api.config.ns.toUpperCase();
             const message = `User '${api.config.username}' cannot list ${
               csp ? `web application '${uri.path}'` : "namespace"
-            } contents. If they do not have READ permission on the default code database of the ${nsUpper} namespace then grant it and retry. If the problem remains then execute the following SQL in that namespace:\n\t GRANT EXECUTE ON %Library.RoutineMgr_StudioOpenDialog TO ${
+            } contents. If they do not have READ permission on the default code database of the ${api.config.ns.toUpperCase()} namespace then grant it and retry. If the problem remains then execute the following SQL in that namespace:\n\t GRANT EXECUTE ON %Library.RoutineMgr_StudioOpenDialog TO ${
               api.config.username
             }`;
-            outputChannel.appendError(message);
+            handleError(message);
           }
         }
       });
@@ -466,10 +467,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
           )
           .catch((error) => {
             // Throw all failures
-            if (error && error.errorText && error.errorText !== "") {
-              throw vscode.FileSystemError.Unavailable(error.errorText);
-            }
-            throw vscode.FileSystemError.Unavailable(uri);
+            throw vscode.FileSystemError.Unavailable(stringifyError(error) || uri);
           })
           .then(async (response) => {
             // New file has been written
@@ -607,7 +605,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
           throw new vscode.FileSystemError(
             `Failed to delete ${failed} document${
               failed > 1 ? "s" : ""
-            }. Check 'ObjectScript' Output channel for details.`
+            }. Check the 'ObjectScript' Output channel for details.`
           );
         }
       });
@@ -621,13 +619,10 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
         }
       },
       (error) => {
-        let message = `Failed to delete file '${fileName}'.`;
-        if (error && error.errorText && error.errorText !== "") {
-          outputChannel.appendLine("\n" + error.errorText);
-          outputChannel.show(true);
-          message += " Check 'ObjectScript' Output channel for details.";
-        }
-        throw new vscode.FileSystemError(message);
+        handleError(error);
+        throw new vscode.FileSystemError(
+          `Failed to delete file '${fileName}'. Check the 'ObjectScript' Output channel for details.`
+        );
       }
     );
   }
@@ -684,10 +679,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
       )
       .catch((error) => {
         // Throw all failures
-        if (error && error.errorText && error.errorText !== "") {
-          throw vscode.FileSystemError.Unavailable(error.errorText);
-        }
-        throw vscode.FileSystemError.Unavailable(error.message);
+        throw vscode.FileSystemError.Unavailable(stringifyError(error) || newUri);
       })
       .then(async (response) => {
         // New file has been written
@@ -734,14 +726,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
         compileList.push(isCSPFile(uri) ? uri.path : uri.path.slice(1).replace(/\//g, "."));
       }
     } catch (error) {
-      console.log(error);
-      let errorMsg = "Error determining documents to compile.";
-      if (error && error.errorText && error.errorText !== "") {
-        outputChannel.appendLine("\n" + error.errorText);
-        outputChannel.show(true);
-        errorMsg += " Check 'ObjectScript' output channel for details.";
-      }
-      vscode.window.showErrorMessage(errorMsg, "Dismiss");
+      handleError(error, "Error determining documents to compile.");
       return;
     }
     if (!compileList.length) return;
@@ -769,7 +754,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
             if (!conf.get("suppressCompileErrorMessages")) {
               vscode.window
                 .showErrorMessage(
-                  "Compilation failed. Check 'ObjectScript' output channel for details.",
+                  "Compilation failed. Check 'ObjectScript' Output channel for details.",
                   "Show",
                   "Dismiss"
                 )
@@ -827,10 +812,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
         .serverInfo()
         .then()
         .catch((error) => {
-          if (error && error.errorText && error.errorText !== "") {
-            throw vscode.FileSystemError.Unavailable(error.errorText);
-          }
-          throw vscode.FileSystemError.Unavailable(uri);
+          throw vscode.FileSystemError.Unavailable(stringifyError(error) || uri);
         });
     }
     const config = api.config;
@@ -938,13 +920,8 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
         })
       )
       .catch((error) => {
-        if (error?.statusCode === 304 && cachedFile) {
-          return cachedFile;
-        }
-        if (error && error.errorText && error.errorText !== "") {
-          throw vscode.FileSystemError.FileNotFound(error.errorText);
-        }
-        throw vscode.FileSystemError.FileNotFound(uri);
+        if (error?.statusCode == 304 && cachedFile) return cachedFile;
+        throw vscode.FileSystemError.FileNotFound(stringifyError(error) || uri);
       });
   }
 
diff --git a/src/providers/FileSystemProvider/TextSearchProvider.ts b/src/providers/FileSystemProvider/TextSearchProvider.ts
index ff61554b..8c59f670 100644
--- a/src/providers/FileSystemProvider/TextSearchProvider.ts
+++ b/src/providers/FileSystemProvider/TextSearchProvider.ts
@@ -3,7 +3,7 @@ import { makeRe } from "minimatch";
 import { AsyncSearchRequest, SearchResult, SearchMatch } from "../../api/atelier";
 import { AtelierAPI } from "../../api";
 import { DocumentContentProvider } from "../DocumentContentProvider";
-import { notNull, outputChannel, throttleRequests } from "../../utils";
+import { handleError, notNull, outputChannel, throttleRequests } from "../../utils";
 import { config } from "../../extension";
 import { fileSpecFromURI } from "../../utils/FileProviderUtil";
 
@@ -183,22 +183,11 @@ function searchMatchToLine(
 /**
  * Handle errors produced during the retrieving of search results.
  */
-function handleSearchError(error): vscode.TextSearchComplete {
-  let message = "An error occurred during the search.";
-  if (error.errorText && error.errorText !== "") {
-    outputChannel.appendLine("\n" + error.errorText);
-    message += " Check `ObjectScript` Output channel for details.";
-  } else {
-    try {
-      outputChannel.appendLine(typeof error == "object" ? JSON.stringify(error) : String(error));
-      message += " Check `ObjectScript` Output channel for details.";
-    } catch {
-      // Ignore a JSON stringify failure
-    }
-  }
+function handleSearchError(error: any): vscode.TextSearchComplete {
+  handleError(error);
   return {
     message: {
-      text: message,
+      text: "An error occurred during the search. Check the `ObjectScript` Output channel for details.",
       type: vscode.TextSearchCompleteMessageType.Warning,
     },
   };
@@ -232,7 +221,7 @@ async function processSearchResults(
     message = {
       text: `Failed to display results from ${rejected} file${
         rejected > 1 ? "s" : ""
-      }. Check \`ObjectScript\` Output channel for details.`,
+      }. Check the \`ObjectScript\` Output channel for details.`,
       type: vscode.TextSearchCompleteMessageType.Warning,
     };
   }
@@ -607,8 +596,8 @@ export class TextSearchProvider implements vscode.TextSearchProvider {
             options.includes.length > 0
               ? convertFilters(options.includes).join(",")
               : filterExclude
-              ? fileSpecFromURI(uri) // Excludes were specified but no includes, so start with the default includes (this step makes type=cls|rtn effective)
-              : "";
+                ? fileSpecFromURI(uri) // Excludes were specified but no includes, so start with the default includes (this step makes type=cls|rtn effective)
+                : "";
           const filter = filterInclude + (!filterExclude ? "" : ",'" + filterExclude);
           if (filter) {
             // Unless isfs is serving CSP files, slash separators in filters must be converted to dot ones before sending to server
diff --git a/src/providers/ObjectScriptClassSymbolProvider.ts b/src/providers/ObjectScriptClassSymbolProvider.ts
index ca83fc3a..cb2c5bf4 100644
--- a/src/providers/ObjectScriptClassSymbolProvider.ts
+++ b/src/providers/ObjectScriptClassSymbolProvider.ts
@@ -5,7 +5,6 @@ export class ObjectScriptClassSymbolProvider implements vscode.DocumentSymbolPro
     document: vscode.TextDocument,
     token: vscode.CancellationToken
   ): Thenable<vscode.DocumentSymbol[]> {
-    // tslint:disable-next-line:cyclomatic-complexity
     return new Promise((resolve) => {
       let classItSelf = null;
       let symbols: vscode.DocumentSymbol[] = [];
diff --git a/src/providers/ObjectScriptCompletionItemProvider.ts b/src/providers/ObjectScriptCompletionItemProvider.ts
index 3b6e8fce..670001a7 100644
--- a/src/providers/ObjectScriptCompletionItemProvider.ts
+++ b/src/providers/ObjectScriptCompletionItemProvider.ts
@@ -340,7 +340,6 @@ export class ObjectScriptCompletionItemProvider implements vscode.CompletionItem
       text = range ? document.getText(range) : "";
       className = text.split(" ").pop();
     }
-    // tslint:disable-next-line: max-line-length
     pattern =
       /(?:(Extends |CompileAfter *=|DependsOn *=|PropertyClass *=) *\(? *)((%?[a-zA-Z0-9]*(?:\.[a-zA-Z0-9]*)*)(, *%?[a-zA-Z0-9]*(?:\.[a-zA-Z0-9]*)*|, *)*.?)?/i;
     if (
diff --git a/src/providers/RuleEditorProvider.ts b/src/providers/RuleEditorProvider.ts
index 96750452..f7172e3f 100644
--- a/src/providers/RuleEditorProvider.ts
+++ b/src/providers/RuleEditorProvider.ts
@@ -3,7 +3,7 @@ import { AtelierAPI } from "../api";
 import { loadChanges } from "../commands/compile";
 import { StudioActions } from "../commands/studio";
 import { clsLangId, cspApps } from "../extension";
-import { currentFile, outputChannel } from "../utils";
+import { currentFile, handleError, outputChannel } from "../utils";
 
 /**
  * The URI strings for all documents that are open in a custom editor.
@@ -263,25 +263,15 @@ export class RuleEditorProvider implements vscode.CustomTextEditorProvider {
                         type: "revert",
                       });
                     }
-                    if (actionToProcess.errorText !== "") {
+                    if (actionToProcess.errorText != "") {
                       outputChannel.appendLine(
                         `\nError executing AfterUserAction '${event.label}':\n${actionToProcess.errorText}`
                       );
-                      outputChannel.show();
+                      outputChannel.show(true);
                     }
                   }
                 })
-                .catch((error) => {
-                  outputChannel.appendLine(`\nError executing AfterUserAction '${event.label}':`);
-                  if (error && error.errorText && error.errorText !== "") {
-                    outputChannel.appendLine(error.errorText);
-                  } else {
-                    outputChannel.appendLine(
-                      typeof error == "string" ? error : error instanceof Error ? error.message : JSON.stringify(error)
-                    );
-                  }
-                  outputChannel.show();
-                });
+                .catch((error) => handleError(error, `Error executing AfterUserAction '${event.label}'.`));
             }
           });
           return;
diff --git a/src/providers/WorkspaceSymbolProvider.ts b/src/providers/WorkspaceSymbolProvider.ts
index 824434a5..379d47ee 100644
--- a/src/providers/WorkspaceSymbolProvider.ts
+++ b/src/providers/WorkspaceSymbolProvider.ts
@@ -3,6 +3,8 @@ import { AtelierAPI } from "../api";
 import { DocumentContentProvider } from "./DocumentContentProvider";
 import { filesystemSchemas } from "../extension";
 import { fileSpecFromURI } from "../utils/FileProviderUtil";
+import { allDocumentsInWorkspace } from "../utils/documentIndex";
+import { handleError } from "../utils";
 
 export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
   private readonly _sqlPrefix: string =
@@ -18,13 +20,13 @@ export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
     " UNION SELECT Name, Parent->ID AS Parent, 'Trigger' AS Type FROM %Dictionary.TriggerDefinition" +
     " UNION SELECT Name, Parent->ID AS Parent, 'Storage' AS Type FROM %Dictionary.StorageDefinition" +
     " UNION SELECT Name, Parent->ID AS Parent, 'Projection' AS Type FROM %Dictionary.ProjectionDefinition" +
-    ") AS mem JOIN ";
+    ") AS mem ";
 
   private readonly _sqlPrj: string =
-    "%Studio.Project_ProjectItemsList(?) AS pil ON mem.Parent = pil.Name AND pil.Type = 'CLS'";
+    "JOIN %Studio.Project_ProjectItemsList(?) AS pil ON mem.Parent = pil.Name AND pil.Type = 'CLS'";
 
   private readonly _sqlDocs: string =
-    "%Library.RoutineMgr_StudioOpenDialog(?,1,1,?,1,0,?,'Type = 4',0,?) AS sod ON mem.Parent = $EXTRACT(sod.Name,1,$LENGTH(sod.Name)-4)";
+    "JOIN %Library.RoutineMgr_StudioOpenDialog(?,1,1,?,1,0,?,'Type = 4',0,?) AS sod ON mem.Parent = $EXTRACT(sod.Name,1,$LENGTH(sod.Name)-4)";
 
   private readonly _sqlSuffix: string = " WHERE LOWER(mem.Name) LIKE ? ESCAPE '\\'";
 
@@ -110,8 +112,8 @@ export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
                 params.has("system") && params.get("system").length
                   ? params.get("system")
                   : api.ns == "%SYS"
-                  ? "1"
-                  : "0",
+                    ? "1"
+                    : "0",
                 params.has("generated") && params.get("generated").length ? params.get("generated") : "0",
                 params.has("mapped") && params.get("mapped") == "0" ? "0" : "1",
                 pattern,
@@ -119,15 +121,29 @@ export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
               .then((data) => (token.isCancellationRequested ? [] : this._queryResultToSymbols(data, wsFolder)));
           }
         } else {
-          // Client-side folders should use the isfs default parameters
+          // Use the document index to determien the classes to search
           const api = new AtelierAPI(wsFolder.uri);
-          if (!api.active || token.isCancellationRequested) return Promise.resolve([]);
+          if (!api.active) return Promise.resolve([]);
+          const docs = allDocumentsInWorkspace(wsFolder).filter((d) => d.endsWith(".cls"));
+          if (!docs.length || token.isCancellationRequested) return Promise.resolve([]);
           return api
-            .actionQuery(`${this._sqlPrefix}${this._sqlDocs}${this._sqlSuffix}`, ["*.cls", "0", "0", "1", pattern])
+            .actionQuery(`${this._sqlPrefix}${this._sqlSuffix} AND mem.Parent %INLIST $LISTFROMSTRING(?)`, [
+              pattern,
+              docs.map((d) => d.slice(0, -4)).join(","),
+            ])
             .then((data) => (token.isCancellationRequested ? [] : this._queryResultToSymbols(data, wsFolder)));
         }
       })
-    ).then((results) => results.flatMap((result) => (result.status == "fulfilled" ? result.value : [])));
+    ).then((results) =>
+      results.flatMap((result) => {
+        if (result.status == "fulfilled") {
+          return result.value;
+        } else {
+          handleError(result.reason);
+          return [];
+        }
+      })
+    );
   }
 
   resolveWorkspaceSymbol(symbol: vscode.SymbolInformation): vscode.ProviderResult<vscode.SymbolInformation> {
diff --git a/src/queries.d.ts b/src/queries.d.ts
deleted file mode 100644
index b5303cea..00000000
--- a/src/queries.d.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export interface StudioOpenDialog {
-  Name: string;
-  IsDirectory: string;
-  Type: string;
-  Size: string;
-  Date: string;
-  Description: string;
-  IconType: string;
-}
diff --git a/src/utils/FileProviderUtil.ts b/src/utils/FileProviderUtil.ts
index e4bad5ce..c08be6c7 100644
--- a/src/utils/FileProviderUtil.ts
+++ b/src/utils/FileProviderUtil.ts
@@ -112,10 +112,10 @@ export function fileSpecFromURI(uri: vscode.Uri): string {
   const folder = !csp
     ? uri.path.replace(/\/$/, "").replace(/\//g, ".")
     : uri.path === "/"
-    ? ""
-    : uri.path.endsWith("/")
-    ? uri.path
-    : uri.path + "/";
+      ? ""
+      : uri.path.endsWith("/")
+        ? uri.path
+        : uri.path + "/";
   // The query filter represents the studio spec to be used,
   // overrides.filter represents the SQL query that will be passed to the server
 
diff --git a/src/utils/documentIndex.ts b/src/utils/documentIndex.ts
new file mode 100644
index 00000000..bd9ce98a
--- /dev/null
+++ b/src/utils/documentIndex.ts
@@ -0,0 +1,208 @@
+import * as vscode from "vscode";
+import { CurrentBinaryFile, CurrentTextFile, currentFileFromContent, handleError, notIsfs, outputChannel } from ".";
+import { AtelierAPI } from "../api";
+import { compile, importFile } from "../commands/compile";
+
+interface WSFolderIndex {
+  /** The `FileSystemWatcher` for this workspace folder */
+  watcher: vscode.FileSystemWatcher;
+  /** Map of InterSystems classes and routines in this workspace to their `Uri`s */
+  documents: Map<string, vscode.Uri[]>;
+  /** Map of stringified `Uri`s to their InterSystems class/routine name */
+  uris: Map<string, string>;
+}
+
+interface WSFolderIndexChange {
+  /** InterSystems document added to the index, if any */
+  added?: CurrentTextFile | CurrentBinaryFile;
+  /** InterSystems document removed from the index, if any */
+  removed?: string;
+}
+
+/** Map of stringified workspace folder `Uri`s to collection of InterSystems classes and routines contained therein */
+const wsFolderIndex: Map<string, WSFolderIndex> = new Map();
+
+/** Glob pattern that matches files we want to index */
+const filePattern = "{**/*.cls,**/*.mac,**/*.int,**/*.inc}";
+
+/** We want decoding errors to be thrown */
+const textDecoder = new TextDecoder("utf-8", { fatal: true });
+
+/** Create index of `wsFolder` and set up a `FileSystemWatcher` to keep the index up to date */
+export async function indexWorkspaceFolder(wsFolder: vscode.WorkspaceFolder): Promise<void> {
+  if (!notIsfs(wsFolder.uri)) return;
+  const pattern = new vscode.RelativePattern(wsFolder, filePattern);
+  const documents: Map<string, vscode.Uri[]> = new Map();
+  const uris: Map<string, string> = new Map();
+  // Index files that currently exist
+  const files = await vscode.workspace.findFiles(pattern);
+  for (const file of files) updateIndexForDocument(file, documents, uris);
+  // Watch for changes that may require an index update
+  const watcher = vscode.workspace.createFileSystemWatcher(pattern);
+  watcher.onDidChange((uri) => updateIndexAndSyncChanges(uri, documents, uris));
+  watcher.onDidCreate((uri) => updateIndexAndSyncChanges(uri, documents, uris));
+  watcher.onDidDelete((uri) => {
+    const change = removeDocumentFromIndex(uri, documents, uris);
+    if (change.removed) {
+      const api = new AtelierAPI(uri);
+      if (!api.active) return;
+      // Delete document on the server
+      api.deleteDoc(change.removed).catch((error) => handleError(error));
+    }
+  });
+  wsFolderIndex.set(wsFolder.uri.toString(), { watcher, documents, uris });
+}
+
+/** Remove the index of `wsFolder` */
+export function removeIndexOfWorkspaceFolder(wsFolder: vscode.WorkspaceFolder): void {
+  const key = wsFolder.uri.toString();
+  const index = wsFolderIndex.get(key);
+  if (!index) return;
+  index.watcher.dispose();
+  wsFolderIndex.delete(key);
+}
+
+/** Update the entries in the index for `uri` */
+export async function updateIndexForDocument(
+  uri: vscode.Uri,
+  documents?: Map<string, vscode.Uri[]>,
+  uris?: Map<string, string>
+): Promise<WSFolderIndexChange> {
+  const result: WSFolderIndexChange = {};
+  const uriString = uri.toString();
+  if (!documents) {
+    const wsFolder = vscode.workspace.getWorkspaceFolder(uri);
+    if (!wsFolder) return result;
+    const index = wsFolderIndex.get(wsFolder.uri.toString());
+    if (!index) return result;
+    documents = index.documents;
+    uris = index.uris;
+  }
+  const documentName = uris.get(uriString);
+  const textDocument = vscode.workspace.textDocuments.find((d) => d.uri.toString() == uriString);
+  let content: string;
+  if (textDocument) {
+    // Get the content from the text document
+    content = textDocument.getText();
+  } else {
+    // Get the content from the file system
+    try {
+      content = textDecoder.decode(await vscode.workspace.fs.readFile(uri));
+    } catch (error) {
+      // Either a vscode.FileSystemError from readFile()
+      // or a TypeError from decode(). Don't log TypeError
+      // since the file may be a non-text file
+      // with a cls, mac, int or inc extension.
+      if (error instanceof vscode.FileSystemError) {
+        outputChannel.appendLine(`Failed to get text contents of '${uri.toString(true)}': ${error.toString()}`);
+      }
+      return result;
+    }
+  }
+  const file = currentFileFromContent(uri, content);
+  if (!file) return result;
+  // This file contains an InterSystems document, so add it to the index
+  if (!documentName || (documentName && documentName != file.name)) {
+    const documentUris = documents.get(file.name) ?? [];
+    if (documentUris.length == 0) result.added = file;
+    documentUris.push(uri);
+    documents.set(file.name, documentUris);
+    uris.set(uriString, file.name);
+    if (documentName) {
+      // Remove the outdated reference
+      const oldDocumentUris = documents.get(documentName);
+      if (!oldDocumentUris) return result;
+      const idx = oldDocumentUris.findIndex((f) => f.toString() == uriString);
+      if (idx == -1) return result;
+      if (documentUris.length > 1) {
+        documentUris.splice(idx, 1);
+        documents.set(documentName, documentUris);
+      } else {
+        documents.delete(documentName);
+        result.removed = documentName;
+      }
+    }
+  }
+  return result;
+}
+
+/** Remove the entries in the index for `uri` */
+function removeDocumentFromIndex(
+  uri: vscode.Uri,
+  documents?: Map<string, vscode.Uri[]>,
+  uris?: Map<string, string>
+): WSFolderIndexChange {
+  const result: WSFolderIndexChange = {};
+  const uriString = uri.toString();
+  if (!documents) {
+    const wsFolder = vscode.workspace.getWorkspaceFolder(uri);
+    if (!wsFolder) return result;
+    const index = wsFolderIndex.get(wsFolder.uri.toString());
+    if (!index) return result;
+    documents = index.documents;
+    uris = index.uris;
+  }
+  const documentName = uris.get(uriString);
+  if (!documentName) return result;
+  // Remove it from the index
+  const documentUris = documents.get(documentName);
+  if (!documentUris) return result;
+  const idx = documentUris.findIndex((f) => f.toString() == uriString);
+  if (idx == -1) return result;
+  if (documentUris.length > 1) {
+    documentUris.splice(idx, 1);
+    documents.set(documentName, documentUris);
+  } else {
+    documents.delete(documentName);
+    result.removed = documentName;
+  }
+  uris.delete(uriString);
+  return result;
+}
+
+/** Update the entries in the index for `uri` and sync any changes with the server */
+async function updateIndexAndSyncChanges(
+  uri: vscode.Uri,
+  documents?: Map<string, vscode.Uri[]>,
+  uris?: Map<string, string>
+): Promise<void> {
+  const change = await updateIndexForDocument(uri, documents, uris);
+  if (!change.added && !change.removed) return;
+  const api = new AtelierAPI(uri);
+  if (!api.active) return;
+  const config = vscode.workspace.getConfiguration("objectscript", uri);
+  if (change.added && config.get("importOnSave")) {
+    // Create the document on the server
+    try {
+      await importFile(change.added);
+      if (config.get("compileOnSave")) await compile([change.added]);
+    } catch (error) {
+      handleError(error);
+    }
+  }
+  if (change.removed) {
+    try {
+      // Delete document on the server
+      await api.deleteDoc(change.removed);
+    } catch (error) {
+      handleError(error);
+    }
+  }
+}
+
+/** Get all `Uri`s for `document` in `wsFolder` */
+export function getUrisForDocument(document: string, wsFolder: vscode.WorkspaceFolder): vscode.Uri[] {
+  const index = wsFolderIndex.get(wsFolder.uri.toString());
+  return index ? index.documents.get(document) ?? [] : [];
+}
+
+/** Clean up all `FileSystemWatcher`s */
+export function disposeDocumentIndex(): void {
+  for (const index of wsFolderIndex.values()) index.watcher.dispose();
+}
+
+/** Get the names of all documents in `wsFolder` */
+export function allDocumentsInWorkspace(wsFolder: vscode.WorkspaceFolder): string[] {
+  const index = wsFolderIndex.get(wsFolder.uri.toString());
+  return index ? Array.from(index.documents.keys()) : [];
+}
diff --git a/src/utils/documentPicker.ts b/src/utils/documentPicker.ts
index 5eac353f..4eba12c5 100644
--- a/src/utils/documentPicker.ts
+++ b/src/utils/documentPicker.ts
@@ -1,6 +1,6 @@
 import * as vscode from "vscode";
 import { AtelierAPI } from "../api";
-import { cspAppsForApi, outputChannel } from ".";
+import { cspAppsForApi, handleError } from ".";
 
 interface DocumentPickerItem extends vscode.QuickPickItem {
   /** The full name of this item, including its parent(s). */
@@ -144,13 +144,7 @@ export async function pickDocuments(api: AtelierAPI, prompt?: string): Promise<s
         })
         .catch((error) => {
           quickPick.hide();
-          let message = `Failed to get namespace contents.`;
-          if (error && error.errorText && error.errorText !== "") {
-            outputChannel.appendLine("\n" + error.errorText);
-            outputChannel.show(true);
-            message += " Check 'ObjectScript' output channel for details.";
-          }
-          vscode.window.showErrorMessage(message, "Dismiss");
+          handleError(error, "Failed to get namespace contents.");
         });
     };
     const expandItem = (itemIdx: number): Promise<void> => {
@@ -177,13 +171,7 @@ export async function pickDocuments(api: AtelierAPI, prompt?: string): Promise<s
         })
         .catch((error) => {
           quickPick.hide();
-          let message = `Failed to get namespace contents.`;
-          if (error && error.errorText && error.errorText !== "") {
-            outputChannel.appendLine("\n" + error.errorText);
-            outputChannel.show(true);
-            message += " Check 'ObjectScript' output channel for details.";
-          }
-          vscode.window.showErrorMessage(message, "Dismiss");
+          handleError(error, "Failed to get namespace contents.");
         });
     };
 
@@ -304,13 +292,7 @@ export async function pickDocuments(api: AtelierAPI, prompt?: string): Promise<s
           .then((data) => data.result.content.map((e) => e.Name))
           .catch((error) => {
             quickPick.hide();
-            let message = `Failed to resolve documents in selected packages or folders.`;
-            if (error && error.errorText && error.errorText !== "") {
-              outputChannel.appendLine("\n" + error.errorText);
-              outputChannel.show(true);
-              message += " Check 'ObjectScript' output channel for details.";
-            }
-            vscode.window.showErrorMessage(message, "Dismiss");
+            handleError(error, "Failed to resolve documents in selected packages or folders.");
           });
         // Remove duplicates
         result = [...new Set(resolved.concat(result.filter((e) => !e.endsWith("*"))))];
@@ -383,13 +365,7 @@ export async function pickDocument(api: AtelierAPI, prompt?: string): Promise<st
         })
         .catch((error) => {
           quickPick.hide();
-          let message = `Failed to get namespace contents.`;
-          if (error && error.errorText && error.errorText !== "") {
-            outputChannel.appendLine("\n" + error.errorText);
-            outputChannel.show(true);
-            message += " Check 'ObjectScript' output channel for details.";
-          }
-          vscode.window.showErrorMessage(message, "Dismiss");
+          handleError(error, "Failed to get namespace contents.");
         });
     };
 
@@ -462,8 +438,8 @@ export async function pickDocument(api: AtelierAPI, prompt?: string): Promise<st
                 error?.statusCode == 400
                   ? `'${doc}' is an invalid document name.`
                   : error?.statusCode == 404
-                  ? `Document '${doc}' does not exist.`
-                  : `Internal Server Error encountered trying to validate document '${doc}'.`,
+                    ? `Document '${doc}' does not exist.`
+                    : `Internal Server Error encountered trying to validate document '${doc}'.`,
                 "Dismiss"
               );
               resolve(undefined);
@@ -499,13 +475,7 @@ export async function pickDocument(api: AtelierAPI, prompt?: string): Promise<st
             })
             .catch((error) => {
               quickPick.hide();
-              let message = `Failed to get namespace contents.`;
-              if (error && error.errorText && error.errorText !== "") {
-                outputChannel.appendLine("\n" + error.errorText);
-                outputChannel.show(true);
-                message += " Check 'ObjectScript' output channel for details.";
-              }
-              vscode.window.showErrorMessage(message, "Dismiss");
+              handleError(error, "Failed to get namespace contents.");
             });
         }
       }
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 77e9fa85..63a66872 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -11,29 +11,63 @@ import {
   lsExtensionId,
   OBJECTSCRIPT_FILE_SCHEMA,
   documentContentProvider,
+  filesystemSchemas,
+  otherDocExts,
 } from "../extension";
 import { getCategory } from "../commands/export";
 import { isCSPFile } from "../providers/FileSystemProvider/FileSystemProvider";
 import { AtelierAPI } from "../api";
 
-let latestErrorMessage = "";
-export const outputChannel: {
-  resetError?(): void;
-  appendError?(value: string, show?: boolean): void;
-} & vscode.OutputChannel = vscode.window.createOutputChannel("ObjectScript", "vscode-objectscript-output");
+export const outputChannel = vscode.window.createOutputChannel("ObjectScript", "vscode-objectscript-output");
 
-/// Append Error if no duplicates previous one
-outputChannel.appendError = (value: string, show = true): void => {
-  if (latestErrorMessage === value) {
-    return;
+/**
+ * Return a string represenattion of `error`.
+ * If `error` is `undefined`, returns the empty string.
+ */
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+export function stringifyError(error): string {
+  try {
+    return (
+      error == undefined
+        ? ""
+        : error.errorText
+          ? <string>error.errorText
+          : typeof error == "string"
+            ? error
+            : error instanceof Error
+              ? error.toString()
+              : JSON.stringify(error)
+    ).trim();
+  } catch {
+    // Need to catch errors from JSON.stringify()
+    return "";
   }
-  latestErrorMessage = value;
-  outputChannel.appendLine(value);
-  show && outputChannel.show(true);
-};
-outputChannel.resetError = (): void => {
-  latestErrorMessage = "";
-};
+}
+
+/** The last error string written to the Output channel */
+let lastErrorStr = "";
+
+/**
+ * Stringify `error` and append it to the Output channel, followed by line feed character.
+ * Doesn't append `error` if it's a duplicate of the last error appended, or if it's
+ * stringified value is the empty string. If `message` is defined, calls
+ * `vscode.window.showErrorMessage()` with that message plus a reminder to check
+ * the Output channel, if an error was appended to it.
+ */
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+export function handleError(error, message?: string): void {
+  if (!error) return;
+  const errorStr = stringifyError(error);
+  if (errorStr.length) {
+    if (errorStr != lastErrorStr) {
+      lastErrorStr = errorStr;
+      outputChannel.appendLine(errorStr);
+    }
+    outputChannel.show(true);
+    if (message) message += " Check the 'ObjectScript' Output channel for details.";
+  }
+  if (message) vscode.window.showErrorMessage(message, "Dismiss");
+}
 
 export function outputConsole(data: string[]): void {
   data.forEach((line): void => {
@@ -41,7 +75,6 @@ export function outputConsole(data: string[]): void {
   });
 }
 
-// tslint:disable-next-line: interface-name
 export interface CurrentFile {
   name: string;
   fileName: string;
@@ -87,79 +120,119 @@ export function cspAppsForApi(api: AtelierAPI): string[] {
   );
 }
 
+/**
+ * Get a list of Studio Abstract Document extensions in the server-namespace that `uri` is connected to.
+ */
+function otherDocExtsForUri(uri: vscode.Uri): string[] {
+  const api = new AtelierAPI(uri);
+  return otherDocExts.get(`${api.serverId}:${api.config.ns}`.toLowerCase()) ?? [];
+}
+
+/**
+ * Returns the path of file `uri` relative to workspace folder `wsUri`.
+ * Returns the emptry string if `uri` is not in `wsUri`.
+ */
+function filePathNoWsFolder(uri: vscode.Uri, wsUri: vscode.Uri): string {
+  let wsPath = wsUri.path;
+  if (!wsPath.endsWith("/")) wsPath += "/";
+  return uri.path.startsWith(wsPath) ? uri.path.slice(wsPath.length) : "";
+}
+
 /**
  * Determine the server name of a local non-ObjectScript file (any file that's not CLS,MAC,INT,INC).
- * @param localPath The full path to the file on disk.
+ * @param uri The uri of the file.
  * @param workspace The workspace the file is in.
  * @param fileExt The extension of the file.
  */
-function getServerDocName(localPath: string, workspace: string, fileExt: string): string {
+function getServerDocName(uri: vscode.Uri, workspace: string, fileExt: string): string {
   if (!workspace) {
     // No workspace folders are open
     return null;
   }
-  const workspacePath = uriOfWorkspaceFolder(workspace).fsPath;
-  const filePathNoWorkspaceArr = localPath.replace(workspacePath + path.sep, "").split(path.sep);
-  const uri = vscode.Uri.file(localPath);
-  const cspIdx = uri.path.indexOf(cspAppsForUri(uri).find((cspApp) => uri.path.includes(cspApp + "/")));
+  const relativeFilePath = filePathNoWsFolder(uri, uriOfWorkspaceFolder(workspace));
+  if (relativeFilePath == "") return null;
+  const cspIdx = uri.path.lastIndexOf(cspAppsForUri(uri).find((cspApp) => uri.path.includes(cspApp + "/")));
   if (cspIdx != -1) {
     return uri.path.slice(cspIdx);
-  } else {
-    const { atelier, folder, addCategory } = config("export", workspace);
-    const root = [
-      typeof folder === "string" && folder.length ? folder : null,
-      addCategory ? getCategory(localPath, addCategory) : null,
+  } else if (fileExt == "dfi") {
+    // Check for matching export settings first. If no match, use base name.
+    const { folder, addCategory } = config("export", workspace);
+    let root = [
+      typeof folder == "string" && folder.length ? folder : null,
+      addCategory ? getCategory(uri.fsPath, addCategory) : null,
     ]
       .filter(notNull)
-      .join(path.sep);
-    let filePath = filePathNoWorkspaceArr.join(path.sep).slice(root.length + path.sep.length);
-    if (fileExt == "dfi" && atelier) {
-      filePath = filePath.replaceAll(path.sep, "-");
+      .join("/")
+      .replace(/\\/g, "/");
+    if (!root.endsWith("/")) root += "/";
+    if (relativeFilePath.startsWith(root)) {
+      // Convert any folders into "-"
+      return relativeFilePath.slice(root.length).replace(/\//g, "-");
+    } else {
+      // Use the last part of the path since it didn't match the export settings
+      return uri.path.split("/").pop();
     }
-    return filePath;
+  } else {
+    // Use the last part of the path without checking the export settings
+    return uri.path.split("/").pop();
   }
 }
 
 /**
- * Determine if this non-ObjectScript local file is importable
- * (i.e. is part of a CSP application or matches our export settings).
- * @param file The file to check.
+ * Determine if this non-ObjectScript local file is importable.
+ * @param uri The file to check.
  */
-export function isImportableLocalFile(file: vscode.TextDocument): boolean {
-  const workspace = currentWorkspaceFolder(file);
+export function isImportableLocalFile(uri: vscode.Uri): boolean {
+  // A non-class or routine file is only importable
+  // if it's in a web application folder or it's a
+  // known Studio abstract document type within a workspace folder
+  if (!vscode.workspace.getWorkspaceFolder(uri)) return false;
+  return (
+    cspAppsForUri(uri).some((cspApp) => uri.path.includes(cspApp + "/")) ||
+    otherDocExtsForUri(uri).includes(uri.path.split(".").pop().toLowerCase())
+  );
+  /*
+  const workspace = workspaceFolderOfUri(uri);
   if (workspace == "") {
     // No workspace folders are open
     return false;
   }
   const workspacePath = uriOfWorkspaceFolder(workspace).fsPath;
-  const filePathNoWorkspaceArr = file.fileName.replace(workspacePath + path.sep, "").split(path.sep);
-  const isCSP = cspAppsForUri(file.uri).findIndex((cspApp) => file.uri.path.includes(cspApp + "/")) != -1;
-  if (isCSP) {
+  const filePathNoWorkspaceArr = uri.fsPath.replace(workspacePath + path.sep, "").split(path.sep);
+  if (cspAppsForUri(uri).some((cspApp) => uri.path.includes(cspApp + "/"))) {
     return true;
   } else {
-    // Check if this file matches our export settings
-    const { atelier, folder, addCategory } = config("export", workspace);
-    const expectedRoot = [
-      typeof folder === "string" && folder.length ? folder : null,
-      addCategory ? getCategory(file.fileName, addCategory) : null,
-    ]
-      .filter(notNull)
-      .join(path.sep);
-    let filePath = filePathNoWorkspaceArr.join(path.sep);
-    if (filePath.startsWith(expectedRoot)) {
-      filePath = filePath.slice(expectedRoot.length + path.sep.length);
-      if (file.uri.path.toLowerCase().endsWith(".dfi")) {
-        // DFI files can be split using the atelier setting
-        if ((atelier && !filePath.includes("-")) || !atelier) {
-          return true;
+    // Check if this is a known "other" document
+    const fileExt = uri.path.split(".").pop().toLowerCase();
+    if (otherDocExtsForUri(uri).includes(fileExt)) {
+      // The server-namespace supports this document type
+      return true;
+    } else {
+      // Fall back to checking if this file matches our export settings
+      const { atelier, folder, addCategory } = config("export", workspace);
+      const expectedRoot = [
+        typeof folder === "string" && folder.length ? folder : null,
+        addCategory ? getCategory(uri.fsPath, addCategory) : null,
+      ]
+        .filter(notNull)
+        .join(path.sep);
+      let filePath = filePathNoWorkspaceArr.join(path.sep);
+      if (filePath.startsWith(expectedRoot)) {
+        filePath = filePath.slice(expectedRoot.length + path.sep.length);
+        if (fileExt == "dfi") {
+          // DFI files can be split using the atelier setting
+          if ((atelier && !filePath.includes("-")) || !atelier) {
+            return true;
+          }
+        } else {
+          // Non-CSP or DFI files cannot be in subdirectories
+          return !filePath.includes(path.sep);
         }
-      } else {
-        // Non-CSP or DFI files cannot be in subdirectories
-        return !filePath.includes(path.sep);
       }
     }
     return false;
   }
+    */
 }
 
 /** A regex for extracting the name of a class from its content */
@@ -176,6 +249,14 @@ export function currentFileFromContent(uri: vscode.Uri, content: string | Buffer
     return null;
   }
   const fileExt = fileName.split(".").pop().toLowerCase();
+  if (
+    notIsfs(uri) &&
+    !["cls", "mac", "int", "inc"].includes(fileExt) &&
+    // This is a non-class or routine local file, so check if we can import it
+    !isImportableLocalFile(uri)
+  ) {
+    return null;
+  }
   let name = "";
   let ext = "";
   if (fileExt === "cls" && typeof content === "string") {
@@ -188,16 +269,18 @@ export function currentFileFromContent(uri: vscode.Uri, content: string | Buffer
     const match = content.match(routineNameTypeRegex);
     if (match) {
       [, name, ext = "mac"] = match;
-    } else {
-      [name, ext = "mac"] = path.basename(fileName).split(".");
     }
   } else {
-    name = getServerDocName(fileName, workspaceFolder, fileExt);
+    if (notIsfs(uri)) {
+      name = getServerDocName(uri, workspaceFolder, fileExt);
+    } else {
+      name = uri.path;
+    }
     // Need to strip leading / for custom Studio documents which should not be treated as files.
     // e.g. For a custom Studio document Test.ZPM, the variable name would be /Test.ZPM which is
     // not the document name. The document name is Test.ZPM so requests made to the Atelier APIs
     // using the name with the leading / would fail to find the document.
-    if (name.charAt(0) === "/") {
+    if (name?.charAt(0) == "/") {
       name = name.slice(1);
     }
   }
@@ -241,28 +324,19 @@ export function currentFile(document?: vscode.TextDocument): CurrentTextFile {
   const fileName = document.fileName;
   const fileExt = fileName.split(".").pop().toLowerCase();
   if (
-    !schemas.includes(document.uri.scheme) &&
-    (!document ||
-      !document.fileName ||
-      !document.languageId ||
-      !document.languageId.startsWith("objectscript") ||
-      document.languageId === "objectscript-output")
+    notIsfs(document.uri) &&
+    !["cls", "mac", "int", "inc"].includes(fileExt) &&
+    // This is a non-class or routine local file, so check if we can import it
+    !isImportableLocalFile(document.uri)
   ) {
-    // This is a non-InterSystems local file, so check if we can import it
-    if (!isImportableLocalFile(document)) {
-      return null;
-    }
+    return null;
   }
   const eol = document.eol || vscode.EndOfLine.LF;
   const uri = redirectDotvscodeRoot(document.uri);
   const content = document.getText();
   let name = "";
   let ext = "";
-  const params = new URLSearchParams(uri.query);
-  const csp = params.has("csp") && ["", "1"].includes(params.get("csp"));
-  if (csp) {
-    name = uri.path;
-  } else if (fileExt === "cls") {
+  if (fileExt === "cls") {
     // Allow Unicode letters
     const match = content.match(classNameRegex);
     if (match) {
@@ -272,24 +346,18 @@ export function currentFile(document?: vscode.TextDocument): CurrentTextFile {
     const match = content.match(routineNameTypeRegex);
     if (match) {
       [, name, ext = "mac"] = match;
-    } else {
-      [name, ext = "mac"] = path.basename(document.fileName).split(".");
     }
   } else {
-    if (document.uri.scheme === "file") {
-      if (fileExt.match(/(csp|csr)/i) && !isImportableLocalFile(document)) {
-        // This is a csp or csr file that's not in a csp directory
-        return null;
-      }
-      name = getServerDocName(fileName, currentWorkspaceFolder(document), fileExt);
+    if (notIsfs(document.uri)) {
+      name = getServerDocName(document.uri, currentWorkspaceFolder(document), fileExt);
     } else {
-      name = fileName;
+      name = uri.path;
     }
     // Need to strip leading / for custom Studio documents which should not be treated as files.
     // e.g. For a custom Studio document Test.ZPM, the variable name would be /Test.ZPM which is
     // not the document name. The document name is Test.ZPM so requests made to the Atelier APIs
     // using the name with the leading / would fail to find the document.
-    if (name.charAt(0) === "/") {
+    if (name?.charAt(0) == "/") {
       name = name.slice(1);
     }
   }
@@ -317,12 +385,11 @@ export function connectionTarget(uri?: vscode.Uri): ConnectionTarget {
   uri = uri
     ? uri
     : vscode.window.activeTextEditor && vscode.window.activeTextEditor.document
-    ? vscode.window.activeTextEditor.document.uri
-    : undefined;
+      ? vscode.window.activeTextEditor.document.uri
+      : undefined;
   if (uri) {
-    if (uri.scheme === "file") {
+    if (notIsfs(uri)) {
       const folder = vscode.workspace.getWorkspaceFolder(uri);
-
       // Active document might not be from any folder in the workspace (e.g. user's settings.json)
       if (folder) {
         result.configName = folder.name;
@@ -400,11 +467,11 @@ export function currentWorkspaceFolder(document?: vscode.TextDocument): string {
 }
 
 export function workspaceFolderOfUri(uri: vscode.Uri): string {
-  if (uri.scheme === "file") {
+  if (notIsfs(uri)) {
     if (vscode.workspace.getWorkspaceFolder(uri)) {
       return vscode.workspace.getWorkspaceFolder(uri).name;
     }
-  } else if (schemas.includes(uri.scheme)) {
+  } else {
     const rootUri = uri.with({ path: "/" }).toString();
     const foundFolder = vscode.workspace.workspaceFolders.find(
       (workspaceFolder) => workspaceFolder.uri.toString() == rootUri
@@ -708,11 +775,16 @@ export function isUnauthenticated(username: string): boolean {
   return username == undefined || username == "" || username.toLowerCase() == "unknownuser";
 }
 
+/** Returns `true` if `uri.scheme` is neither `isfs` nor `isfs-readonly` */
+export function notIsfs(uri: vscode.Uri): boolean {
+  return !filesystemSchemas.includes(uri.scheme);
+}
+
 // ---------------------------------------------------------------------
 // Source: https://github.com/amsterdamharu/lib/blob/master/src/index.js
 
 const promiseLike = (x) => x !== undefined && typeof x.then === "function";
-const ifPromise = (fn) => (x) => promiseLike(x) ? x.then(fn) : fn(x);
+const ifPromise = (fn) => (x) => (promiseLike(x) ? x.then(fn) : fn(x));
 
 /*
   causes a promise returning function not to be called

From 42c4aea25a7413fca7b5ef2fbe70fc187d3cd608 Mon Sep 17 00:00:00 2001
From: Brett Saviano <bsaviano@intersystems.com>
Date: Tue, 20 Aug 2024 08:07:29 -0400
Subject: [PATCH 2/9] Hide server-side source control menus for client-side
 workspaces

---
 package.json                  | 4 ++--
 src/commands/serverActions.ts | 6 +++---
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/package.json b/package.json
index 35b1a10c..5fbe9930 100644
--- a/package.json
+++ b/package.json
@@ -192,7 +192,7 @@
         },
         {
           "command": "vscode-objectscript.serverCommands.sourceControl",
-          "when": "(vscode-objectscript.connectActive && resourceScheme == isfs) || (vscode-objectscript.connectActive && !editorIsOpen)"
+          "when": "(vscode-objectscript.connectActive && resourceScheme == isfs) || (vscode-objectscript.connectActive && !editorIsOpen && virtualWorkspace)"
         },
         {
           "command": "vscode-objectscript.serverCommands.contextSourceControl",
@@ -200,7 +200,7 @@
         },
         {
           "command": "vscode-objectscript.serverCommands.other",
-          "when": "vscode-objectscript.connectActive && resourceScheme =~ /^isfs(-readonly)?$/ || (vscode-objectscript.connectActive && !editorIsOpen)"
+          "when": "vscode-objectscript.connectActive && resourceScheme =~ /^isfs(-readonly)?$/ || (vscode-objectscript.connectActive && !editorIsOpen && virtualWorkspace)"
         },
         {
           "command": "vscode-objectscript.serverCommands.contextOther",
diff --git a/src/commands/serverActions.ts b/src/commands/serverActions.ts
index c835085d..eff4e261 100644
--- a/src/commands/serverActions.ts
+++ b/src/commands/serverActions.ts
@@ -32,6 +32,7 @@ export async function serverActions(): Promise<void> {
   const { links } = config("conn");
   const nsEncoded = encodeURIComponent(ns);
   const actions: ServerAction[] = [];
+  const wsUri = uriOfWorkspaceFolder();
   if (!api.externalServer) {
     actions.push({
       detail: (active ? "Disable" : "Enable") + " current connection",
@@ -47,7 +48,6 @@ export async function serverActions(): Promise<void> {
     });
 
     // Switching namespace makes only sense for non-ISFS folders
-    const wsUri = uriOfWorkspaceFolder();
     if (wsUri && notIsfs(wsUri)) {
       actions.push({
         id: "switchNamespace",
@@ -137,7 +137,7 @@ export async function serverActions(): Promise<void> {
   const classRef = `/csp/documatic/%25CSP.Documatic.cls?LIBRARY=${nsEncoded}${
     classname ? "&CLASSNAME=" + classnameEncoded : ""
   }`;
-  const project = new URLSearchParams(uriOfWorkspaceFolder()?.query).get("project") || "";
+  const project = new URLSearchParams(wsUri?.query).get("project") || "";
   let extraLinks = 0;
   for (const title in links) {
     const rawLink = String(links[title]);
@@ -193,7 +193,7 @@ export async function serverActions(): Promise<void> {
     detail: "Select a Studio Add-in to open",
   });
   if (
-    !vscode.window.activeTextEditor ||
+    (!vscode.window.activeTextEditor && wsUri && notIsfs(wsUri)) ||
     vscode.window.activeTextEditor.document.uri.scheme === FILESYSTEM_SCHEMA ||
     vscode.window.activeTextEditor.document.uri.scheme === FILESYSTEM_READONLY_SCHEMA
   ) {

From 73dd4a05cdbf04595060135831a373f4a433556a Mon Sep 17 00:00:00 2001
From: Brett Saviano <bsaviano@intersystems.com>
Date: Fri, 23 Aug 2024 08:28:50 -0400
Subject: [PATCH 3/9] Fix `virtualWorkspace` check

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 5fbe9930..c7a99ca8 100644
--- a/package.json
+++ b/package.json
@@ -192,7 +192,7 @@
         },
         {
           "command": "vscode-objectscript.serverCommands.sourceControl",
-          "when": "(vscode-objectscript.connectActive && resourceScheme == isfs) || (vscode-objectscript.connectActive && !editorIsOpen && virtualWorkspace)"
+          "when": "(vscode-objectscript.connectActive && resourceScheme == isfs) || (vscode-objectscript.connectActive && !editorIsOpen && virtualWorkspace =~ /^isfs(-readonly)?$/)"
         },
         {
           "command": "vscode-objectscript.serverCommands.contextSourceControl",
@@ -200,7 +200,7 @@
         },
         {
           "command": "vscode-objectscript.serverCommands.other",
-          "when": "vscode-objectscript.connectActive && resourceScheme =~ /^isfs(-readonly)?$/ || (vscode-objectscript.connectActive && !editorIsOpen && virtualWorkspace)"
+          "when": "vscode-objectscript.connectActive && resourceScheme =~ /^isfs(-readonly)?$/ || (vscode-objectscript.connectActive && !editorIsOpen && virtualWorkspace =~ /^isfs(-readonly)?$/)"
         },
         {
           "command": "vscode-objectscript.serverCommands.contextOther",

From 84e1acd847f5cc4ba8916c8d592cb42533a8d14a Mon Sep 17 00:00:00 2001
From: Brett Saviano <bsaviano@intersystems.com>
Date: Mon, 9 Sep 2024 16:12:49 -0400
Subject: [PATCH 4/9] npm run lint-fix

---
 src/commands/studio.ts     | 2 +-
 src/utils/documentIndex.ts | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/commands/studio.ts b/src/commands/studio.ts
index ea856cdc..182b98bb 100644
--- a/src/commands/studio.ts
+++ b/src/commands/studio.ts
@@ -491,7 +491,7 @@ export class StudioActions {
     return this.api
       .actionQuery("SELECT %Atelier_v1_Utils.Extension_ExtensionEnabled() AS Enabled", [])
       .then((data) => data.result.content)
-      .then((content) => (content && content.length ? content[0]?.Enabled ?? false : false))
+      .then((content) => (content && content.length ? (content[0]?.Enabled ?? false) : false))
       .catch(() => false); // Treat any errors as "no source control"
   }
 
diff --git a/src/utils/documentIndex.ts b/src/utils/documentIndex.ts
index bd9ce98a..58c0a6d9 100644
--- a/src/utils/documentIndex.ts
+++ b/src/utils/documentIndex.ts
@@ -193,7 +193,7 @@ async function updateIndexAndSyncChanges(
 /** Get all `Uri`s for `document` in `wsFolder` */
 export function getUrisForDocument(document: string, wsFolder: vscode.WorkspaceFolder): vscode.Uri[] {
   const index = wsFolderIndex.get(wsFolder.uri.toString());
-  return index ? index.documents.get(document) ?? [] : [];
+  return index ? (index.documents.get(document) ?? []) : [];
 }
 
 /** Clean up all `FileSystemWatcher`s */

From 610dd44e23b86785c9b5df70fab5a4dfad959ec7 Mon Sep 17 00:00:00 2001
From: Brett Saviano <bsaviano@intersystems.com>
Date: Mon, 9 Sep 2024 17:06:44 -0400
Subject: [PATCH 5/9] New typescript and node types

---
 package-lock.json                             | 23 +++++++++++++------
 package.json                                  |  6 ++---
 .../FileSystemProvider/FileSystemProvider.ts  |  4 +---
 .../FileSystemProvider/TextSearchProvider.ts  |  2 +-
 4 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index ddd5f343..bb0d8fef 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21,13 +21,13 @@
         "node-fetch-cjs": "3.1.1",
         "vscode-cache": "^0.3.0",
         "vscode-extension-telemetry": "^0.1.6",
-        "ws": "^8.17.1"
+        "ws": "^8.18.0"
       },
       "devDependencies": {
         "@types/istextorbinary": "2.3.1",
         "@types/minimatch": "5.1.2",
         "@types/mocha": "^7.0.2",
-        "@types/node": "^14.18.0",
+        "@types/node": "^20.16.5",
         "@types/semver": "7.5.4",
         "@types/vscode": "1.91.0",
         "@types/ws": "8.5.4",
@@ -50,7 +50,7 @@
         "path-browserify": "^1.0.1",
         "prettier": "^3.3.1",
         "ts-loader": "^9.5.1",
-        "typescript": "^5.4.5",
+        "typescript": "^5.6.2",
         "webpack": "^5.94.0",
         "webpack-cli": "^5.1.4"
       },
@@ -333,10 +333,13 @@
       "dev": true
     },
     "node_modules/@types/node": {
-      "version": "14.18.63",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz",
-      "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==",
-      "dev": true
+      "version": "20.16.5",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz",
+      "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==",
+      "dev": true,
+      "dependencies": {
+        "undici-types": "~6.19.2"
+      }
     },
     "node_modules/@types/semver": {
       "version": "7.5.4",
@@ -5762,6 +5765,12 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/undici-types": {
+      "version": "6.19.8",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+      "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
+      "dev": true
+    },
     "node_modules/update-browserslist-db": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
diff --git a/package.json b/package.json
index 97f6c84e..ab95af5e 100644
--- a/package.json
+++ b/package.json
@@ -1770,7 +1770,7 @@
     "@types/istextorbinary": "2.3.1",
     "@types/minimatch": "5.1.2",
     "@types/mocha": "^7.0.2",
-    "@types/node": "^14.18.0",
+    "@types/node": "^20.16.5",
     "@types/semver": "7.5.4",
     "@types/vscode": "1.91.0",
     "@types/ws": "8.5.4",
@@ -1792,7 +1792,7 @@
     "path-browserify": "^1.0.1",
     "prettier": "^3.3.1",
     "ts-loader": "^9.5.1",
-    "typescript": "^5.4.5",
+    "typescript": "^5.6.2",
     "@vscode/debugadapter-testsupport": "^1.67.0",
     "webpack": "^5.94.0",
     "webpack-cli": "^5.1.4"
@@ -1809,7 +1809,7 @@
     "@vscode/debugadapter": "^1.65.0",
     "@vscode/debugprotocol": "^1.65.0",
     "vscode-extension-telemetry": "^0.1.6",
-    "ws": "^8.17.1"
+    "ws": "^8.18.0"
   },
   "extensionDependencies": [
     "intersystems-community.servermanager"
diff --git a/src/providers/FileSystemProvider/FileSystemProvider.ts b/src/providers/FileSystemProvider/FileSystemProvider.ts
index 60db9577..7bcbd4b9 100644
--- a/src/providers/FileSystemProvider/FileSystemProvider.ts
+++ b/src/providers/FileSystemProvider/FileSystemProvider.ts
@@ -28,8 +28,6 @@ import { addIsfsFileToProject, modifyProject } from "../../commands/project";
 import { DocumentContentProvider } from "../DocumentContentProvider";
 import { Document, UserAction } from "../../api/atelier";
 
-declare function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timeout;
-
 export type Entry = File | Directory;
 
 export function generateFileContent(
@@ -177,7 +175,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
 
   private _emitter = new vscode.EventEmitter<vscode.FileChangeEvent[]>();
   private _bufferedEvents: vscode.FileChangeEvent[] = [];
-  private _fireSoonHandle?: NodeJS.Timer;
+  private _fireSoonHandle?: NodeJS.Timeout;
 
   public constructor() {
     this.onDidChangeFile = this._emitter.event;
diff --git a/src/providers/FileSystemProvider/TextSearchProvider.ts b/src/providers/FileSystemProvider/TextSearchProvider.ts
index 8c59f670..342a99c3 100644
--- a/src/providers/FileSystemProvider/TextSearchProvider.ts
+++ b/src/providers/FileSystemProvider/TextSearchProvider.ts
@@ -89,7 +89,7 @@ function searchMatchToLine(
                 line = memend + (match.attrline ?? 1);
               } else {
                 // This is a keyword with a multiline value
-                line = i + (match.attrline - 1 ?? 0);
+                line = i + (match.attrline - 1 || 0);
               }
             } else {
               // This is in the class member definition

From 7e83e48b80438c10170fcdb268bcaaa647d38a51 Mon Sep 17 00:00:00 2001
From: Brett Saviano <bsaviano@intersystems.com>
Date: Wed, 30 Oct 2024 12:20:13 -0400
Subject: [PATCH 6/9] Fix two bugs

---
 src/commands/export.ts     |  9 +++++++++
 src/utils/documentIndex.ts | 20 +++++++++++++++++---
 2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/src/commands/export.ts b/src/commands/export.ts
index 6ac22d14..21d4d65b 100644
--- a/src/commands/export.ts
+++ b/src/commands/export.ts
@@ -15,6 +15,14 @@ import {
 import { NodeBase } from "../explorer/models/nodeBase";
 import { pickDocuments } from "../utils/documentPicker";
 
+/**
+ * Array of stringified `Uri`s that have been exported.
+ * Used by the documentIndex to determine if a created/changed
+ * file needs to be synced with the server. If the documentIndex
+ * finds a match in this array, the element is then removed.
+ */
+export const exportedUris: string[] = [];
+
 export const getCategory = (fileName: string, addCategory: any | boolean): string => {
   const fileExt = fileName.split(".").pop().toLowerCase();
   if (typeof addCategory === "object") {
@@ -94,6 +102,7 @@ async function exportFile(wsFolderUri: vscode.Uri, namespace: string, name: stri
   api.setNamespace(namespace);
   let fileUri = vscode.Uri.file(fileName);
   if (wsFolderUri.scheme != "file") fileUri = wsFolderUri.with({ path: fileUri.path });
+  exportedUris.push(fileUri.toString());
   const log = (status: string) =>
     outputChannel.appendLine(`Export '${name}' to '${fileUri.toString(true)}' - ${status}`);
 
diff --git a/src/utils/documentIndex.ts b/src/utils/documentIndex.ts
index 58c0a6d9..d3f6513d 100644
--- a/src/utils/documentIndex.ts
+++ b/src/utils/documentIndex.ts
@@ -2,6 +2,7 @@ import * as vscode from "vscode";
 import { CurrentBinaryFile, CurrentTextFile, currentFileFromContent, handleError, notIsfs, outputChannel } from ".";
 import { AtelierAPI } from "../api";
 import { compile, importFile } from "../commands/compile";
+import { exportedUris } from "../commands/export";
 
 interface WSFolderIndex {
   /** The `FileSystemWatcher` for this workspace folder */
@@ -22,7 +23,7 @@ interface WSFolderIndexChange {
 /** Map of stringified workspace folder `Uri`s to collection of InterSystems classes and routines contained therein */
 const wsFolderIndex: Map<string, WSFolderIndex> = new Map();
 
-/** Glob pattern that matches files we want to index */
+/** Glob pattern that matches classes and routines */
 const filePattern = "{**/*.cls,**/*.mac,**/*.int,**/*.inc}";
 
 /** We want decoding errors to be thrown */
@@ -42,11 +43,12 @@ export async function indexWorkspaceFolder(wsFolder: vscode.WorkspaceFolder): Pr
   watcher.onDidChange((uri) => updateIndexAndSyncChanges(uri, documents, uris));
   watcher.onDidCreate((uri) => updateIndexAndSyncChanges(uri, documents, uris));
   watcher.onDidDelete((uri) => {
+    // Remove the class/routine in the file from the index,
+    // then delete it on the server if required
     const change = removeDocumentFromIndex(uri, documents, uris);
     if (change.removed) {
       const api = new AtelierAPI(uri);
       if (!api.active) return;
-      // Delete document on the server
       api.deleteDoc(change.removed).catch((error) => handleError(error));
     }
   });
@@ -94,7 +96,7 @@ export async function updateIndexForDocument(
       // since the file may be a non-text file
       // with a cls, mac, int or inc extension.
       if (error instanceof vscode.FileSystemError) {
-        outputChannel.appendLine(`Failed to get text contents of '${uri.toString(true)}': ${error.toString()}`);
+        outputChannel.appendLine(`Failed to read contents of '${uri.toString(true)}': ${error.toString()}`);
       }
       return result;
     }
@@ -168,6 +170,18 @@ async function updateIndexAndSyncChanges(
 ): Promise<void> {
   const change = await updateIndexForDocument(uri, documents, uris);
   if (!change.added && !change.removed) return;
+  const uriString = uri.toString();
+  const exportedIdx = exportedUris.findIndex((e) => e == uriString);
+  if (exportedIdx != -1) {
+    // This creation/change event was fired due to a server
+    // export, so don't re-sync the file with the server
+    exportedUris.splice(exportedIdx, 1);
+    return;
+  }
+  if (vscode.workspace.textDocuments.some((td) => td.uri.toString() == uriString)) {
+    // Don't sync with the server because onDidSaveTextDocument will handle it
+    return;
+  }
   const api = new AtelierAPI(uri);
   if (!api.active) return;
   const config = vscode.workspace.getConfiguration("objectscript", uri);

From bda787d648bdf4f9449a244661ea2784fd8ac380 Mon Sep 17 00:00:00 2001
From: Brett Saviano <bsaviano@intersystems.com>
Date: Mon, 25 Nov 2024 10:47:09 -0500
Subject: [PATCH 7/9] #1454, plus other changes

---
 .eslintignore                                 |   2 -
 .eslintrc.json                                |  27 -
 eslint.config.mjs                             |  51 ++
 package-lock.json                             | 745 +++++++++---------
 package.json                                  |  53 +-
 src/api/index.ts                              |   6 +-
 src/commands/compile.ts                       |  27 +-
 src/commands/delete.ts                        |   4 +-
 src/commands/export.ts                        |  32 +-
 src/commands/newFile.ts                       |   9 -
 src/commands/project.ts                       |   8 +-
 src/commands/serverActions.ts                 |  16 +-
 src/commands/studio.ts                        | 105 +--
 src/debug/debugSession.ts                     |   2 +-
 src/debug/xdebugConnection.ts                 |   3 -
 src/explorer/explorer.ts                      |  30 +-
 src/explorer/models/classNode.ts              |  33 -
 src/explorer/models/cspFileNode.ts            |  33 -
 src/explorer/models/nodeBase.ts               |  64 --
 src/explorer/models/packageNode.ts            |  24 -
 src/explorer/models/projectNode.ts            |  96 ---
 src/explorer/models/projectRootNode.ts        | 107 ---
 src/explorer/models/projectsServerNode.ts     |  39 -
 src/explorer/models/projectsServerNsNode.ts   |  38 -
 src/explorer/models/rootNode.ts               | 184 -----
 src/explorer/models/routineNode.ts            |  33 -
 src/explorer/models/workspaceNode.ts          |  98 ---
 src/explorer/nodes.ts                         | 726 +++++++++++++++++
 src/explorer/projectsExplorer.ts              |   3 +-
 src/extension.ts                              | 151 ++--
 .../FileSystemProvider/FileSystemProvider.ts  | 180 +++--
 src/providers/RuleEditorProvider.ts           |   9 +-
 src/utils/classDefinition.ts                  |   1 -
 src/utils/documentIndex.ts                    | 264 +++++--
 src/utils/index.ts                            | 140 ++--
 35 files changed, 1654 insertions(+), 1689 deletions(-)
 delete mode 100644 .eslintignore
 delete mode 100644 .eslintrc.json
 create mode 100644 eslint.config.mjs
 delete mode 100644 src/explorer/models/classNode.ts
 delete mode 100644 src/explorer/models/cspFileNode.ts
 delete mode 100644 src/explorer/models/nodeBase.ts
 delete mode 100644 src/explorer/models/packageNode.ts
 delete mode 100644 src/explorer/models/projectNode.ts
 delete mode 100644 src/explorer/models/projectRootNode.ts
 delete mode 100644 src/explorer/models/projectsServerNode.ts
 delete mode 100644 src/explorer/models/projectsServerNsNode.ts
 delete mode 100644 src/explorer/models/rootNode.ts
 delete mode 100644 src/explorer/models/routineNode.ts
 delete mode 100644 src/explorer/models/workspaceNode.ts
 create mode 100644 src/explorer/nodes.ts

diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index dc3b2e6a..00000000
--- a/.eslintignore
+++ /dev/null
@@ -1,2 +0,0 @@
-vscode.d.ts
-vscode.proposed.d.ts
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index b669dba2..00000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
-  "parser": "@typescript-eslint/parser",
-  "parserOptions": {
-    "ecmaVersion": 2018,
-    "sourceType": "module",
-    "project": "./tsconfig.json"
-  },
-  "env": {
-    "es6": true,
-    "node": true
-  },
-  "extends": [
-    "eslint:recommended",
-    "plugin:@typescript-eslint/recommended",
-    "plugin:@typescript-eslint/eslint-recommended",
-    "prettier",
-    "plugin:prettier/recommended"
-  ],
-  "plugins": [
-    "@typescript-eslint"
-  ],
-  "rules": {
-    "@typescript-eslint/no-explicit-any": 0,
-    "@typescript-eslint/explicit-function-return-type": 0,
-    "@typescript-eslint/no-unused-vars": 0
-  }
-}
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 00000000..bb0d92cc
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,51 @@
+import typescriptEslint from "@typescript-eslint/eslint-plugin";
+import globals from "globals";
+import tsParser from "@typescript-eslint/parser";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+import js from "@eslint/js";
+import { FlatCompat } from "@eslint/eslintrc";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+const compat = new FlatCompat({
+    baseDirectory: __dirname,
+    recommendedConfig: js.configs.recommended,
+    allConfig: js.configs.all
+});
+
+export default [{
+    ignores: ["**/vscode.d.ts", "**/vscode.proposed.d.ts"],
+}, ...compat.extends(
+    "eslint:recommended",
+    "plugin:@typescript-eslint/recommended",
+    "plugin:@typescript-eslint/eslint-recommended",
+    "prettier",
+    "plugin:prettier/recommended",
+), {
+    plugins: {
+        "@typescript-eslint": typescriptEslint,
+    },
+
+    languageOptions: {
+        globals: {
+            ...globals.node,
+        },
+
+        parser: tsParser,
+        ecmaVersion: 2018,
+        sourceType: "module",
+
+        parserOptions: {
+            project: "./tsconfig.json",
+        },
+    },
+
+    rules: {
+        "@typescript-eslint/no-explicit-any": 0,
+        "@typescript-eslint/explicit-function-return-type": 0,
+        "@typescript-eslint/no-unused-vars": 0,
+        "@typescript-eslint/no-require-imports": 0,
+        "@typescript-eslint/no-unused-expressions": 0,
+    },
+}];
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 746de875..592cc197 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,35 +24,36 @@
         "ws": "^8.18.0"
       },
       "devDependencies": {
+        "@eslint/js": "^9.15.0",
         "@intersystems-community/intersystems-servermanager": "^3.8.0",
         "@types/istextorbinary": "2.3.1",
         "@types/minimatch": "5.1.2",
         "@types/mocha": "^7.0.2",
-        "@types/node": "20.16.5",
+        "@types/node": "20.17.6",
         "@types/semver": "7.5.4",
         "@types/vscode": "1.93.0",
         "@types/ws": "8.5.4",
         "@types/xmldom": "^0.1.29",
-        "@typescript-eslint/eslint-plugin": "^7.12.0",
-        "@typescript-eslint/parser": "^7.12.0",
+        "@typescript-eslint/eslint-plugin": "^8.15.0",
+        "@typescript-eslint/parser": "^8.15.0",
         "@vscode/debugadapter-testsupport": "^1.67.0",
-        "@vscode/dts": "^0.4.0",
-        "@vscode/test-electron": "^2.4.0",
-        "eslint": "^8.56.0",
-        "eslint-config-airbnb-base": "^15.0.0",
+        "@vscode/dts": "^0.4.1",
+        "@vscode/test-electron": "^2.4.1",
+        "eslint": "^9.15.0",
         "eslint-config-prettier": "^9.1.0",
-        "eslint-plugin-import": "^2.29.1",
-        "eslint-plugin-jsx-a11y": "^6.8.0",
+        "eslint-plugin-import": "^2.31.0",
+        "eslint-plugin-jsx-a11y": "^6.10.2",
         "eslint-plugin-node": "^11.1.0",
-        "eslint-plugin-prettier": "^5.1.3",
-        "eslint-plugin-promise": "^6.2.0",
+        "eslint-plugin-prettier": "^5.2.1",
+        "eslint-plugin-promise": "^7.1.0",
         "glob": "^7.1.6",
+        "globals": "^15.12.0",
         "mocha": "^9.1.3",
         "path-browserify": "^1.0.1",
         "prettier": "^3.3.1",
         "ts-loader": "^9.5.1",
         "typescript": "^5.6.2",
-        "webpack": "^5.94.0",
+        "webpack": "^5.96.1",
         "webpack-cli": "^5.1.4"
       },
       "engines": {
@@ -95,16 +96,51 @@
         "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
       }
     },
+    "node_modules/@eslint/config-array": {
+      "version": "0.19.0",
+      "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz",
+      "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==",
+      "dev": true,
+      "dependencies": {
+        "@eslint/object-schema": "^2.1.4",
+        "debug": "^4.3.1",
+        "minimatch": "^3.1.2"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/config-array/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/@eslint/core": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz",
+      "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==",
+      "dev": true,
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
     "node_modules/@eslint/eslintrc": {
-      "version": "2.1.4",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
-      "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz",
+      "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==",
       "dev": true,
       "dependencies": {
         "ajv": "^6.12.4",
         "debug": "^4.3.2",
-        "espree": "^9.6.0",
-        "globals": "^13.19.0",
+        "espree": "^10.0.1",
+        "globals": "^14.0.0",
         "ignore": "^5.2.0",
         "import-fresh": "^3.2.1",
         "js-yaml": "^4.1.0",
@@ -112,12 +148,24 @@
         "strip-json-comments": "^3.1.1"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
         "url": "https://opencollective.com/eslint"
       }
     },
+    "node_modules/@eslint/eslintrc/node_modules/globals": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+      "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/@eslint/eslintrc/node_modules/minimatch": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -131,39 +179,68 @@
       }
     },
     "node_modules/@eslint/js": {
-      "version": "8.57.1",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
-      "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
+      "version": "9.15.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz",
+      "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==",
       "dev": true,
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/object-schema": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz",
+      "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==",
+      "dev": true,
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       }
     },
-    "node_modules/@humanwhocodes/config-array": {
-      "version": "0.13.0",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
-      "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
-      "deprecated": "Use @eslint/config-array instead",
+    "node_modules/@eslint/plugin-kit": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz",
+      "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==",
       "dev": true,
       "dependencies": {
-        "@humanwhocodes/object-schema": "^2.0.3",
-        "debug": "^4.3.1",
-        "minimatch": "^3.0.5"
+        "levn": "^0.4.1"
       },
       "engines": {
-        "node": ">=10.10.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       }
     },
-    "node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+    "node_modules/@humanfs/core": {
+      "version": "0.19.1",
+      "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+      "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+      "dev": true,
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node": {
+      "version": "0.16.6",
+      "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
+      "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
       "dev": true,
       "dependencies": {
-        "brace-expansion": "^1.1.7"
+        "@humanfs/core": "^0.19.1",
+        "@humanwhocodes/retry": "^0.3.0"
       },
       "engines": {
-        "node": "*"
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
+      "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
+      "dev": true,
+      "engines": {
+        "node": ">=18.18"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
       }
     },
     "node_modules/@humanwhocodes/module-importer": {
@@ -179,12 +256,18 @@
         "url": "https://github.com/sponsors/nzakas"
       }
     },
-    "node_modules/@humanwhocodes/object-schema": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
-      "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
-      "deprecated": "Use @eslint/object-schema instead",
-      "dev": true
+    "node_modules/@humanwhocodes/retry": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz",
+      "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==",
+      "dev": true,
+      "engines": {
+        "node": ">=18.18"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
     },
     "node_modules/@intersystems-community/intersystems-servermanager": {
       "version": "3.8.0",
@@ -304,10 +387,30 @@
       "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
       "dev": true
     },
+    "node_modules/@types/eslint": {
+      "version": "9.6.1",
+      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
+      "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
+      "dev": true,
+      "dependencies": {
+        "@types/estree": "*",
+        "@types/json-schema": "*"
+      }
+    },
+    "node_modules/@types/eslint-scope": {
+      "version": "3.7.7",
+      "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
+      "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
+      "dev": true,
+      "dependencies": {
+        "@types/eslint": "*",
+        "@types/estree": "*"
+      }
+    },
     "node_modules/@types/estree": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
-      "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+      "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
       "dev": true
     },
     "node_modules/@types/istextorbinary": {
@@ -320,9 +423,9 @@
       }
     },
     "node_modules/@types/json-schema": {
-      "version": "7.0.9",
-      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
-      "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
+      "version": "7.0.15",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+      "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
       "dev": true
     },
     "node_modules/@types/json5": {
@@ -344,9 +447,9 @@
       "dev": true
     },
     "node_modules/@types/node": {
-      "version": "20.16.5",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz",
-      "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==",
+      "version": "20.17.6",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz",
+      "integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==",
       "dev": true,
       "dependencies": {
         "undici-types": "~6.19.2"
@@ -381,31 +484,31 @@
       "dev": true
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "7.18.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz",
-      "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==",
+      "version": "8.15.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.15.0.tgz",
+      "integrity": "sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg==",
       "dev": true,
       "dependencies": {
         "@eslint-community/regexpp": "^4.10.0",
-        "@typescript-eslint/scope-manager": "7.18.0",
-        "@typescript-eslint/type-utils": "7.18.0",
-        "@typescript-eslint/utils": "7.18.0",
-        "@typescript-eslint/visitor-keys": "7.18.0",
+        "@typescript-eslint/scope-manager": "8.15.0",
+        "@typescript-eslint/type-utils": "8.15.0",
+        "@typescript-eslint/utils": "8.15.0",
+        "@typescript-eslint/visitor-keys": "8.15.0",
         "graphemer": "^1.4.0",
         "ignore": "^5.3.1",
         "natural-compare": "^1.4.0",
         "ts-api-utils": "^1.3.0"
       },
       "engines": {
-        "node": "^18.18.0 || >=20.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
       "peerDependencies": {
-        "@typescript-eslint/parser": "^7.0.0",
-        "eslint": "^8.56.0"
+        "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0",
+        "eslint": "^8.57.0 || ^9.0.0"
       },
       "peerDependenciesMeta": {
         "typescript": {
@@ -414,26 +517,26 @@
       }
     },
     "node_modules/@typescript-eslint/parser": {
-      "version": "7.18.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz",
-      "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==",
+      "version": "8.15.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.15.0.tgz",
+      "integrity": "sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "7.18.0",
-        "@typescript-eslint/types": "7.18.0",
-        "@typescript-eslint/typescript-estree": "7.18.0",
-        "@typescript-eslint/visitor-keys": "7.18.0",
+        "@typescript-eslint/scope-manager": "8.15.0",
+        "@typescript-eslint/types": "8.15.0",
+        "@typescript-eslint/typescript-estree": "8.15.0",
+        "@typescript-eslint/visitor-keys": "8.15.0",
         "debug": "^4.3.4"
       },
       "engines": {
-        "node": "^18.18.0 || >=20.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
       "peerDependencies": {
-        "eslint": "^8.56.0"
+        "eslint": "^8.57.0 || ^9.0.0"
       },
       "peerDependenciesMeta": {
         "typescript": {
@@ -465,16 +568,16 @@
       "dev": true
     },
     "node_modules/@typescript-eslint/scope-manager": {
-      "version": "7.18.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz",
-      "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==",
+      "version": "8.15.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.15.0.tgz",
+      "integrity": "sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.18.0",
-        "@typescript-eslint/visitor-keys": "7.18.0"
+        "@typescript-eslint/types": "8.15.0",
+        "@typescript-eslint/visitor-keys": "8.15.0"
       },
       "engines": {
-        "node": "^18.18.0 || >=20.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
         "type": "opencollective",
@@ -482,25 +585,25 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils": {
-      "version": "7.18.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz",
-      "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==",
+      "version": "8.15.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.15.0.tgz",
+      "integrity": "sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/typescript-estree": "7.18.0",
-        "@typescript-eslint/utils": "7.18.0",
+        "@typescript-eslint/typescript-estree": "8.15.0",
+        "@typescript-eslint/utils": "8.15.0",
         "debug": "^4.3.4",
         "ts-api-utils": "^1.3.0"
       },
       "engines": {
-        "node": "^18.18.0 || >=20.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
       "peerDependencies": {
-        "eslint": "^8.56.0"
+        "eslint": "^8.57.0 || ^9.0.0"
       },
       "peerDependenciesMeta": {
         "typescript": {
@@ -532,12 +635,12 @@
       "dev": true
     },
     "node_modules/@typescript-eslint/types": {
-      "version": "7.18.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz",
-      "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==",
+      "version": "8.15.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.15.0.tgz",
+      "integrity": "sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ==",
       "dev": true,
       "engines": {
-        "node": "^18.18.0 || >=20.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
         "type": "opencollective",
@@ -545,22 +648,22 @@
       }
     },
     "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "7.18.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz",
-      "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==",
+      "version": "8.15.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.15.0.tgz",
+      "integrity": "sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.18.0",
-        "@typescript-eslint/visitor-keys": "7.18.0",
+        "@typescript-eslint/types": "8.15.0",
+        "@typescript-eslint/visitor-keys": "8.15.0",
         "debug": "^4.3.4",
-        "globby": "^11.1.0",
+        "fast-glob": "^3.3.2",
         "is-glob": "^4.0.3",
         "minimatch": "^9.0.4",
         "semver": "^7.6.0",
         "ts-api-utils": "^1.3.0"
       },
       "engines": {
-        "node": "^18.18.0 || >=20.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
         "type": "opencollective",
@@ -596,56 +699,67 @@
       "dev": true
     },
     "node_modules/@typescript-eslint/utils": {
-      "version": "7.18.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz",
-      "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==",
+      "version": "8.15.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.15.0.tgz",
+      "integrity": "sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.4.0",
-        "@typescript-eslint/scope-manager": "7.18.0",
-        "@typescript-eslint/types": "7.18.0",
-        "@typescript-eslint/typescript-estree": "7.18.0"
+        "@typescript-eslint/scope-manager": "8.15.0",
+        "@typescript-eslint/types": "8.15.0",
+        "@typescript-eslint/typescript-estree": "8.15.0"
       },
       "engines": {
-        "node": "^18.18.0 || >=20.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
       "peerDependencies": {
-        "eslint": "^8.56.0"
+        "eslint": "^8.57.0 || ^9.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
       }
     },
     "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "7.18.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz",
-      "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==",
+      "version": "8.15.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.15.0.tgz",
+      "integrity": "sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.18.0",
-        "eslint-visitor-keys": "^3.4.3"
+        "@typescript-eslint/types": "8.15.0",
+        "eslint-visitor-keys": "^4.2.0"
       },
       "engines": {
-        "node": "^18.18.0 || >=20.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       }
     },
+    "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+      "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
+      "dev": true,
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
     "node_modules/@ungap/promise-all-settled": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
       "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
       "dev": true
     },
-    "node_modules/@ungap/structured-clone": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
-      "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
-      "dev": true
-    },
     "node_modules/@vscode/debugadapter": {
       "version": "1.68.0",
       "resolved": "https://registry.npmjs.org/@vscode/debugadapter/-/debugadapter-1.68.0.tgz",
@@ -675,9 +789,9 @@
       "integrity": "sha512-2J27dysaXmvnfuhFGhfeuxfHRXunqNPxtBoR3koiTOA9rdxWNDTa1zIFLCFMSHJ9MPTPKFcBeblsyaCJCIlQxg=="
     },
     "node_modules/@vscode/dts": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/@vscode/dts/-/dts-0.4.0.tgz",
-      "integrity": "sha512-m28fZnyS9PlzVvYHppyC3Q98U2RFIZO2srnBMvyupPBY5QkSxoNIjTV9roLaU7kE+gc+HXczH8XHPETUkt9IAA==",
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/@vscode/dts/-/dts-0.4.1.tgz",
+      "integrity": "sha512-o8cI5Vqt6S6Y5mCI7yCkSQdiLQaLG5DMUpciJV3zReZwE+dA5KERxSVX8H3cPEhyKw21XwKGmIrg6YmN6M5uZA==",
       "dev": true,
       "dependencies": {
         "https-proxy-agent": "^7.0.0",
@@ -1103,15 +1217,6 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/array-union": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
-      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
-      "dev": true,
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/array.prototype.findlastindex": {
       "version": "1.2.5",
       "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
@@ -1375,9 +1480,9 @@
       "dev": true
     },
     "node_modules/browserslist": {
-      "version": "4.23.3",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz",
-      "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==",
+      "version": "4.24.2",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz",
+      "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==",
       "dev": true,
       "funding": [
         {
@@ -1394,10 +1499,10 @@
         }
       ],
       "dependencies": {
-        "caniuse-lite": "^1.0.30001646",
-        "electron-to-chromium": "^1.5.4",
+        "caniuse-lite": "^1.0.30001669",
+        "electron-to-chromium": "^1.5.41",
         "node-releases": "^2.0.18",
-        "update-browserslist-db": "^1.1.0"
+        "update-browserslist-db": "^1.1.1"
       },
       "bin": {
         "browserslist": "cli.js"
@@ -1477,9 +1582,9 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001655",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz",
-      "integrity": "sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==",
+      "version": "1.0.30001683",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001683.tgz",
+      "integrity": "sha512-iqmNnThZ0n70mNwvxpEC2nBJ037ZHZUoBI5Gorh1Mw6IlEAZujEoU1tXA628iZfzm7R9FvFzxbfdgml82a3k8Q==",
       "dev": true,
       "funding": [
         {
@@ -1668,12 +1773,6 @@
       "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
       "dev": true
     },
-    "node_modules/confusing-browser-globals": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz",
-      "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==",
-      "dev": true
-    },
     "node_modules/continuation-local-storage": {
       "version": "3.2.1",
       "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz",
@@ -1700,9 +1799,9 @@
       "dev": true
     },
     "node_modules/cross-spawn": {
-      "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
-      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
       "dev": true,
       "dependencies": {
         "path-key": "^3.1.0",
@@ -1880,30 +1979,6 @@
         "node": ">=0.3.1"
       }
     },
-    "node_modules/dir-glob": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
-      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
-      "dev": true,
-      "dependencies": {
-        "path-type": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/doctrine": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
-      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
-      "dev": true,
-      "dependencies": {
-        "esutils": "^2.0.2"
-      },
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
     "node_modules/eastasianwidth": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -1911,9 +1986,9 @@
       "dev": true
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.5.13",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz",
-      "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==",
+      "version": "1.5.63",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.63.tgz",
+      "integrity": "sha512-ddeXKuY9BHo/mw145axlyWjlJ1UBt4WK3AlvkT7W2AbqfRQoacVoRUCF6wL3uIx/8wT9oLKXzI+rFqHHscByaA==",
       "dev": true
     },
     "node_modules/emitter-listener": {
@@ -2116,87 +2191,62 @@
       }
     },
     "node_modules/eslint": {
-      "version": "8.57.1",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
-      "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
-      "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
+      "version": "9.15.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz",
+      "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.2.0",
-        "@eslint-community/regexpp": "^4.6.1",
-        "@eslint/eslintrc": "^2.1.4",
-        "@eslint/js": "8.57.1",
-        "@humanwhocodes/config-array": "^0.13.0",
+        "@eslint-community/regexpp": "^4.12.1",
+        "@eslint/config-array": "^0.19.0",
+        "@eslint/core": "^0.9.0",
+        "@eslint/eslintrc": "^3.2.0",
+        "@eslint/js": "9.15.0",
+        "@eslint/plugin-kit": "^0.2.3",
+        "@humanfs/node": "^0.16.6",
         "@humanwhocodes/module-importer": "^1.0.1",
-        "@nodelib/fs.walk": "^1.2.8",
-        "@ungap/structured-clone": "^1.2.0",
+        "@humanwhocodes/retry": "^0.4.1",
+        "@types/estree": "^1.0.6",
+        "@types/json-schema": "^7.0.15",
         "ajv": "^6.12.4",
         "chalk": "^4.0.0",
-        "cross-spawn": "^7.0.2",
+        "cross-spawn": "^7.0.5",
         "debug": "^4.3.2",
-        "doctrine": "^3.0.0",
         "escape-string-regexp": "^4.0.0",
-        "eslint-scope": "^7.2.2",
-        "eslint-visitor-keys": "^3.4.3",
-        "espree": "^9.6.1",
-        "esquery": "^1.4.2",
+        "eslint-scope": "^8.2.0",
+        "eslint-visitor-keys": "^4.2.0",
+        "espree": "^10.3.0",
+        "esquery": "^1.5.0",
         "esutils": "^2.0.2",
         "fast-deep-equal": "^3.1.3",
-        "file-entry-cache": "^6.0.1",
+        "file-entry-cache": "^8.0.0",
         "find-up": "^5.0.0",
         "glob-parent": "^6.0.2",
-        "globals": "^13.19.0",
-        "graphemer": "^1.4.0",
         "ignore": "^5.2.0",
         "imurmurhash": "^0.1.4",
         "is-glob": "^4.0.0",
-        "is-path-inside": "^3.0.3",
-        "js-yaml": "^4.1.0",
         "json-stable-stringify-without-jsonify": "^1.0.1",
-        "levn": "^0.4.1",
         "lodash.merge": "^4.6.2",
         "minimatch": "^3.1.2",
         "natural-compare": "^1.4.0",
-        "optionator": "^0.9.3",
-        "strip-ansi": "^6.0.1",
-        "text-table": "^0.2.0"
+        "optionator": "^0.9.3"
       },
       "bin": {
         "eslint": "bin/eslint.js"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
-        "url": "https://opencollective.com/eslint"
-      }
-    },
-    "node_modules/eslint-config-airbnb-base": {
-      "version": "15.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz",
-      "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==",
-      "dev": true,
-      "dependencies": {
-        "confusing-browser-globals": "^1.0.10",
-        "object.assign": "^4.1.2",
-        "object.entries": "^1.1.5",
-        "semver": "^6.3.0"
-      },
-      "engines": {
-        "node": "^10.12.0 || >=12.0.0"
+        "url": "https://eslint.org/donate"
       },
       "peerDependencies": {
-        "eslint": "^7.32.0 || ^8.2.0",
-        "eslint-plugin-import": "^2.25.2"
-      }
-    },
-    "node_modules/eslint-config-airbnb-base/node_modules/semver": {
-      "version": "6.3.1",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
-      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
-      "dev": true,
-      "bin": {
-        "semver": "bin/semver.js"
+        "jiti": "*"
+      },
+      "peerDependenciesMeta": {
+        "jiti": {
+          "optional": true
+        }
       }
     },
     "node_modules/eslint-config-prettier": {
@@ -2464,12 +2514,12 @@
       }
     },
     "node_modules/eslint-plugin-promise": {
-      "version": "6.6.0",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz",
-      "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==",
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.1.0.tgz",
+      "integrity": "sha512-8trNmPxdAy3W620WKDpaS65NlM5yAumod6XeC4LOb+jxlkG4IVcp68c6dXY2ev+uT4U1PtG57YDV6EGAXN0GbQ==",
       "dev": true,
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
         "url": "https://opencollective.com/eslint"
@@ -2528,16 +2578,28 @@
       }
     },
     "node_modules/eslint/node_modules/eslint-scope": {
-      "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
-      "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz",
+      "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==",
       "dev": true,
       "dependencies": {
         "esrecurse": "^4.3.0",
         "estraverse": "^5.2.0"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint/node_modules/eslint-visitor-keys": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+      "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
+      "dev": true,
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
         "url": "https://opencollective.com/eslint"
@@ -2577,17 +2639,29 @@
       }
     },
     "node_modules/espree": {
-      "version": "9.6.1",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
-      "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+      "version": "10.3.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
+      "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
       "dev": true,
       "dependencies": {
-        "acorn": "^8.9.0",
+        "acorn": "^8.14.0",
         "acorn-jsx": "^5.3.2",
-        "eslint-visitor-keys": "^3.4.1"
+        "eslint-visitor-keys": "^4.2.0"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/espree/node_modules/eslint-visitor-keys": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+      "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
+      "dev": true,
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
         "url": "https://opencollective.com/eslint"
@@ -2718,15 +2792,15 @@
       }
     },
     "node_modules/file-entry-cache": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
-      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+      "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
       "dev": true,
       "dependencies": {
-        "flat-cache": "^3.0.4"
+        "flat-cache": "^4.0.0"
       },
       "engines": {
-        "node": "^10.12.0 || >=12.0.0"
+        "node": ">=16.0.0"
       }
     },
     "node_modules/fill-range": {
@@ -2768,22 +2842,22 @@
       }
     },
     "node_modules/flat-cache": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
-      "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+      "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
       "dev": true,
       "dependencies": {
-        "flatted": "^3.1.0",
-        "rimraf": "^3.0.2"
+        "flatted": "^3.2.9",
+        "keyv": "^4.5.4"
       },
       "engines": {
-        "node": "^10.12.0 || >=12.0.0"
+        "node": ">=16"
       }
     },
     "node_modules/flatted": {
-      "version": "3.2.4",
-      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz",
-      "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==",
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz",
+      "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==",
       "dev": true
     },
     "node_modules/follow-redirects": {
@@ -2979,15 +3053,12 @@
       }
     },
     "node_modules/globals": {
-      "version": "13.24.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
-      "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+      "version": "15.12.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-15.12.0.tgz",
+      "integrity": "sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==",
       "dev": true,
-      "dependencies": {
-        "type-fest": "^0.20.2"
-      },
       "engines": {
-        "node": ">=8"
+        "node": ">=18"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
@@ -3009,26 +3080,6 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/globby": {
-      "version": "11.1.0",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
-      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
-      "dev": true,
-      "dependencies": {
-        "array-union": "^2.1.0",
-        "dir-glob": "^3.0.1",
-        "fast-glob": "^3.2.9",
-        "ignore": "^5.2.0",
-        "merge2": "^1.4.1",
-        "slash": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
     "node_modules/gopd": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
@@ -3592,15 +3643,6 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/is-path-inside": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
-      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/is-plain-obj": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
@@ -3799,6 +3841,12 @@
         "js-yaml": "bin/js-yaml.js"
       }
     },
+    "node_modules/json-buffer": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+      "dev": true
+    },
     "node_modules/json-parse-even-better-errors": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
@@ -3856,6 +3904,15 @@
         "setimmediate": "^1.0.5"
       }
     },
+    "node_modules/keyv": {
+      "version": "4.5.4",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+      "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+      "dev": true,
+      "dependencies": {
+        "json-buffer": "3.0.1"
+      }
+    },
     "node_modules/kind-of": {
       "version": "6.0.3",
       "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@@ -4248,20 +4305,6 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/object.entries": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz",
-      "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==",
-      "dev": true,
-      "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
     "node_modules/object.fromentries": {
       "version": "2.0.8",
       "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
@@ -4552,19 +4595,10 @@
       "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
       "dev": true
     },
-    "node_modules/path-type": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
-      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
-      "dev": true,
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/picocolors": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
-      "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
       "dev": true
     },
     "node_modules/picomatch": {
@@ -4850,21 +4884,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/rimraf": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-      "dev": true,
-      "dependencies": {
-        "glob": "^7.1.3"
-      },
-      "bin": {
-        "rimraf": "bin.js"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
-      }
-    },
     "node_modules/run-parallel": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -5093,15 +5112,6 @@
       "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
       "dev": true
     },
-    "node_modules/slash": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
-      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
-      "dev": true,
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/source-map": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -5382,12 +5392,6 @@
         "randombytes": "^2.1.0"
       }
     },
-    "node_modules/text-table": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
-      "dev": true
-    },
     "node_modules/textextensions": {
       "version": "5.16.0",
       "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-5.16.0.tgz",
@@ -5413,9 +5417,9 @@
       }
     },
     "node_modules/ts-api-utils": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
-      "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz",
+      "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==",
       "dev": true,
       "engines": {
         "node": ">=16"
@@ -5483,18 +5487,6 @@
         "node": ">= 0.8.0"
       }
     },
-    "node_modules/type-fest": {
-      "version": "0.20.2",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
-      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
     "node_modules/typed-array-buffer": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
@@ -5603,9 +5595,9 @@
       "dev": true
     },
     "node_modules/update-browserslist-db": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
-      "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz",
+      "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
       "dev": true,
       "funding": [
         {
@@ -5622,8 +5614,8 @@
         }
       ],
       "dependencies": {
-        "escalade": "^3.1.2",
-        "picocolors": "^1.0.1"
+        "escalade": "^3.2.0",
+        "picocolors": "^1.1.0"
       },
       "bin": {
         "update-browserslist-db": "cli.js"
@@ -5677,18 +5669,18 @@
       }
     },
     "node_modules/webpack": {
-      "version": "5.94.0",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz",
-      "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==",
+      "version": "5.96.1",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz",
+      "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==",
       "dev": true,
       "dependencies": {
-        "@types/estree": "^1.0.5",
+        "@types/eslint-scope": "^3.7.7",
+        "@types/estree": "^1.0.6",
         "@webassemblyjs/ast": "^1.12.1",
         "@webassemblyjs/wasm-edit": "^1.12.1",
         "@webassemblyjs/wasm-parser": "^1.12.1",
-        "acorn": "^8.7.1",
-        "acorn-import-attributes": "^1.9.5",
-        "browserslist": "^4.21.10",
+        "acorn": "^8.14.0",
+        "browserslist": "^4.24.0",
         "chrome-trace-event": "^1.0.2",
         "enhanced-resolve": "^5.17.1",
         "es-module-lexer": "^1.2.1",
@@ -5798,15 +5790,6 @@
         "node": ">=10.13.0"
       }
     },
-    "node_modules/webpack/node_modules/acorn-import-attributes": {
-      "version": "1.9.5",
-      "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
-      "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
-      "dev": true,
-      "peerDependencies": {
-        "acorn": "^8"
-      }
-    },
     "node_modules/which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
index 2470e025..a318e922 100644
--- a/package.json
+++ b/package.json
@@ -374,16 +374,6 @@
           "when": "view == ObjectScriptExplorer && viewItem =~ /^dataNode:/",
           "group": "1_objectscript_modify"
         },
-        {
-          "command": "vscode-objectscript.serverCommands.contextSourceControl",
-          "when": "view == ObjectScriptProjectsExplorer && viewItem =~ /^dataNode:/",
-          "group": "9_objectscript_servercommand@1"
-        },
-        {
-          "command": "vscode-objectscript.serverCommands.contextOther",
-          "when": "view == ObjectScriptProjectsExplorer && viewItem =~ /^dataNode:/",
-          "group": "9_objectscript_servercommand@2"
-        },
         {
           "command": "vscode-objectscript.explorer.otherNamespace",
           "when": "view == ObjectScriptExplorer && viewItem =~ /^serverNode((?!:extra:).)*$/",
@@ -1425,7 +1415,7 @@
         "objectscript.overwriteServerChanges": {
           "type": "boolean",
           "default": false,
-          "description": "Overwrite a changed server version without confirmation when importing the local file."
+          "description": "Controls whether synching a file to the server in a client-side workspace folder will always overwrite the server version, even if it changed since it was last accessed."
         },
         "objectscript.autoPreviewXML": {
           "type": "boolean",
@@ -1487,9 +1477,9 @@
           "default": false
         },
         "objectscript.autoAdjustName": {
-          "markdownDescription": "Automatically modify the class name or ROUTINE header to match the file's path when copying or creating a new file. Does not affect `isfs` files.",
+          "markdownDescription": "Automatically modify the class name or ROUTINE header of a file in a client-side workspace folder to match the file's path when copying or creating a new file. Uses the `#objectscript.export#` settings to determine the new name.",
           "type": "boolean",
-          "default": true
+          "default": false
         },
         "objectscript.compileOnSave": {
           "description": "Automatically compile an InterSystems file when saved in the editor.",
@@ -1521,11 +1511,6 @@
             "pattern": "^[^.]+$"
           }
         },
-        "objectscript.importOnSave": {
-          "description": "Automatically save a client-side InterSystems file on the server when saved in the editor.",
-          "type": "boolean",
-          "default": true
-        },
         "objectscript.showGeneratedFileDecorations": {
           "description": "Controls whether a badge is shown in the file explorer and open editors view for generated files.",
           "type": "boolean",
@@ -1616,6 +1601,11 @@
             "The step buttons execute an entire line."
           ],
           "default": "command"
+        },
+        "objectscript.syncLocalChanges": {
+          "description": "Controls whether files in client-side workspace folders that are created, deleted, or changed are automatically synced to the server. Synching will occur whether changes are made due to user actions in VS Code (for example, saving a file that's being actively edited) or outside of VS Code (for example, deleting a file from the OS file explorer while VS Code has its folder open).",
+          "type": "boolean",
+          "default": true
         }
       }
     },
@@ -1781,35 +1771,36 @@
     "postinstall": "npm run download-api"
   },
   "devDependencies": {
+    "@eslint/js": "^9.15.0",
     "@intersystems-community/intersystems-servermanager": "^3.8.0",
     "@types/istextorbinary": "2.3.1",
     "@types/minimatch": "5.1.2",
     "@types/mocha": "^7.0.2",
-    "@types/node": "20.16.5",
+    "@types/node": "20.17.6",
     "@types/semver": "7.5.4",
     "@types/vscode": "1.93.0",
     "@types/ws": "8.5.4",
     "@types/xmldom": "^0.1.29",
-    "@typescript-eslint/eslint-plugin": "^7.12.0",
-    "@typescript-eslint/parser": "^7.12.0",
-    "@vscode/dts": "^0.4.0",
-    "@vscode/test-electron": "^2.4.0",
-    "eslint": "^8.56.0",
-    "eslint-config-airbnb-base": "^15.0.0",
+    "@typescript-eslint/eslint-plugin": "^8.15.0",
+    "@typescript-eslint/parser": "^8.15.0",
+    "@vscode/debugadapter-testsupport": "^1.67.0",
+    "@vscode/dts": "^0.4.1",
+    "@vscode/test-electron": "^2.4.1",
+    "eslint": "^9.15.0",
     "eslint-config-prettier": "^9.1.0",
-    "eslint-plugin-import": "^2.29.1",
-    "eslint-plugin-jsx-a11y": "^6.8.0",
+    "eslint-plugin-import": "^2.31.0",
+    "eslint-plugin-jsx-a11y": "^6.10.2",
     "eslint-plugin-node": "^11.1.0",
-    "eslint-plugin-prettier": "^5.1.3",
-    "eslint-plugin-promise": "^6.2.0",
+    "eslint-plugin-prettier": "^5.2.1",
+    "eslint-plugin-promise": "^7.1.0",
     "glob": "^7.1.6",
+    "globals": "^15.12.0",
     "mocha": "^9.1.3",
     "path-browserify": "^1.0.1",
     "prettier": "^3.3.1",
     "ts-loader": "^9.5.1",
     "typescript": "^5.6.2",
-    "@vscode/debugadapter-testsupport": "^1.67.0",
-    "webpack": "^5.94.0",
+    "webpack": "^5.96.1",
     "webpack-cli": "^5.1.4"
   },
   "dependencies": {
diff --git a/src/api/index.ts b/src/api/index.ts
index 53598ab0..d1b3e6f4 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -22,7 +22,7 @@ import * as Atelier from "./atelier";
 // Map of the authRequest promises for each username@host:port target to avoid concurrency issues
 const authRequestMap = new Map<string, Promise<any>>();
 
-export interface ConnectionSettings {
+interface ConnectionSettings {
   serverName: string;
   active: boolean;
   apiVersion: number;
@@ -261,13 +261,9 @@ export class AtelierAPI {
     minVersion: number,
     method: string,
     path?: string,
-    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
     body?: any,
-    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
     params?: any,
-    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
     headers?: any,
-    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
     options?: any
   ): Promise<any> {
     const { active, apiVersion, host, port, username, password, https } = this.config;
diff --git a/src/commands/compile.ts b/src/commands/compile.ts
index 55f62b58..73fd698c 100644
--- a/src/commands/compile.ts
+++ b/src/commands/compile.ts
@@ -12,6 +12,7 @@ import {
 } from "../extension";
 import { DocumentContentProvider } from "../providers/DocumentContentProvider";
 import {
+  base64EncodeContent,
   classNameRegex,
   cspAppsForUri,
   CurrentBinaryFile,
@@ -19,6 +20,7 @@ import {
   CurrentFile,
   currentFileFromContent,
   CurrentTextFile,
+  exportedUris,
   handleError,
   isClassDeployed,
   notIsfs,
@@ -27,10 +29,8 @@ import {
   routineNameTypeRegex,
   throttleRequests,
 } from "../utils";
-import { PackageNode } from "../explorer/models/packageNode";
-import { NodeBase } from "../explorer/models/nodeBase";
-import { RootNode } from "../explorer/models/rootNode";
 import { StudioActions } from "./studio";
+import { NodeBase, PackageNode, RootNode } from "../explorer/nodes";
 
 async function compileFlags(): Promise<string> {
   const defaultFlags = config().compileFlags;
@@ -105,16 +105,8 @@ export async function importFile(
       content.pop();
     }
   } else {
-    // Base64 encoding must be in chunk size multiple of 3 and within the server's potential 32K string limit
-    // Output is 4 chars for each 3 input, so 24573/3*4 = 32764
-    const chunkSize = 24573;
-    let start = 0;
-    content = [];
     enc = true;
-    while (start < file.content.byteLength) {
-      content.push(file.content.toString("base64", start, start + chunkSize));
-      start += chunkSize;
-    }
+    content = base64EncodeContent(file.content);
   }
   const mtime = await checkChangedOnServer(file);
   ignoreConflict =
@@ -132,11 +124,9 @@ export async function importFile(
       },
       ignoreConflict
     )
-    .then(() => {
-      // Clear cache entry
-      workspaceState.update(`${file.uniqueId}:mtime`, undefined);
-      // Create fresh cache entry
-      checkChangedOnServer(file, true);
+    .then((data) => {
+      // Update cache entry
+      workspaceState.update(`${file.uniqueId}:mtime`, Number(new Date(data.result.ts + "Z")));
 
       // In case another extension has used an 'objectscript://' uri to load a document read-only from the server,
       // make it reload with what we just imported to the server.
@@ -236,6 +226,7 @@ export async function loadChanges(files: (CurrentTextFile | CurrentBinaryFile)[]
             file.uri,
             Buffer.isBuffer(content) ? content : new TextEncoder().encode(content.join("\n"))
           );
+          exportedUris.push(file.uri.toString());
         } else if (filesystemSchemas.includes(file.uri.scheme)) {
           fileSystemProvider.fireFileChanged(file.uri);
         }
@@ -257,7 +248,7 @@ export async function compile(docs: CurrentFile[], flags?: string): Promise<any>
       {
         cancellable: true,
         location: vscode.ProgressLocation.Notification,
-        title: `Compiling: ${docs.length === 1 ? docs.map((el) => el.name).join(", ") : docs.length + " files"}`,
+        title: `Compiling: ${docs.length == 1 ? docs[0].name : docs.length + " files"}`,
       },
       (progress, token: vscode.CancellationToken) =>
         api
diff --git a/src/commands/delete.ts b/src/commands/delete.ts
index 3d4bc47a..5d73ec64 100644
--- a/src/commands/delete.ts
+++ b/src/commands/delete.ts
@@ -1,14 +1,12 @@
 import * as vscode from "vscode";
 
 import { AtelierAPI } from "../api";
-import { PackageNode } from "../explorer/models/packageNode";
-import { RootNode } from "../explorer/models/rootNode";
-import { NodeBase } from "../explorer/models/nodeBase";
 import { FILESYSTEM_SCHEMA, explorerProvider } from "../extension";
 import { outputChannel, uriOfWorkspaceFolder } from "../utils";
 import { OtherStudioAction, fireOtherStudioAction } from "./studio";
 import { DocumentContentProvider } from "../providers/DocumentContentProvider";
 import { UserAction } from "../api/atelier";
+import { NodeBase, PackageNode, RootNode } from "../explorer/nodes";
 
 function deleteList(items: string[], workspaceFolder: string, namespace: string): Promise<any> {
   if (!items || !items.length) {
diff --git a/src/commands/export.ts b/src/commands/export.ts
index 21d4d65b..23d5df70 100644
--- a/src/commands/export.ts
+++ b/src/commands/export.ts
@@ -5,6 +5,7 @@ import { config, explorerProvider, OBJECTSCRIPT_FILE_SCHEMA, schemas, workspaceS
 import {
   currentFile,
   currentFileFromContent,
+  exportedUris,
   handleError,
   notNull,
   outputChannel,
@@ -12,18 +13,10 @@ import {
   throttleRequests,
   uriOfWorkspaceFolder,
 } from "../utils";
-import { NodeBase } from "../explorer/models/nodeBase";
 import { pickDocuments } from "../utils/documentPicker";
+import { NodeBase } from "../explorer/nodes";
 
-/**
- * Array of stringified `Uri`s that have been exported.
- * Used by the documentIndex to determine if a created/changed
- * file needs to be synced with the server. If the documentIndex
- * finds a match in this array, the element is then removed.
- */
-export const exportedUris: string[] = [];
-
-export const getCategory = (fileName: string, addCategory: any | boolean): string => {
+export function getCategory(fileName: string, addCategory: any | boolean): string {
   const fileExt = fileName.split(".").pop().toLowerCase();
   if (typeof addCategory === "object") {
     for (const pattern of Object.keys(addCategory)) {
@@ -45,9 +38,9 @@ export const getCategory = (fileName: string, addCategory: any | boolean): strin
     default:
       return "oth";
   }
-};
+}
 
-export const getFileName = (
+export function getFileName(
   folder: string,
   name: string,
   split: boolean,
@@ -56,7 +49,7 @@ export const getFileName = (
     [key: string]: string;
   },
   sep = path.sep
-): string => {
+): string {
   if (name.includes("/")) {
     // This is a file from a web application
     const nameArr: string[] = name.split("/");
@@ -65,12 +58,7 @@ export const getFileName = (
   } else {
     let fileNameArray: string[];
     let fileExt: string;
-    if (/\.dfi$/i.test(name)) {
-      // This is a DFI file
-      fileNameArray = name.split("-");
-      fileNameArray.push(fileNameArray.pop().slice(0, -4));
-      fileExt = "dfi";
-    } else if (/\.(?:cls|mac|int|inc)$/.test(name)) {
+    if (/\.(?:cls|mac|int|inc)$/.test(name)) {
       // This is a class, routine or include file
       if (map) {
         for (const pattern of Object.keys(map)) {
@@ -95,14 +83,13 @@ export const getFileName = (
     }
     return [folder, cat, name].filter(notNull).join(sep);
   }
-};
+}
 
 async function exportFile(wsFolderUri: vscode.Uri, namespace: string, name: string, fileName: string): Promise<void> {
   const api = new AtelierAPI(wsFolderUri);
   api.setNamespace(namespace);
   let fileUri = vscode.Uri.file(fileName);
   if (wsFolderUri.scheme != "file") fileUri = wsFolderUri.with({ path: fileUri.path });
-  exportedUris.push(fileUri.toString());
   const log = (status: string) =>
     outputChannel.appendLine(`Export '${name}' to '${fileUri.toString(true)}' - ${status}`);
 
@@ -120,16 +107,17 @@ async function exportFile(wsFolderUri: vscode.Uri, namespace: string, name: stri
       const serverTime = Number(new Date(data.result.ts + "Z"));
       await workspaceState.update(`${file.uniqueId}:mtime`, serverTime);
     };
-
     if (Buffer.isBuffer(content)) {
       // This is a binary file
       await vscode.workspace.fs.writeFile(fileUri, content);
+      exportedUris.push(fileUri.toString());
       await recordMtime();
       log("Success");
     } else {
       // This is a text file
       const joinedContent = content.join("\n");
       await vscode.workspace.fs.writeFile(fileUri, new TextEncoder().encode(joinedContent));
+      exportedUris.push(fileUri.toString());
       await recordMtime();
       log("Success");
     }
diff --git a/src/commands/newFile.ts b/src/commands/newFile.ts
index e4e6c94c..81e6adb7 100644
--- a/src/commands/newFile.ts
+++ b/src/commands/newFile.ts
@@ -5,7 +5,6 @@ import { FILESYSTEM_SCHEMA } from "../extension";
 import { DocumentContentProvider } from "../providers/DocumentContentProvider";
 import { handleError } from "../utils";
 import { getFileName } from "./export";
-import { importFolder } from "./compile";
 import { getUrisForDocument } from "../utils/documentIndex";
 
 interface InputStepItem extends vscode.QuickPickItem {
@@ -860,14 +859,6 @@ ClassMethod %OnDashboardAction(pAction As %String, pContext As %ZEN.proxyObject)
     if (clsUri && clsContent) {
       // Write the file content
       await vscode.workspace.fs.writeFile(clsUri, new TextEncoder().encode(clsContent.trimStart()));
-      if (
-        clsUri.scheme != FILESYSTEM_SCHEMA &&
-        api &&
-        vscode.workspace.getConfiguration("objectscript", wsFolder).get("importOnSave")
-      ) {
-        // Save this local file on the server
-        await importFolder(clsUri, true);
-      }
       // Show the file
       vscode.window.showTextDocument(clsUri, { preview: false });
     }
diff --git a/src/commands/project.ts b/src/commands/project.ts
index fc87607b..391cb2b7 100644
--- a/src/commands/project.ts
+++ b/src/commands/project.ts
@@ -1,11 +1,5 @@
 import * as vscode from "vscode";
 import { AtelierAPI } from "../api";
-import { ClassNode } from "../explorer/models/classNode";
-import { CSPFileNode } from "../explorer/models/cspFileNode";
-import { NodeBase } from "../explorer/models/nodeBase";
-import { ProjectNode } from "../explorer/models/projectNode";
-import { ProjectRootNode } from "../explorer/models/projectRootNode";
-import { RoutineNode } from "../explorer/models/routineNode";
 import { config, filesystemSchemas, projectsExplorerProvider, schemas } from "../extension";
 import { compareConns } from "../providers/DocumentContentProvider";
 import { isCSPFile } from "../providers/FileSystemProvider/FileSystemProvider";
@@ -13,6 +7,7 @@ import { handleError, notIsfs, notNull } from "../utils";
 import { pickServerAndNamespace } from "./addServerNamespaceToWorkspace";
 import { exportList } from "./export";
 import { OtherStudioAction, StudioActions } from "./studio";
+import { NodeBase, ProjectNode, ProjectRootNode, RoutineNode, CSPFileNode, ClassNode } from "../explorer/nodes";
 
 export interface ProjectItem {
   Name: string;
@@ -1048,7 +1043,6 @@ function isfsFolderForProject(project: string, nodeOrWorkspaceFolder: string | N
  */
 export async function addIsfsFileToProject(
   project: string,
-  uri: vscode.Uri,
   fileName: string,
   csp: boolean,
   api: AtelierAPI
diff --git a/src/commands/serverActions.ts b/src/commands/serverActions.ts
index eff4e261..9e4711bb 100644
--- a/src/commands/serverActions.ts
+++ b/src/commands/serverActions.ts
@@ -3,9 +3,9 @@ import {
   config,
   workspaceState,
   checkConnection,
-  FILESYSTEM_SCHEMA,
-  FILESYSTEM_READONLY_SCHEMA,
   explorerProvider,
+  filesystemSchemas,
+  FILESYSTEM_SCHEMA,
 } from "../extension";
 import {
   connectionTarget,
@@ -47,7 +47,7 @@ export async function serverActions(): Promise<void> {
       detail: "Force attempt to connect to the server",
     });
 
-    // Switching namespace makes only sense for non-ISFS folders
+    // Switching namespace only makes sense for client-side folders
     if (wsUri && notIsfs(wsUri)) {
       actions.push({
         id: "switchNamespace",
@@ -193,15 +193,19 @@ export async function serverActions(): Promise<void> {
     detail: "Select a Studio Add-in to open",
   });
   if (
-    (!vscode.window.activeTextEditor && wsUri && notIsfs(wsUri)) ||
-    vscode.window.activeTextEditor.document.uri.scheme === FILESYSTEM_SCHEMA ||
-    vscode.window.activeTextEditor.document.uri.scheme === FILESYSTEM_READONLY_SCHEMA
+    (!vscode.window.activeTextEditor && wsUri && wsUri.scheme == FILESYSTEM_SCHEMA) ||
+    vscode.window.activeTextEditor?.document.uri.scheme == FILESYSTEM_SCHEMA
   ) {
     actions.push({
       id: "serverSourceControlMenu",
       label: "Server Source Control...",
       detail: "Pick server-side source control action",
     });
+  }
+  if (
+    (!vscode.window.activeTextEditor && wsUri && filesystemSchemas.includes(wsUri.scheme)) ||
+    filesystemSchemas.includes(vscode.window.activeTextEditor?.document.uri.scheme)
+  ) {
     actions.push({
       id: "serverCommandMenu",
       label: "Server Command Menu...",
diff --git a/src/commands/studio.ts b/src/commands/studio.ts
index 182b98bb..2f9a5da2 100644
--- a/src/commands/studio.ts
+++ b/src/commands/studio.ts
@@ -1,18 +1,10 @@
 import * as vscode from "vscode";
 import { AtelierAPI } from "../api";
-import { config, iscIcon } from "../extension";
-import { outputChannel, outputConsole, getServerName, notIsfs, handleError } from "../utils";
+import { iscIcon } from "../extension";
+import { outputChannel, outputConsole, getServerName, notIsfs, handleError, openCustomEditors } from "../utils";
 import { DocumentContentProvider } from "../providers/DocumentContentProvider";
-import { ClassNode } from "../explorer/models/classNode";
-import { PackageNode } from "../explorer/models/packageNode";
-import { RoutineNode } from "../explorer/models/routineNode";
-import { importAndCompile } from "./compile";
-import { ProjectNode } from "../explorer/models/projectNode";
-import { openCustomEditors } from "../providers/RuleEditorProvider";
 import { UserAction } from "../api/atelier";
 
-export let documentBeingProcessed: vscode.TextDocument = null;
-
 export enum OtherStudioAction {
   AttemptedEdit = 0,
   CreatedNewDocument = 1,
@@ -71,15 +63,11 @@ export class StudioActions {
   private name: string;
   public projectEditAnswer?: string;
 
-  public constructor(uriOrNode?: vscode.Uri | PackageNode | ClassNode | RoutineNode) {
-    if (uriOrNode instanceof vscode.Uri) {
-      this.uri = uriOrNode;
-      this.name = getServerName(uriOrNode);
-      this.api = new AtelierAPI(uriOrNode);
-    } else if (uriOrNode) {
-      this.api = new AtelierAPI(uriOrNode.workspaceFolderUri || uriOrNode.workspaceFolder);
-      this.api.setNamespace(uriOrNode.namespace);
-      this.name = uriOrNode instanceof PackageNode ? uriOrNode.fullName + ".PKG" : uriOrNode.fullName;
+  public constructor(uri?: vscode.Uri) {
+    if (uri instanceof vscode.Uri) {
+      this.uri = uri;
+      this.name = getServerName(uri);
+      this.api = new AtelierAPI(uri);
     } else {
       this.api = new AtelierAPI();
     }
@@ -131,7 +119,7 @@ export class StudioActions {
       outputChannel.appendLine(errorText);
       outputChannel.show(true);
     }
-    if (config().studioActionDebugOutput) {
+    if (vscode.workspace.getConfiguration("objectscript").get("studioActionDebugOutput")) {
       outputChannel.appendLine(JSON.stringify(userAction));
     }
     switch (serverAction) {
@@ -304,7 +292,7 @@ export class StudioActions {
       ? [type.toString(), action.id, this.name, answer, msg]
       : [type.toString(), action.id, this.name, selectedText];
 
-    if (config().studioActionDebugOutput) {
+    if (vscode.workspace.getConfiguration("objectscript").get("studioActionDebugOutput")) {
       outputChannel.appendLine(`${query.slice(0, query.indexOf("("))}(${JSON.stringify(parameters).slice(1, -1)})`);
     }
 
@@ -319,8 +307,29 @@ export class StudioActions {
           this.api
             .actionQuery(query, parameters)
             .then(async (data) => {
-              if (action.save && action.id != "6" /* No save for import list */) {
-                await this.processSaveFlag(action.save);
+              if (action.save && action.id != "6" && !this.name.endsWith(".PRJ") && this.uri) {
+                // Save the requested documents.
+                // Ignore the save flag if this is a project or bulk import action.
+                const bitString: string = action.save.toString().padStart(3, "0");
+                // Save all documents
+                if (bitString.charAt(2) == "1") {
+                  // Save all documents in this workspace folder
+                  const wsFolderUriString = vscode.workspace.getWorkspaceFolder(this.uri)?.uri.toString();
+                  if (wsFolderUriString) {
+                    await Promise.allSettled(
+                      vscode.workspace.textDocuments.map((td) =>
+                        td.isDirty && vscode.workspace.getWorkspaceFolder(td.uri)?.uri.toString() == wsFolderUriString
+                          ? td.save()
+                          : undefined
+                      )
+                    );
+                  }
+                } else if (bitString.charAt(0) == "1") {
+                  // Save just the current document
+                  const uriString = this.uri.toString();
+                  const textDocument = vscode.workspace.textDocuments.find((td) => td.uri.toString() == uriString);
+                  if (textDocument?.isDirty) await textDocument.save();
+                }
               }
               if (!afterUserAction) {
                 outputConsole(data.console);
@@ -461,32 +470,6 @@ export class StudioActions {
     }
   }
 
-  private async processSaveFlag(saveFlag: number) {
-    const bitString = saveFlag.toString().padStart(3, "0");
-    const saveAndCompile = async (document: vscode.TextDocument) => {
-      if (document.isDirty) {
-        // Prevent onDidSave from compiling the file
-        // in order to await the importAndCompile function
-        documentBeingProcessed = document;
-        await document.save();
-        await importAndCompile(false, document);
-        documentBeingProcessed = null;
-      }
-    };
-
-    // Save the current document
-    if (bitString.charAt(0) === "1") {
-      await saveAndCompile(vscode.window.activeTextEditor.document);
-    }
-
-    // Save all documents
-    if (bitString.charAt(2) === "1") {
-      for (const document of vscode.workspace.textDocuments) {
-        await saveAndCompile(document);
-      }
-    }
-  }
-
   public async isSourceControlEnabled(): Promise<boolean> {
     return this.api
       .actionQuery("SELECT %Atelier_v1_Utils.Extension_ExtensionEnabled() AS Enabled", [])
@@ -528,27 +511,25 @@ async function _mainMenu(sourceControl: boolean, uri?: vscode.Uri): Promise<void
   }
 }
 
-export async function contextCommandMenu(node: PackageNode | ClassNode | RoutineNode | ProjectNode): Promise<void> {
-  return _contextMenu(false, node);
+export async function contextCommandMenu(uri?: vscode.Uri): Promise<void> {
+  return _contextMenu(false, uri);
 }
 
-export async function contextSourceControlMenu(
-  node: PackageNode | ClassNode | RoutineNode | ProjectNode
-): Promise<void> {
-  return _contextMenu(true, node);
+export async function contextSourceControlMenu(uri?: vscode.Uri): Promise<void> {
+  return _contextMenu(true, uri);
 }
 
-export async function _contextMenu(sourceControl: boolean, node: PackageNode | ClassNode | RoutineNode): Promise<void> {
-  const nodeOrUri = node || vscode.window.activeTextEditor?.document.uri;
-  if (!nodeOrUri || (nodeOrUri instanceof vscode.Uri && notIsfs(nodeOrUri))) return;
-  const studioActions = new StudioActions(nodeOrUri);
+async function _contextMenu(sourceControl: boolean, uri?: vscode.Uri): Promise<void> {
+  uri = uri || vscode.window.activeTextEditor?.document.uri;
+  if (!uri || !(uri instanceof vscode.Uri) || notIsfs(uri)) return;
+  const studioActions = new StudioActions(uri);
   if (studioActions) {
     if (await studioActions.isSourceControlEnabled()) {
       return studioActions.getMenu(StudioMenuType.Context, sourceControl);
     } else {
       const serverInfo = studioActions.getServerInfo();
       vscode.window.showInformationMessage(
-        `No source control class is configured for namespace "${serverInfo.namespace}" on server ${serverInfo.server}.`,
+        `No source control class is configured for namespace '${serverInfo.namespace}' on server '${serverInfo.server}'.`,
         "Dismiss"
       );
     }
@@ -557,7 +538,7 @@ export async function _contextMenu(sourceControl: boolean, node: PackageNode | C
 
 export async function fireOtherStudioAction(
   action: OtherStudioAction,
-  uri?: vscode.Uri,
+  uri: vscode.Uri,
   userAction?: UserAction
 ): Promise<void> {
   if (vscode.workspace.getConfiguration("objectscript.serverSourceControl", uri)?.get("disableOtherActionTriggers")) {
@@ -566,7 +547,7 @@ export async function fireOtherStudioAction(
   const studioActions = new StudioActions(uri);
   return (
     studioActions &&
-    !openCustomEditors.includes(uri?.toString()) && // The custom editor will handle all server-side source control interactions
+    !openCustomEditors.includes(uri.toString()) && // The custom editor will handle all server-side source control interactions
     studioActions.fireOtherStudioAction(action, userAction)
   );
 }
diff --git a/src/debug/debugSession.ts b/src/debug/debugSession.ts
index bbfb6268..310f6425 100644
--- a/src/debug/debugSession.ts
+++ b/src/debug/debugSession.ts
@@ -921,7 +921,7 @@ export class ObjectScriptDebugSession extends LoggingDebugSession {
     response: DebugProtocol.Response,
     codeOrMessage: number | DebugProtocol.Message,
     format?: string,
-    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+
     variables?: any,
     dest?: ErrorDestination
   ): void;
diff --git a/src/debug/xdebugConnection.ts b/src/debug/xdebugConnection.ts
index 5f986afa..bc513045 100644
--- a/src/debug/xdebugConnection.ts
+++ b/src/debug/xdebugConnection.ts
@@ -123,13 +123,10 @@ export abstract class Breakpoint {
   public static fromXml(breakpointNode: Element, connection: Connection): Breakpoint {
     switch (breakpointNode.getAttribute("type")) {
       case "line":
-        // eslint-disable-next-line @typescript-eslint/no-use-before-define
         return new LineBreakpoint(breakpointNode, connection);
       case "conditional":
-        // eslint-disable-next-line @typescript-eslint/no-use-before-define
         return new ConditionalBreakpoint(breakpointNode, connection);
       case "watch":
-        // eslint-disable-next-line @typescript-eslint/no-use-before-define
         return new Watchpoint(breakpointNode, connection);
       default:
         throw new Error(`Invalid type ${breakpointNode.getAttribute("type")}`);
diff --git a/src/explorer/explorer.ts b/src/explorer/explorer.ts
index 0b10d9e6..3337140b 100644
--- a/src/explorer/explorer.ts
+++ b/src/explorer/explorer.ts
@@ -1,37 +1,9 @@
 import * as vscode from "vscode";
-import { NodeBase } from "./models/nodeBase";
-
 import { AtelierAPI } from "../api";
 import { config, documentContentProvider, OBJECTSCRIPT_FILE_SCHEMA, projectsExplorerProvider } from "../extension";
-import { WorkspaceNode } from "./models/workspaceNode";
 import { handleError, notIsfs } from "../utils";
-import { DocumentContentProvider } from "../providers/DocumentContentProvider";
 import { StudioActions, OtherStudioAction } from "../commands/studio";
-
-/** Get the URI for this leaf node */
-export function getLeafNodeUri(node: NodeBase, forceServerCopy = false): vscode.Uri {
-  if (node.workspaceFolder == undefined) {
-    // Should only be the case for leaf nodes in the projects explorer
-    // that are children of an extra server namespace node
-    return DocumentContentProvider.getUri(
-      node.fullName,
-      undefined,
-      undefined,
-      true,
-      node.workspaceFolderUri,
-      forceServerCopy
-    );
-  } else {
-    return DocumentContentProvider.getUri(
-      node.fullName,
-      node.workspaceFolder,
-      node.namespace,
-      undefined,
-      undefined,
-      forceServerCopy
-    );
-  }
-}
+import { NodeBase, WorkspaceNode } from "./nodes";
 
 /** Use for detecting doubleclick */
 let lastOpened: { uri: vscode.Uri; date: Date };
diff --git a/src/explorer/models/classNode.ts b/src/explorer/models/classNode.ts
deleted file mode 100644
index d842cbd3..00000000
--- a/src/explorer/models/classNode.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import * as vscode from "vscode";
-import { NodeBase, NodeOptions } from "./nodeBase";
-import { config } from "../../extension";
-import { getLeafNodeUri } from "../explorer";
-import { notIsfs } from "../../utils";
-
-export class ClassNode extends NodeBase {
-  public static readonly contextValue: string = "dataNode:classNode";
-  public constructor(label: string, fullName: string, options: NodeOptions) {
-    super(label, fullName, options);
-  }
-
-  public getTreeItem(): vscode.TreeItem {
-    const displayName: string = this.label;
-    const itemUri = getLeafNodeUri(this);
-    const isLocalFile = notIsfs(itemUri);
-    const showServerCopy: boolean = config("explorer.alwaysShowServerCopy", this.workspaceFolder);
-    const serverCopyUri = getLeafNodeUri(this, true);
-
-    return {
-      collapsibleState: vscode.TreeItemCollapsibleState.None,
-      command: {
-        arguments: [isLocalFile && !showServerCopy ? itemUri : serverCopyUri, this.options.project, this.fullName],
-        command: "vscode-objectscript.explorer.open",
-        title: "Open Class",
-      },
-      resourceUri: isLocalFile && !showServerCopy ? itemUri : undefined,
-      contextValue: "dataNode:classNode",
-      label: `${displayName}`,
-      tooltip: isLocalFile && !showServerCopy ? undefined : this.fullName,
-    };
-  }
-}
diff --git a/src/explorer/models/cspFileNode.ts b/src/explorer/models/cspFileNode.ts
deleted file mode 100644
index b8993894..00000000
--- a/src/explorer/models/cspFileNode.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import * as vscode from "vscode";
-import { NodeBase, NodeOptions } from "./nodeBase";
-import { config } from "../../extension";
-import { getLeafNodeUri } from "../explorer";
-import { notIsfs } from "../../utils";
-
-export class CSPFileNode extends NodeBase {
-  public static readonly contextValue: string = "dataNode:cspFileNode";
-  public constructor(label: string, fullName: string, options: NodeOptions) {
-    super(label, fullName, options);
-  }
-
-  public getTreeItem(): vscode.TreeItem {
-    const displayName: string = this.label;
-    const itemUri = getLeafNodeUri(this);
-    const isLocalFile = notIsfs(itemUri);
-    const showServerCopy: boolean = config("explorer.alwaysShowServerCopy", this.workspaceFolder);
-    const serverCopyUri = getLeafNodeUri(this, true);
-
-    return {
-      collapsibleState: vscode.TreeItemCollapsibleState.None,
-      command: {
-        arguments: [isLocalFile && !showServerCopy ? itemUri : serverCopyUri, this.options.project, this.fullName],
-        command: "vscode-objectscript.explorer.open",
-        title: "Open File",
-      },
-      resourceUri: isLocalFile && !showServerCopy ? itemUri : undefined,
-      contextValue: CSPFileNode.contextValue,
-      label: `${displayName}`,
-      tooltip: isLocalFile && !showServerCopy ? undefined : this.fullName,
-    };
-  }
-}
diff --git a/src/explorer/models/nodeBase.ts b/src/explorer/models/nodeBase.ts
deleted file mode 100644
index 0fb52a9a..00000000
--- a/src/explorer/models/nodeBase.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import * as vscode from "vscode";
-import { currentWorkspaceFolder, uriOfWorkspaceFolder } from "../../utils";
-import { AtelierAPI } from "../../api";
-
-export interface NodeOptions {
-  extraNode?: boolean;
-  generated?: boolean;
-  system?: boolean;
-  namespace?: string;
-  workspaceFolder?: string;
-  workspaceFolderUri?: vscode.Uri;
-  project?: string;
-}
-
-export class NodeBase {
-  public readonly options: NodeOptions;
-  public readonly label: string;
-  public readonly fullName: string;
-  public readonly workspaceFolder: string;
-  public readonly conn: any;
-  public readonly extraNode: boolean;
-  public readonly namespace: string;
-  public readonly workspaceFolderUri: vscode.Uri;
-
-  protected constructor(label: string, fullName: string, options: NodeOptions) {
-    this.options = {
-      generated: false,
-      extraNode: false,
-      ...options,
-    };
-    this.label = label;
-    this.fullName = fullName;
-    const { workspaceFolder, namespace, extraNode, workspaceFolderUri } = options;
-    if (workspaceFolderUri) {
-      // Used by Projects tree
-      this.workspaceFolderUri = workspaceFolderUri;
-      this.workspaceFolder = vscode.workspace.getWorkspaceFolder(workspaceFolderUri)?.name;
-      const api = new AtelierAPI(workspaceFolderUri);
-      this.conn = api.config;
-    } else {
-      this.workspaceFolder = workspaceFolder || currentWorkspaceFolder();
-      this.workspaceFolderUri = uriOfWorkspaceFolder(this.workspaceFolder);
-      const api = new AtelierAPI(workspaceFolder);
-      this.conn = api.config;
-    }
-    this.namespace = namespace || this.conn.ns;
-    this.extraNode = extraNode;
-  }
-
-  public getTreeItem(): vscode.TreeItem {
-    return {
-      collapsibleState: vscode.TreeItemCollapsibleState.None,
-      label: this.label,
-    };
-  }
-
-  public async getChildren(element: NodeBase): Promise<NodeBase[]> {
-    return [];
-  }
-
-  public async getItems4Export(): Promise<string[]> {
-    return [this.fullName];
-  }
-}
diff --git a/src/explorer/models/packageNode.ts b/src/explorer/models/packageNode.ts
deleted file mode 100644
index 2145dc84..00000000
--- a/src/explorer/models/packageNode.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import * as vscode from "vscode";
-import { RootNode } from "./rootNode";
-import { NodeOptions } from "./nodeBase";
-
-export class PackageNode extends RootNode {
-  public constructor(label: string, fullName: string, category: string, options: NodeOptions) {
-    super(label, fullName, "dataNode:packageNode", category, options);
-  }
-
-  public getTreeItem(): vscode.TreeItem {
-    const displayName: string = this.label;
-
-    return {
-      collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
-      contextValue: this.contextValue,
-      label: `${displayName}`,
-      tooltip: this.fullName,
-    };
-  }
-
-  public getClasses(): string[] {
-    return [];
-  }
-}
diff --git a/src/explorer/models/projectNode.ts b/src/explorer/models/projectNode.ts
deleted file mode 100644
index 4e344df9..00000000
--- a/src/explorer/models/projectNode.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-import * as vscode from "vscode";
-import { NodeBase, NodeOptions } from "./nodeBase";
-import { ProjectRootNode } from "./projectRootNode";
-import { OtherStudioAction, StudioActions } from "../../commands/studio";
-import { AtelierAPI } from "../../api";
-
-export class ProjectNode extends NodeBase {
-  private description: string;
-  public constructor(label: string, options: NodeOptions, description: string) {
-    super(label, `${label}.PRJ`, options);
-    this.description = description;
-  }
-
-  public async getChildren(_element: NodeBase): Promise<NodeBase[]> {
-    const children = [];
-    let node: ProjectRootNode;
-
-    // Technically a project is a "document", so tell the server that we're opening it
-    const api = new AtelierAPI(this.workspaceFolderUri);
-    api.setNamespace(this.namespace);
-    await new StudioActions().fireProjectUserAction(api, this.label, OtherStudioAction.OpenedDocument).catch(() => {
-      // Swallow error because showing it is more disruptive than using a potentially outdated project definition
-    });
-
-    node = new ProjectRootNode(
-      "Classes",
-      "",
-      "dataRootNode:classesRootNode",
-      "CLS",
-      this.options,
-      false,
-      new vscode.ThemeIcon("symbol-class")
-    );
-    children.push(node);
-
-    node = new ProjectRootNode(
-      "Routines",
-      "",
-      "dataRootNode:routinesRootNode",
-      "RTN",
-      this.options,
-      false,
-      new vscode.ThemeIcon("note")
-    );
-    children.push(node);
-
-    node = new ProjectRootNode(
-      "Includes",
-      "",
-      "dataRootNode:routinesRootNode",
-      "INC",
-      this.options,
-      false,
-      new vscode.ThemeIcon("file-symlink-file")
-    );
-    children.push(node);
-
-    node = new ProjectRootNode(
-      "CSP Files",
-      "",
-      "dataRootNode:cspRootNode",
-      "CSP",
-      this.options,
-      false,
-      new vscode.ThemeIcon("symbol-file")
-    );
-    children.push(node);
-
-    node = new ProjectRootNode(
-      "Other",
-      "",
-      "dataRootNode:otherRootNode",
-      "OTH",
-      this.options,
-      false,
-      new vscode.ThemeIcon("symbol-misc")
-    );
-    children.push(node);
-
-    return children;
-  }
-
-  public getTreeItem(): vscode.TreeItem {
-    return {
-      collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
-      contextValue: "dataNode:projectNode",
-      label: this.label,
-      tooltip: this.description,
-      iconPath: new vscode.ThemeIcon("files"),
-    };
-  }
-
-  public getItems4Export(): Promise<string[]> {
-    return Promise.resolve([]);
-  }
-}
diff --git a/src/explorer/models/projectRootNode.ts b/src/explorer/models/projectRootNode.ts
deleted file mode 100644
index ff996370..00000000
--- a/src/explorer/models/projectRootNode.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-import { AtelierAPI } from "../../api";
-import { ClassNode } from "./classNode";
-import { CSPFileNode } from "./cspFileNode";
-import { NodeBase } from "./nodeBase";
-import { RootNode } from "./rootNode";
-import { RoutineNode } from "./routineNode";
-
-export class ProjectRootNode extends RootNode {
-  public getChildren(element: NodeBase): Promise<NodeBase[]> {
-    const api = new AtelierAPI(this.workspaceFolderUri);
-    api.setNamespace(this.namespace);
-    let query: string;
-    let parameters: string[];
-    if (this.fullName.length) {
-      const l = String(this.fullName.length + 2);
-      if (this.category == "CSP") {
-        query =
-          "SELECT DISTINCT $PIECE(SUBSTR(sod.Name,?+1),'/') AS Name FROM %Library.RoutineMgr_StudioOpenDialog('*.cspall',1,1,1,1,0,1) AS sod " +
-          "JOIN %Studio.Project_ProjectItemsList(?,1) AS pil ON SUBSTR(sod.Name,2) %STARTSWITH ? AND (" +
-          "(pil.Type = 'DIR' AND SUBSTR(sod.Name,2) %STARTSWITH pil.Name||'/') OR (pil.Type = 'CSP' AND SUBSTR(sod.Name,2) = pil.Name))";
-        parameters = [l, this.options.project, this.fullName + "/"];
-      } else {
-        parameters = [l, l, l, this.options.project, this.fullName + "."];
-        if (this.category == "CLS") {
-          query =
-            "SELECT DISTINCT CASE " +
-            "WHEN $LENGTH(SUBSTR(Name,?),'.') > 1 THEN $PIECE(SUBSTR(Name,?),'.') " +
-            "ELSE SUBSTR(Name,?)||'.cls' " +
-            "END Name FROM %Studio.Project_ProjectItemsList(?) " +
-            "WHERE Type = 'CLS' AND Name %STARTSWITH ?";
-        } else {
-          parameters = [l].concat(parameters);
-          query =
-            "SELECT DISTINCT CASE " +
-            `WHEN $LENGTH(SUBSTR(Name,?),'.') > 2 AND NOT (SUBSTR(Name,?) %PATTERN '.E1"."0.1"G"1N1".int"') THEN $PIECE(SUBSTR(Name,?),'.') ` +
-            "ELSE SUBSTR(Name,?) END Name FROM %Studio.Project_ProjectItemsList(?,1) " +
-            "WHERE Name %STARTSWITH ? AND ";
-          if (this.category == "RTN") {
-            query += "Type = 'MAC' AND $PIECE(Name,'.',$LENGTH(Name,'.')) != 'inc'";
-          } else if (this.category == "INC") {
-            query += "Type = 'MAC' AND $PIECE(Name,'.',$LENGTH(Name,'.')) = 'inc'";
-          } else {
-            query +=
-              "Type != 'DIR' AND Type != 'CSP' AND Type != 'CLS' AND Type != 'PKG' AND Type != 'MAC' AND Type != 'GBL'";
-          }
-        }
-      }
-    } else {
-      query =
-        "SELECT DISTINCT CASE " +
-        "WHEN Type = 'CSP' OR Type = 'DIR' THEN $PIECE(Name,'/') " +
-        "WHEN (Type != 'CSP' AND Type != 'DIR' AND $LENGTH(Name,'.') > 2) OR Type = 'CLS' OR Type = 'PKG' THEN $PIECE(Name,'.') " +
-        "ELSE Name END Name FROM %Studio.Project_ProjectItemsList(?,1) WHERE ";
-      parameters = [this.options.project];
-      if (this.category == "CLS") {
-        query += "Type = 'PKG' OR Type = 'CLS'";
-      } else if (this.category == "RTN") {
-        query += "Type = 'MAC' AND $PIECE(Name,'.',$LENGTH(Name,'.')) != 'inc'";
-      } else if (this.category == "INC") {
-        query += "Type = 'MAC' AND $PIECE(Name,'.',$LENGTH(Name,'.')) = 'inc'";
-      } else if (this.category == "CSP") {
-        query += "Type = 'DIR' OR Type = 'CSP'";
-      } else {
-        query +=
-          "Type != 'DIR' AND Type != 'CSP' AND Type != 'CLS' AND Type != 'PKG' AND Type != 'MAC' AND Type != 'GBL'";
-      }
-    }
-    return api
-      .actionQuery(query, parameters)
-      .then((data) => data.result.content.map((e) => e.Name))
-      .then((entries: string[]) => {
-        // Sort the files and folders separately an case-insensitively
-        const folders: string[] = [];
-        const files: string[] = [];
-        const collator = new Intl.Collator("en");
-        for (const entry of entries) entry.includes(".") ? files.push(entry) : folders.push(entry);
-        return [...folders.sort(collator.compare), ...files.sort(collator.compare)];
-      })
-      .then((entries: string[]) =>
-        entries.map((entry) => {
-          const fullName = this.fullName.length
-            ? `${this.fullName}${this.category == "CSP" ? "/" : "."}${entry}`
-            : entry;
-          if (this.category == "CSP") {
-            if (entry.includes(".")) {
-              return new CSPFileNode(entry, fullName, this.options);
-            } else {
-              return new ProjectRootNode(entry, fullName, "dataNode:cspApplication", this.category, this.options, true);
-            }
-          } else {
-            if (entry.includes(".")) {
-              if (["mac", "int", "inc"].includes(entry.split(".").pop().toLowerCase())) {
-                return new RoutineNode(entry, fullName, this.options);
-              } else {
-                return new ClassNode(entry, fullName, this.options);
-              }
-            } else {
-              return new ProjectRootNode(entry, fullName, "dataNode:packageNode", this.category, this.options);
-            }
-          }
-        })
-      );
-  }
-  public getItems4Export(): Promise<string[]> {
-    return Promise.resolve([]);
-  }
-}
diff --git a/src/explorer/models/projectsServerNode.ts b/src/explorer/models/projectsServerNode.ts
deleted file mode 100644
index ba964b03..00000000
--- a/src/explorer/models/projectsServerNode.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import * as vscode from "vscode";
-import { AtelierAPI } from "../../api";
-import { NodeBase } from "./nodeBase";
-import { ProjectNode } from "./projectNode";
-
-export class ProjectsServerNode extends NodeBase {
-  public eventEmitter: vscode.EventEmitter<NodeBase>;
-  public uniqueId: string;
-  public constructor(label: string, eventEmitter: vscode.EventEmitter<NodeBase>, wsUri: vscode.Uri) {
-    super(label, label, { workspaceFolderUri: wsUri });
-    this.uniqueId = `projectsServerNode:${this.workspaceFolder}`;
-    this.eventEmitter = eventEmitter;
-  }
-
-  public getTreeItem(): vscode.TreeItem {
-    const { host, port, pathPrefix, serverName } = this.conn;
-    return {
-      collapsibleState: vscode.TreeItemCollapsibleState.Expanded,
-      contextValue: this.uniqueId,
-      label: `${
-        serverName && serverName.length ? serverName : `${host}:${port}${pathPrefix}`
-      }:${this.namespace.toUpperCase()}`,
-      iconPath: new vscode.ThemeIcon("server-environment"),
-      tooltip: "Explore projects in this server namespace",
-    };
-  }
-
-  public async getChildren(element: NodeBase): Promise<NodeBase[]> {
-    const api = new AtelierAPI(this.workspaceFolderUri);
-    api.setNamespace(this.namespace);
-    return api
-      .actionQuery("SELECT Name, Description FROM %Studio.Project", [])
-      .then((data) =>
-        data.result.content.map(
-          (project) => new ProjectNode(project.Name, { project: project.Name, ...this.options }, project.Description)
-        )
-      );
-  }
-}
diff --git a/src/explorer/models/projectsServerNsNode.ts b/src/explorer/models/projectsServerNsNode.ts
deleted file mode 100644
index 3bf80356..00000000
--- a/src/explorer/models/projectsServerNsNode.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import * as vscode from "vscode";
-import { AtelierAPI } from "../../api";
-import { NodeBase } from "./nodeBase";
-import { ProjectNode } from "./projectNode";
-
-export class ProjectsServerNsNode extends NodeBase {
-  public eventEmitter: vscode.EventEmitter<NodeBase>;
-
-  public constructor(label: string, eventEmitter: vscode.EventEmitter<NodeBase>, wsUri: vscode.Uri, extra = false) {
-    super(label, label, { workspaceFolderUri: wsUri, extraNode: extra });
-    this.eventEmitter = eventEmitter;
-  }
-
-  public getTreeItem(): vscode.TreeItem {
-    const { host, port, pathPrefix, serverName } = this.conn;
-    return {
-      collapsibleState: vscode.TreeItemCollapsibleState.Expanded,
-      contextValue: `projectsServerNsNode${this.extraNode ? ":extra" : ""}`,
-      label: `${
-        serverName && serverName.length ? serverName : `${host}:${port}${pathPrefix}`
-      }:${this.namespace.toUpperCase()}`,
-      iconPath: new vscode.ThemeIcon("server-environment"),
-      tooltip: "Explore projects in this server namespace",
-    };
-  }
-
-  public async getChildren(element: NodeBase): Promise<NodeBase[]> {
-    const api = new AtelierAPI(this.workspaceFolderUri);
-    api.setNamespace(this.namespace);
-    return api
-      .actionQuery("SELECT Name, Description FROM %Studio.Project", [])
-      .then((data) =>
-        data.result.content.map(
-          (project) => new ProjectNode(project.Name, { project: project.Name, ...this.options }, project.Description)
-        )
-      );
-  }
-}
diff --git a/src/explorer/models/rootNode.ts b/src/explorer/models/rootNode.ts
deleted file mode 100644
index 37d3a500..00000000
--- a/src/explorer/models/rootNode.ts
+++ /dev/null
@@ -1,184 +0,0 @@
-import * as vscode from "vscode";
-
-import { NodeBase, NodeOptions } from "./nodeBase";
-import { PackageNode } from "./packageNode";
-import { RoutineNode } from "./routineNode";
-import { AtelierAPI } from "../../api";
-import { ClassNode } from "./classNode";
-import { CSPFileNode } from "./cspFileNode";
-import { cspApps } from "../../extension";
-
-type IconPath =
-  | string
-  | vscode.Uri
-  | {
-      light: string | vscode.Uri;
-      dark: string | vscode.Uri;
-    }
-  | vscode.ThemeIcon;
-
-export class RootNode extends NodeBase {
-  public readonly contextValue: string;
-  private readonly _category: string;
-  private readonly isCsp: boolean;
-  private readonly iconPath: IconPath;
-
-  public constructor(
-    label: string,
-    fullName: string,
-    contextValue: string,
-    category: string,
-    options: NodeOptions,
-    isCsp = false,
-    iconPath?: IconPath
-  ) {
-    super(label, fullName, options);
-    this.contextValue = contextValue;
-    this._category = category;
-    this.isCsp = isCsp;
-    this.iconPath = iconPath;
-  }
-
-  public get category(): string {
-    return this._category;
-  }
-
-  public getTreeItem(): vscode.TreeItem {
-    return {
-      collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
-      contextValue: this.contextValue,
-      label: this.label,
-      tooltip: this.isCsp ? this.fullName : undefined,
-      iconPath: this.iconPath,
-    };
-  }
-
-  public async getChildren(element: NodeBase): Promise<NodeBase[]> {
-    const path = this instanceof PackageNode || this.isCsp ? this.fullName + "/" : "";
-    return this.getItems(path, this._category);
-  }
-
-  public async getList(
-    path: string,
-    category: string,
-    flat: boolean
-  ): Promise<{ Name: string; Type: string; fullName: string }[]> {
-    const sql = "SELECT Name, Type FROM %Library.RoutineMgr_StudioOpenDialog(?,?,?,?,?,?,?)";
-    let spec = "";
-    switch (category) {
-      case "CLS":
-        spec = "*.cls";
-        break;
-      case "RTN":
-        spec = "*.mac,*.int,*.bas,*.mvb,*.mvi";
-        break;
-      case "INC":
-        spec = "*.inc";
-        break;
-      case "ALL":
-        spec = "*.cls,*.mac,*.int,*.inc";
-        break;
-      case "CSP":
-        spec = "*";
-        break;
-      case "OTH":
-        spec = "*.other,'*.bpl,'*.dtl";
-        break;
-      default:
-        return;
-    }
-    const direction = "1";
-    const orderBy = "1"; // by Name
-    const notStudio = "0";
-    const generated = this.options.generated ? "1" : "0";
-
-    spec = path + spec;
-
-    const systemFiles = this.options.system || this.namespace === "%SYS" ? "1" : "0";
-
-    const api = new AtelierAPI(this.workspaceFolder);
-    api.setNamespace(this.namespace);
-    if (category == "CSP" && path == "") {
-      // Use the results from the getCSPApps() API
-      const cspAppsKey = (
-        api.config.serverName && api.config.serverName != ""
-          ? `${api.config.serverName}:${api.config.ns}`
-          : `${api.config.host}:${api.config.port}${api.config.pathPrefix}:${api.config.ns}`
-      ).toLowerCase();
-      let nsCspApps: string[] | undefined = cspApps.get(cspAppsKey);
-      if (nsCspApps == undefined) {
-        nsCspApps = await api.getCSPApps().then((data) => data.result.content || []);
-        cspApps.set(cspAppsKey, nsCspApps);
-      }
-      return nsCspApps.map((cspApp) => {
-        return { Name: cspApp.slice(1), fullName: cspApp.slice(1), Type: "10" };
-      });
-    } else {
-      // Use StudioOpenDialog
-      return api
-        .actionQuery(sql, [spec, direction, orderBy, systemFiles, flat ? "1" : "0", notStudio, generated])
-        .then((data) => {
-          const content = data.result.content;
-          return content;
-        })
-        .then((data) =>
-          data.map((el: { Name: string; Type: number }) => {
-            let fullName = el.Name;
-            if (this instanceof PackageNode) {
-              fullName = this.fullName + "." + el.Name;
-            } else if (this.isCsp) {
-              fullName = this.fullName + "/" + el.Name;
-            }
-            return {
-              Name: el.Name,
-              Type: String(el.Type),
-              fullName,
-            };
-          })
-        );
-    }
-  }
-
-  public getItems(path: string, category: string): Promise<NodeBase[]> {
-    return this.getList(path, category, false).then((data) =>
-      data
-        .filter((el) => {
-          if (category === "OTH") {
-            return el.Type === "100";
-          } else if (category === "CSP") {
-            return el.Type === "10" || el.Type === "5";
-          } else {
-            return true;
-          }
-        })
-        .map((el) => {
-          switch (el.Type) {
-            case "9":
-              return new PackageNode(el.Name, el.fullName, category, this.options);
-            case "4":
-            case "100":
-              return new ClassNode(el.Name, el.fullName, this.options);
-            case "5":
-              return new CSPFileNode(el.Name, el.fullName, this.options);
-            case "0":
-            case "1":
-            case "2":
-            case "3":
-            case "11":
-              return new RoutineNode(el.Name, el.fullName, this.options);
-            case "10":
-              return new RootNode(el.Name, el.fullName, "dataNode:cspApplication", this._category, this.options, true);
-            default:
-              return null;
-          }
-        })
-        .filter((el) => el !== null)
-    );
-  }
-
-  public getItems4Export(): Promise<string[]> {
-    const path = this instanceof PackageNode || this.isCsp ? this.fullName + "/" : "";
-    const cat = this.isCsp ? "CSP" : "ALL";
-    return this.getList(path, cat, true).then((data) => data.map((el) => el.Name));
-  }
-}
diff --git a/src/explorer/models/routineNode.ts b/src/explorer/models/routineNode.ts
deleted file mode 100644
index 28622619..00000000
--- a/src/explorer/models/routineNode.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import * as vscode from "vscode";
-import { NodeBase, NodeOptions } from "./nodeBase";
-import { config } from "../../extension";
-import { getLeafNodeUri } from "../explorer";
-import { notIsfs } from "../../utils";
-
-export class RoutineNode extends NodeBase {
-  public static readonly contextValue: string = "dataNode:routineNode";
-  public constructor(label: string, fullName: string, options: NodeOptions) {
-    super(label, fullName, options);
-  }
-
-  public getTreeItem(): vscode.TreeItem {
-    const displayName: string = this.label;
-    const itemUri = getLeafNodeUri(this);
-    const isLocalFile = notIsfs(itemUri);
-    const showServerCopy: boolean = config("explorer.alwaysShowServerCopy", this.workspaceFolder);
-    const serverCopyUri = getLeafNodeUri(this, true);
-
-    return {
-      collapsibleState: vscode.TreeItemCollapsibleState.None,
-      command: {
-        arguments: [isLocalFile && !showServerCopy ? itemUri : serverCopyUri, this.options.project, this.fullName],
-        command: "vscode-objectscript.explorer.open",
-        title: "Open Routine",
-      },
-      resourceUri: isLocalFile && !showServerCopy ? itemUri : undefined,
-      contextValue: "dataNode:routineNode",
-      label: `${displayName}`,
-      tooltip: isLocalFile && !showServerCopy ? undefined : this.fullName,
-    };
-  }
-}
diff --git a/src/explorer/models/workspaceNode.ts b/src/explorer/models/workspaceNode.ts
deleted file mode 100644
index 6276cdfe..00000000
--- a/src/explorer/models/workspaceNode.ts
+++ /dev/null
@@ -1,98 +0,0 @@
-import * as vscode from "vscode";
-
-import { NodeBase, NodeOptions } from "./nodeBase";
-import { RootNode } from "./rootNode";
-import { workspaceState } from "../../extension";
-
-export class WorkspaceNode extends NodeBase {
-  public eventEmitter: vscode.EventEmitter<NodeBase>;
-  public uniqueId: string;
-  public constructor(label: string, eventEmitter: vscode.EventEmitter<NodeBase>, options: NodeOptions) {
-    super(label, label, options);
-    this.uniqueId = `serverNode:${this.namespace}:${this.extraNode ? ":extra:" : ""}`;
-    this.options.generated = workspaceState.get(`ExplorerGenerated:${this.uniqueId}`);
-    this.options.system = workspaceState.get(`ExplorerSystem:${this.uniqueId}`);
-    this.eventEmitter = eventEmitter;
-  }
-
-  public getTreeItem(): vscode.TreeItem {
-    const flags = [];
-    this.options.generated && flags.push(":generated:");
-    this.options.system && flags.push(":system:");
-    const { host, port, docker, dockerService } = this.conn;
-    const serverInfo = docker
-      ? "docker" + (dockerService ? `:${dockerService}:${port}` : "")
-      : `${host}${port ? ":" + port : ""}`;
-    const connInfo = this.extraNode
-      ? `[${this.namespace}] on ${serverInfo}`
-      : `${this.label} (${serverInfo}[${this.namespace}])`;
-    return {
-      collapsibleState: vscode.TreeItemCollapsibleState.Expanded,
-      contextValue: `${this.uniqueId}${flags.join("")}`,
-      label: connInfo,
-      iconPath: new vscode.ThemeIcon(this.extraNode ? "database" : "server-environment"),
-    };
-  }
-
-  public async getChildren(_element: NodeBase): Promise<NodeBase[]> {
-    const children = [];
-    let node: RootNode;
-
-    node = new RootNode(
-      "Classes",
-      "",
-      "dataRootNode:classesRootNode",
-      "CLS",
-      this.options,
-      false,
-      new vscode.ThemeIcon("symbol-class")
-    );
-    children.push(node);
-
-    node = new RootNode(
-      "Routines",
-      "",
-      "dataRootNode:routinesRootNode",
-      "RTN",
-      this.options,
-      false,
-      new vscode.ThemeIcon("note")
-    );
-    children.push(node);
-
-    node = new RootNode(
-      "Includes",
-      "",
-      "dataRootNode:routinesRootNode",
-      "INC",
-      this.options,
-      false,
-      new vscode.ThemeIcon("file-symlink-file")
-    );
-    children.push(node);
-
-    node = new RootNode(
-      "CSP Files",
-      "",
-      "dataRootNode:cspRootNode",
-      "CSP",
-      this.options,
-      false,
-      new vscode.ThemeIcon("symbol-file")
-    );
-    children.push(node);
-
-    node = new RootNode(
-      "Other",
-      "",
-      "dataRootNode:otherRootNode",
-      "OTH",
-      this.options,
-      false,
-      new vscode.ThemeIcon("symbol-misc")
-    );
-    children.push(node);
-
-    return children;
-  }
-}
diff --git a/src/explorer/nodes.ts b/src/explorer/nodes.ts
new file mode 100644
index 00000000..347e784d
--- /dev/null
+++ b/src/explorer/nodes.ts
@@ -0,0 +1,726 @@
+import * as vscode from "vscode";
+import { AtelierAPI } from "../api";
+import { cspApps, currentWorkspaceFolder, notIsfs, uriOfWorkspaceFolder } from "../utils";
+import { StudioActions, OtherStudioAction } from "../commands/studio";
+import { config, workspaceState } from "../extension";
+import { DocumentContentProvider } from "../providers/DocumentContentProvider";
+
+type IconPath =
+  | string
+  | vscode.Uri
+  | {
+      light: string | vscode.Uri;
+      dark: string | vscode.Uri;
+    }
+  | vscode.ThemeIcon;
+
+interface NodeOptions {
+  extraNode?: boolean;
+  generated?: boolean;
+  system?: boolean;
+  namespace?: string;
+  workspaceFolder?: string;
+  workspaceFolderUri?: vscode.Uri;
+  project?: string;
+}
+
+/** Get the URI for this leaf node */
+function getLeafNodeUri(node: NodeBase, forceServerCopy = false): vscode.Uri {
+  if (node.workspaceFolder == undefined) {
+    // Should only be the case for leaf nodes in the projects explorer
+    // that are children of an extra server namespace node
+    return DocumentContentProvider.getUri(
+      node.fullName,
+      undefined,
+      undefined,
+      true,
+      node.workspaceFolderUri,
+      forceServerCopy
+    );
+  } else {
+    return DocumentContentProvider.getUri(
+      node.fullName,
+      node.workspaceFolder,
+      node.namespace,
+      undefined,
+      undefined,
+      forceServerCopy
+    );
+  }
+}
+
+export class NodeBase {
+  public readonly options: NodeOptions;
+  public readonly label: string;
+  public readonly fullName: string;
+  public readonly workspaceFolder: string;
+  public readonly conn: any;
+  public readonly extraNode: boolean;
+  public readonly namespace: string;
+  public readonly workspaceFolderUri: vscode.Uri;
+
+  protected constructor(label: string, fullName: string, options: NodeOptions) {
+    this.options = {
+      generated: false,
+      extraNode: false,
+      ...options,
+    };
+    this.label = label;
+    this.fullName = fullName;
+    const { workspaceFolder, namespace, extraNode, workspaceFolderUri } = options;
+    if (workspaceFolderUri) {
+      // Used by Projects tree
+      this.workspaceFolderUri = workspaceFolderUri;
+      this.workspaceFolder = vscode.workspace.getWorkspaceFolder(workspaceFolderUri)?.name;
+      const api = new AtelierAPI(workspaceFolderUri);
+      this.conn = api.config;
+    } else {
+      this.workspaceFolder = workspaceFolder || currentWorkspaceFolder();
+      this.workspaceFolderUri = uriOfWorkspaceFolder(this.workspaceFolder);
+      const api = new AtelierAPI(workspaceFolder);
+      this.conn = api.config;
+    }
+    this.namespace = namespace || this.conn.ns;
+    this.extraNode = extraNode;
+  }
+
+  public getTreeItem(): vscode.TreeItem {
+    return {
+      collapsibleState: vscode.TreeItemCollapsibleState.None,
+      label: this.label,
+    };
+  }
+
+  public async getChildren(element: NodeBase): Promise<NodeBase[]> {
+    return [];
+  }
+
+  public async getItems4Export(): Promise<string[]> {
+    return [this.fullName];
+  }
+}
+
+export class RootNode extends NodeBase {
+  public readonly contextValue: string;
+  private readonly _category: string;
+  private readonly isCsp: boolean;
+  private readonly iconPath: IconPath;
+
+  public constructor(
+    label: string,
+    fullName: string,
+    contextValue: string,
+    category: string,
+    options: NodeOptions,
+    isCsp = false,
+    iconPath?: IconPath
+  ) {
+    super(label, fullName, options);
+    this.contextValue = contextValue;
+    this._category = category;
+    this.isCsp = isCsp;
+    this.iconPath = iconPath;
+  }
+
+  public get category(): string {
+    return this._category;
+  }
+
+  public getTreeItem(): vscode.TreeItem {
+    return {
+      collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
+      contextValue: this.contextValue,
+      label: this.label,
+      tooltip: this.isCsp ? this.fullName : undefined,
+      iconPath: this.iconPath,
+    };
+  }
+
+  public async getChildren(element: NodeBase): Promise<NodeBase[]> {
+    const path = this instanceof PackageNode || this.isCsp ? this.fullName + "/" : "";
+    return this.getItems(path, this._category);
+  }
+
+  public async getList(
+    path: string,
+    category: string,
+    flat: boolean
+  ): Promise<{ Name: string; Type: string; fullName: string }[]> {
+    const sql = "SELECT Name, Type FROM %Library.RoutineMgr_StudioOpenDialog(?,?,?,?,?,?,?)";
+    let spec = "";
+    switch (category) {
+      case "CLS":
+        spec = "*.cls";
+        break;
+      case "RTN":
+        spec = "*.mac,*.int,*.bas,*.mvb,*.mvi";
+        break;
+      case "INC":
+        spec = "*.inc";
+        break;
+      case "ALL":
+        spec = "*.cls,*.mac,*.int,*.inc";
+        break;
+      case "CSP":
+        spec = "*";
+        break;
+      case "OTH":
+        spec = "*.other,'*.bpl,'*.dtl";
+        break;
+      default:
+        return;
+    }
+    const direction = "1";
+    const orderBy = "1"; // by Name
+    const notStudio = "0";
+    const generated = this.options.generated ? "1" : "0";
+
+    spec = path + spec;
+
+    const systemFiles = this.options.system || this.namespace === "%SYS" ? "1" : "0";
+
+    const api = new AtelierAPI(this.workspaceFolder);
+    api.setNamespace(this.namespace);
+    if (category == "CSP" && path == "") {
+      // Use the results from the getCSPApps() API
+      const cspAppsKey = (
+        api.config.serverName && api.config.serverName != ""
+          ? `${api.config.serverName}:${api.config.ns}`
+          : `${api.config.host}:${api.config.port}${api.config.pathPrefix}:${api.config.ns}`
+      ).toLowerCase();
+      let nsCspApps: string[] | undefined = cspApps.get(cspAppsKey);
+      if (nsCspApps == undefined) {
+        nsCspApps = await api.getCSPApps().then((data) => data.result.content || []);
+        cspApps.set(cspAppsKey, nsCspApps);
+      }
+      return nsCspApps.map((cspApp) => {
+        return { Name: cspApp.slice(1), fullName: cspApp.slice(1), Type: "10" };
+      });
+    } else {
+      // Use StudioOpenDialog
+      return api
+        .actionQuery(sql, [spec, direction, orderBy, systemFiles, flat ? "1" : "0", notStudio, generated])
+        .then((data) => {
+          const content = data.result.content;
+          return content;
+        })
+        .then((data) =>
+          data.map((el: { Name: string; Type: number }) => {
+            let fullName = el.Name;
+            if (this instanceof PackageNode) {
+              fullName = this.fullName + "." + el.Name;
+            } else if (this.isCsp) {
+              fullName = this.fullName + "/" + el.Name;
+            }
+            return {
+              Name: el.Name,
+              Type: String(el.Type),
+              fullName,
+            };
+          })
+        );
+    }
+  }
+
+  public getItems(path: string, category: string): Promise<NodeBase[]> {
+    return this.getList(path, category, false).then((data) =>
+      data
+        .filter((el) => {
+          if (category === "OTH") {
+            return el.Type === "100";
+          } else if (category === "CSP") {
+            return el.Type === "10" || el.Type === "5";
+          } else {
+            return true;
+          }
+        })
+        .map((el) => {
+          switch (el.Type) {
+            case "9":
+              return new PackageNode(el.Name, el.fullName, category, this.options);
+            case "4":
+            case "100":
+              return new ClassNode(el.Name, el.fullName, this.options);
+            case "5":
+              return new CSPFileNode(el.Name, el.fullName, this.options);
+            case "0":
+            case "1":
+            case "2":
+            case "3":
+            case "11":
+              return new RoutineNode(el.Name, el.fullName, this.options);
+            case "10":
+              return new RootNode(el.Name, el.fullName, "dataNode:cspApplication", this._category, this.options, true);
+            default:
+              return null;
+          }
+        })
+        .filter((el) => el !== null)
+    );
+  }
+
+  public getItems4Export(): Promise<string[]> {
+    const path = this instanceof PackageNode || this.isCsp ? this.fullName + "/" : "";
+    const cat = this.isCsp ? "CSP" : "ALL";
+    return this.getList(path, cat, true).then((data) => data.map((el) => el.Name));
+  }
+}
+
+export class ClassNode extends NodeBase {
+  public static readonly contextValue: string = "dataNode:classNode";
+  public constructor(label: string, fullName: string, options: NodeOptions) {
+    super(label, fullName, options);
+  }
+
+  public getTreeItem(): vscode.TreeItem {
+    const displayName: string = this.label;
+    const itemUri = getLeafNodeUri(this);
+    const isLocalFile = notIsfs(itemUri);
+    const showServerCopy: boolean = config("explorer.alwaysShowServerCopy", this.workspaceFolder);
+    const serverCopyUri = getLeafNodeUri(this, true);
+
+    return {
+      collapsibleState: vscode.TreeItemCollapsibleState.None,
+      command: {
+        arguments: [isLocalFile && !showServerCopy ? itemUri : serverCopyUri, this.options.project, this.fullName],
+        command: "vscode-objectscript.explorer.open",
+        title: "Open Class",
+      },
+      resourceUri: isLocalFile && !showServerCopy ? itemUri : undefined,
+      contextValue: "dataNode:classNode",
+      label: `${displayName}`,
+      tooltip: isLocalFile && !showServerCopy ? undefined : this.fullName,
+    };
+  }
+}
+
+export class CSPFileNode extends NodeBase {
+  public static readonly contextValue: string = "dataNode:cspFileNode";
+  public constructor(label: string, fullName: string, options: NodeOptions) {
+    super(label, fullName, options);
+  }
+
+  public getTreeItem(): vscode.TreeItem {
+    const displayName: string = this.label;
+    const itemUri = getLeafNodeUri(this);
+    const isLocalFile = notIsfs(itemUri);
+    const showServerCopy: boolean = config("explorer.alwaysShowServerCopy", this.workspaceFolder);
+    const serverCopyUri = getLeafNodeUri(this, true);
+
+    return {
+      collapsibleState: vscode.TreeItemCollapsibleState.None,
+      command: {
+        arguments: [isLocalFile && !showServerCopy ? itemUri : serverCopyUri, this.options.project, this.fullName],
+        command: "vscode-objectscript.explorer.open",
+        title: "Open File",
+      },
+      resourceUri: isLocalFile && !showServerCopy ? itemUri : undefined,
+      contextValue: CSPFileNode.contextValue,
+      label: `${displayName}`,
+      tooltip: isLocalFile && !showServerCopy ? undefined : this.fullName,
+    };
+  }
+}
+
+export class PackageNode extends RootNode {
+  public constructor(label: string, fullName: string, category: string, options: NodeOptions) {
+    super(label, fullName, "dataNode:packageNode", category, options);
+  }
+
+  public getTreeItem(): vscode.TreeItem {
+    const displayName: string = this.label;
+
+    return {
+      collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
+      contextValue: this.contextValue,
+      label: `${displayName}`,
+      tooltip: this.fullName,
+    };
+  }
+
+  public getClasses(): string[] {
+    return [];
+  }
+}
+
+export class RoutineNode extends NodeBase {
+  public static readonly contextValue: string = "dataNode:routineNode";
+  public constructor(label: string, fullName: string, options: NodeOptions) {
+    super(label, fullName, options);
+  }
+
+  public getTreeItem(): vscode.TreeItem {
+    const displayName: string = this.label;
+    const itemUri = getLeafNodeUri(this);
+    const isLocalFile = notIsfs(itemUri);
+    const showServerCopy: boolean = config("explorer.alwaysShowServerCopy", this.workspaceFolder);
+    const serverCopyUri = getLeafNodeUri(this, true);
+
+    return {
+      collapsibleState: vscode.TreeItemCollapsibleState.None,
+      command: {
+        arguments: [isLocalFile && !showServerCopy ? itemUri : serverCopyUri, this.options.project, this.fullName],
+        command: "vscode-objectscript.explorer.open",
+        title: "Open Routine",
+      },
+      resourceUri: isLocalFile && !showServerCopy ? itemUri : undefined,
+      contextValue: "dataNode:routineNode",
+      label: `${displayName}`,
+      tooltip: isLocalFile && !showServerCopy ? undefined : this.fullName,
+    };
+  }
+}
+
+export class WorkspaceNode extends NodeBase {
+  public eventEmitter: vscode.EventEmitter<NodeBase>;
+  public uniqueId: string;
+  public constructor(label: string, eventEmitter: vscode.EventEmitter<NodeBase>, options: NodeOptions) {
+    super(label, label, options);
+    this.uniqueId = `serverNode:${this.namespace}:${this.extraNode ? ":extra:" : ""}`;
+    this.options.generated = workspaceState.get(`ExplorerGenerated:${this.uniqueId}`);
+    this.options.system = workspaceState.get(`ExplorerSystem:${this.uniqueId}`);
+    this.eventEmitter = eventEmitter;
+  }
+
+  public getTreeItem(): vscode.TreeItem {
+    const flags = [];
+    this.options.generated && flags.push(":generated:");
+    this.options.system && flags.push(":system:");
+    const { host, port, docker, dockerService } = this.conn;
+    const serverInfo = docker
+      ? "docker" + (dockerService ? `:${dockerService}:${port}` : "")
+      : `${host}${port ? ":" + port : ""}`;
+    const connInfo = this.extraNode
+      ? `[${this.namespace}] on ${serverInfo}`
+      : `${this.label} (${serverInfo}[${this.namespace}])`;
+    return {
+      collapsibleState: vscode.TreeItemCollapsibleState.Expanded,
+      contextValue: `${this.uniqueId}${flags.join("")}`,
+      label: connInfo,
+      iconPath: new vscode.ThemeIcon(this.extraNode ? "database" : "server-environment"),
+    };
+  }
+
+  public async getChildren(_element: NodeBase): Promise<NodeBase[]> {
+    const children = [];
+    let node: RootNode;
+
+    node = new RootNode(
+      "Classes",
+      "",
+      "dataRootNode:classesRootNode",
+      "CLS",
+      this.options,
+      false,
+      new vscode.ThemeIcon("symbol-class")
+    );
+    children.push(node);
+
+    node = new RootNode(
+      "Routines",
+      "",
+      "dataRootNode:routinesRootNode",
+      "RTN",
+      this.options,
+      false,
+      new vscode.ThemeIcon("note")
+    );
+    children.push(node);
+
+    node = new RootNode(
+      "Includes",
+      "",
+      "dataRootNode:routinesRootNode",
+      "INC",
+      this.options,
+      false,
+      new vscode.ThemeIcon("file-symlink-file")
+    );
+    children.push(node);
+
+    node = new RootNode(
+      "CSP Files",
+      "",
+      "dataRootNode:cspRootNode",
+      "CSP",
+      this.options,
+      false,
+      new vscode.ThemeIcon("symbol-file")
+    );
+    children.push(node);
+
+    node = new RootNode(
+      "Other",
+      "",
+      "dataRootNode:otherRootNode",
+      "OTH",
+      this.options,
+      false,
+      new vscode.ThemeIcon("symbol-misc")
+    );
+    children.push(node);
+
+    return children;
+  }
+}
+
+export class ProjectNode extends NodeBase {
+  private description: string;
+  public constructor(label: string, options: NodeOptions, description: string) {
+    super(label, `${label}.PRJ`, options);
+    this.description = description;
+  }
+
+  public async getChildren(_element: NodeBase): Promise<NodeBase[]> {
+    const children = [];
+    let node: ProjectRootNode;
+
+    // Technically a project is a "document", so tell the server that we're opening it
+    const api = new AtelierAPI(this.workspaceFolderUri);
+    api.setNamespace(this.namespace);
+    await new StudioActions().fireProjectUserAction(api, this.label, OtherStudioAction.OpenedDocument).catch(() => {
+      // Swallow error because showing it is more disruptive than using a potentially outdated project definition
+    });
+
+    node = new ProjectRootNode(
+      "Classes",
+      "",
+      "dataRootNode:classesRootNode",
+      "CLS",
+      this.options,
+      false,
+      new vscode.ThemeIcon("symbol-class")
+    );
+    children.push(node);
+
+    node = new ProjectRootNode(
+      "Routines",
+      "",
+      "dataRootNode:routinesRootNode",
+      "RTN",
+      this.options,
+      false,
+      new vscode.ThemeIcon("note")
+    );
+    children.push(node);
+
+    node = new ProjectRootNode(
+      "Includes",
+      "",
+      "dataRootNode:routinesRootNode",
+      "INC",
+      this.options,
+      false,
+      new vscode.ThemeIcon("file-symlink-file")
+    );
+    children.push(node);
+
+    node = new ProjectRootNode(
+      "CSP Files",
+      "",
+      "dataRootNode:cspRootNode",
+      "CSP",
+      this.options,
+      false,
+      new vscode.ThemeIcon("symbol-file")
+    );
+    children.push(node);
+
+    node = new ProjectRootNode(
+      "Other",
+      "",
+      "dataRootNode:otherRootNode",
+      "OTH",
+      this.options,
+      false,
+      new vscode.ThemeIcon("symbol-misc")
+    );
+    children.push(node);
+
+    return children;
+  }
+
+  public getTreeItem(): vscode.TreeItem {
+    return {
+      collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
+      contextValue: "dataNode:projectNode",
+      label: this.label,
+      tooltip: this.description,
+      iconPath: new vscode.ThemeIcon("files"),
+    };
+  }
+
+  public getItems4Export(): Promise<string[]> {
+    return Promise.resolve([]);
+  }
+}
+
+export class ProjectRootNode extends RootNode {
+  public getChildren(element: NodeBase): Promise<NodeBase[]> {
+    const api = new AtelierAPI(this.workspaceFolderUri);
+    api.setNamespace(this.namespace);
+    let query: string;
+    let parameters: string[];
+    if (this.fullName.length) {
+      const l = String(this.fullName.length + 2);
+      if (this.category == "CSP") {
+        query =
+          "SELECT DISTINCT $PIECE(SUBSTR(sod.Name,?+1),'/') AS Name FROM %Library.RoutineMgr_StudioOpenDialog('*.cspall',1,1,1,1,0,1) AS sod " +
+          "JOIN %Studio.Project_ProjectItemsList(?,1) AS pil ON SUBSTR(sod.Name,2) %STARTSWITH ? AND (" +
+          "(pil.Type = 'DIR' AND SUBSTR(sod.Name,2) %STARTSWITH pil.Name||'/') OR (pil.Type = 'CSP' AND SUBSTR(sod.Name,2) = pil.Name))";
+        parameters = [l, this.options.project, this.fullName + "/"];
+      } else {
+        parameters = [l, l, l, this.options.project, this.fullName + "."];
+        if (this.category == "CLS") {
+          query =
+            "SELECT DISTINCT CASE " +
+            "WHEN $LENGTH(SUBSTR(Name,?),'.') > 1 THEN $PIECE(SUBSTR(Name,?),'.') " +
+            "ELSE SUBSTR(Name,?)||'.cls' " +
+            "END Name FROM %Studio.Project_ProjectItemsList(?) " +
+            "WHERE Type = 'CLS' AND Name %STARTSWITH ?";
+        } else {
+          parameters = [l].concat(parameters);
+          query =
+            "SELECT DISTINCT CASE " +
+            `WHEN $LENGTH(SUBSTR(Name,?),'.') > 2 AND NOT (SUBSTR(Name,?) %PATTERN '.E1"."0.1"G"1N1".int"') THEN $PIECE(SUBSTR(Name,?),'.') ` +
+            "ELSE SUBSTR(Name,?) END Name FROM %Studio.Project_ProjectItemsList(?,1) " +
+            "WHERE Name %STARTSWITH ? AND ";
+          if (this.category == "RTN") {
+            query += "Type = 'MAC' AND $PIECE(Name,'.',$LENGTH(Name,'.')) != 'inc'";
+          } else if (this.category == "INC") {
+            query += "Type = 'MAC' AND $PIECE(Name,'.',$LENGTH(Name,'.')) = 'inc'";
+          } else {
+            query +=
+              "Type != 'DIR' AND Type != 'CSP' AND Type != 'CLS' AND Type != 'PKG' AND Type != 'MAC' AND Type != 'GBL'";
+          }
+        }
+      }
+    } else {
+      query =
+        "SELECT DISTINCT CASE " +
+        "WHEN Type = 'CSP' OR Type = 'DIR' THEN $PIECE(Name,'/') " +
+        "WHEN (Type != 'CSP' AND Type != 'DIR' AND $LENGTH(Name,'.') > 2) OR Type = 'CLS' OR Type = 'PKG' THEN $PIECE(Name,'.') " +
+        "ELSE Name END Name FROM %Studio.Project_ProjectItemsList(?,1) WHERE ";
+      parameters = [this.options.project];
+      if (this.category == "CLS") {
+        query += "Type = 'PKG' OR Type = 'CLS'";
+      } else if (this.category == "RTN") {
+        query += "Type = 'MAC' AND $PIECE(Name,'.',$LENGTH(Name,'.')) != 'inc'";
+      } else if (this.category == "INC") {
+        query += "Type = 'MAC' AND $PIECE(Name,'.',$LENGTH(Name,'.')) = 'inc'";
+      } else if (this.category == "CSP") {
+        query += "Type = 'DIR' OR Type = 'CSP'";
+      } else {
+        query +=
+          "Type != 'DIR' AND Type != 'CSP' AND Type != 'CLS' AND Type != 'PKG' AND Type != 'MAC' AND Type != 'GBL'";
+      }
+    }
+    return api
+      .actionQuery(query, parameters)
+      .then((data) => data.result.content.map((e) => e.Name))
+      .then((entries: string[]) => {
+        // Sort the files and folders separately an case-insensitively
+        const folders: string[] = [];
+        const files: string[] = [];
+        const collator = new Intl.Collator("en");
+        for (const entry of entries) entry.includes(".") ? files.push(entry) : folders.push(entry);
+        return [...folders.sort(collator.compare), ...files.sort(collator.compare)];
+      })
+      .then((entries: string[]) =>
+        entries.map((entry) => {
+          const fullName = this.fullName.length
+            ? `${this.fullName}${this.category == "CSP" ? "/" : "."}${entry}`
+            : entry;
+          if (this.category == "CSP") {
+            if (entry.includes(".")) {
+              return new CSPFileNode(entry, fullName, this.options);
+            } else {
+              return new ProjectRootNode(entry, fullName, "dataNode:cspApplication", this.category, this.options, true);
+            }
+          } else {
+            if (entry.includes(".")) {
+              if (["mac", "int", "inc"].includes(entry.split(".").pop().toLowerCase())) {
+                return new RoutineNode(entry, fullName, this.options);
+              } else {
+                return new ClassNode(entry, fullName, this.options);
+              }
+            } else {
+              return new ProjectRootNode(entry, fullName, "dataNode:packageNode", this.category, this.options);
+            }
+          }
+        })
+      );
+  }
+  public getItems4Export(): Promise<string[]> {
+    return Promise.resolve([]);
+  }
+}
+
+export class ProjectsServerNode extends NodeBase {
+  public eventEmitter: vscode.EventEmitter<NodeBase>;
+  public uniqueId: string;
+  public constructor(label: string, eventEmitter: vscode.EventEmitter<NodeBase>, wsUri: vscode.Uri) {
+    super(label, label, { workspaceFolderUri: wsUri });
+    this.uniqueId = `projectsServerNode:${this.workspaceFolder}`;
+    this.eventEmitter = eventEmitter;
+  }
+
+  public getTreeItem(): vscode.TreeItem {
+    const { host, port, pathPrefix, serverName } = this.conn;
+    return {
+      collapsibleState: vscode.TreeItemCollapsibleState.Expanded,
+      contextValue: this.uniqueId,
+      label: `${
+        serverName && serverName.length ? serverName : `${host}:${port}${pathPrefix}`
+      }:${this.namespace.toUpperCase()}`,
+      iconPath: new vscode.ThemeIcon("server-environment"),
+      tooltip: "Explore projects in this server namespace",
+    };
+  }
+
+  public async getChildren(element: NodeBase): Promise<NodeBase[]> {
+    const api = new AtelierAPI(this.workspaceFolderUri);
+    api.setNamespace(this.namespace);
+    return api
+      .actionQuery("SELECT Name, Description FROM %Studio.Project", [])
+      .then((data) =>
+        data.result.content.map(
+          (project) => new ProjectNode(project.Name, { project: project.Name, ...this.options }, project.Description)
+        )
+      );
+  }
+}
+
+export class ProjectsServerNsNode extends NodeBase {
+  public eventEmitter: vscode.EventEmitter<NodeBase>;
+
+  public constructor(label: string, eventEmitter: vscode.EventEmitter<NodeBase>, wsUri: vscode.Uri, extra = false) {
+    super(label, label, { workspaceFolderUri: wsUri, extraNode: extra });
+    this.eventEmitter = eventEmitter;
+  }
+
+  public getTreeItem(): vscode.TreeItem {
+    const { host, port, pathPrefix, serverName } = this.conn;
+    return {
+      collapsibleState: vscode.TreeItemCollapsibleState.Expanded,
+      contextValue: `projectsServerNsNode${this.extraNode ? ":extra" : ""}`,
+      label: `${
+        serverName && serverName.length ? serverName : `${host}:${port}${pathPrefix}`
+      }:${this.namespace.toUpperCase()}`,
+      iconPath: new vscode.ThemeIcon("server-environment"),
+      tooltip: "Explore projects in this server namespace",
+    };
+  }
+
+  public async getChildren(element: NodeBase): Promise<NodeBase[]> {
+    const api = new AtelierAPI(this.workspaceFolderUri);
+    api.setNamespace(this.namespace);
+    return api
+      .actionQuery("SELECT Name, Description FROM %Studio.Project", [])
+      .then((data) =>
+        data.result.content.map(
+          (project) => new ProjectNode(project.Name, { project: project.Name, ...this.options }, project.Description)
+        )
+      );
+  }
+}
diff --git a/src/explorer/projectsExplorer.ts b/src/explorer/projectsExplorer.ts
index 1fb36df9..5bb89a41 100644
--- a/src/explorer/projectsExplorer.ts
+++ b/src/explorer/projectsExplorer.ts
@@ -1,8 +1,7 @@
 import * as vscode from "vscode";
 import { AtelierAPI } from "../api";
-import { NodeBase } from "./models/nodeBase";
-import { ProjectsServerNsNode } from "./models/projectsServerNsNode";
 import { notIsfs } from "../utils";
+import { NodeBase, ProjectsServerNsNode } from "./nodes";
 
 export class ProjectsExplorerProvider implements vscode.TreeDataProvider<NodeBase> {
   public onDidChangeTreeData: vscode.Event<NodeBase>;
diff --git a/src/extension.ts b/src/extension.ts
index aa38f881..8b42fa49 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -54,7 +54,6 @@ import { extractXMLFileContents, previewXMLAsUDL } from "./commands/xmlToUdl";
 import {
   mainCommandMenu,
   contextCommandMenu,
-  documentBeingProcessed,
   fireOtherStudioAction,
   OtherStudioAction,
   contextSourceControlMenu,
@@ -84,7 +83,6 @@ import { ObjectScriptDebugAdapterDescriptorFactory } from "./debug/debugAdapterF
 import { ObjectScriptConfigurationProvider } from "./debug/debugConfProvider";
 import { ProjectsExplorerProvider } from "./explorer/projectsExplorer";
 import { ObjectScriptExplorerProvider, registerExplorerOpen } from "./explorer/explorer";
-import { WorkspaceNode } from "./explorer/models/workspaceNode";
 import { FileSystemProvider, generateFileContent } from "./providers/FileSystemProvider/FileSystemProvider";
 import { WorkspaceSymbolProvider } from "./providers/WorkspaceSymbolProvider";
 import {
@@ -95,12 +93,13 @@ import {
   terminalWithDocker,
   notNull,
   currentFile,
-  isImportableLocalFile,
   workspaceFolderOfUri,
   uriOfWorkspaceFolder,
   isUnauthenticated,
   notIsfs,
   handleError,
+  cspApps,
+  otherDocExts,
 } from "./utils";
 import { ObjectScriptDiagnosticProvider } from "./providers/ObjectScriptDiagnosticProvider";
 import { DocumentLinkProvider } from "./providers/DocumentLinkProvider";
@@ -132,9 +131,8 @@ import {
   modifyProject,
   modifyProjectMetadata,
 } from "./commands/project";
-import { NodeBase } from "./explorer/models/nodeBase";
 import { loadStudioColors, loadStudioSnippets } from "./commands/studioMigration";
-import { openCustomEditors, RuleEditorProvider } from "./providers/RuleEditorProvider";
+import { RuleEditorProvider } from "./providers/RuleEditorProvider";
 import { newFile, NewFileType } from "./commands/newFile";
 import { FileDecorationProvider } from "./providers/FileDecorationProvider";
 import { RESTDebugPanel } from "./commands/restDebugPanel";
@@ -148,6 +146,7 @@ import {
   removeIndexOfWorkspaceFolder,
   updateIndexForDocument,
 } from "./utils/documentIndex";
+import { WorkspaceNode, NodeBase } from "./explorer/nodes";
 
 const packageJson = vscode.extensions.getExtension(extensionId).packageJSON;
 const extensionVersion = packageJson.version;
@@ -208,7 +207,7 @@ export let checkingConnection = false;
 
 let serverManagerApi: serverManager.ServerManagerAPI;
 
-// Map of the intersystems.server connection specs we have resolved via the API to that extension
+/** Map of the intersystems.server connection specs we have resolved via the API to that extension */
 const resolvedConnSpecs = new Map<string, any>();
 
 /**
@@ -228,8 +227,7 @@ export async function resolveConnectionSpec(serverName: string): Promise<void> {
   }
 }
 
-// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
-export async function resolvePassword(serverSpec, ignoreUnauthenticated = false): Promise<void> {
+async function resolvePassword(serverSpec, ignoreUnauthenticated = false): Promise<void> {
   if (
     // Connection isn't unauthenticated
     (!isUnauthenticated(serverSpec.username) || ignoreUnauthenticated) &&
@@ -259,26 +257,11 @@ export async function resolvePassword(serverSpec, ignoreUnauthenticated = false)
   }
 }
 
-// Accessor for the cache of resolved connection specs
-// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+/** Accessor for the cache of resolved connection specs */
 export function getResolvedConnectionSpec(key: string, dflt: any): any {
   return resolvedConnSpecs.has(key) ? resolvedConnSpecs.get(key) : dflt;
 }
 
-/**
- * A map of all CSP web apps in a server-namespace.
- * The key is either `serverName:ns`, or `host:port/pathPrefix:ns`, lowercase.
- * The value is an array of CSP apps as returned by GET %25SYS/cspapps.
- */
-export const cspApps: Map<string, string[]> = new Map();
-
-/**
- * A map of all Studio Abstract Document extensions in a server-namespace.
- * The key is either `serverName:ns`, or `host:port/pathPrefix:ns`, lowercase.
- * The value is lowercase array of file extensions, without the dot.
- */
-export const otherDocExts: Map<string, string[]> = new Map();
-
 export async function checkConnection(
   clearCookies = false,
   uri?: vscode.Uri,
@@ -401,8 +384,8 @@ export async function checkConnection(
       otherDocExts.set(
         key,
         await api
-          .actionQuery("SELECT Extension FROM %Library.RoutineMgr_DocumentTypes()", [])
-          .then((data) => data.result?.content?.map((e) => e.Extension) ?? [])
+          .actionQuery("SELECT Extention FROM %Library.RoutineMgr_DocumentTypes()", [])
+          .then((data) => data.result?.content?.map((e) => e.Extention) ?? [])
           .catch(() => [])
       );
     }
@@ -455,9 +438,9 @@ export async function checkConnection(
                   _onDidChangeConnection.fire();
                   success = true;
                 })
-                .catch(async (error) => {
-                  console.log(`Second connect failed: ${error}`);
-                  await setConnectionState(configName, false);
+                .catch(async (err) => {
+                  error = err;
+                  if (error?.statusCode != 401) errorMessage = undefined;
                   await workspaceState.update(wsKey + ":password", undefined);
                   success = false;
                 })
@@ -477,48 +460,43 @@ export async function checkConnection(
                 prompt: !api.externalServer ? "If no password is entered the connection will be disabled." : "",
                 ignoreFocusOut: true,
               })
-              .then(
-                async (password) => {
-                  if (password) {
-                    await workspaceState.update(wsKey + ":password", password);
-                    resolve(
-                      api
-                        .serverInfo(true, serverInfoTimeout)
-                        .then(async (info): Promise<boolean> => {
-                          await gotServerInfo(info);
-                          _onDidChangeConnection.fire();
-                          return true;
-                        })
-                        .catch(async (error) => {
-                          console.log(`Second connect failed: ${error}`);
-                          await setConnectionState(configName, false);
-                          await workspaceState.update(wsKey + ":password", undefined);
-                          return false;
-                        })
-                        .finally(() => {
-                          checkingConnection = false;
-                        })
-                    );
-                  } else if (!api.externalServer) {
-                    await setConnectionState(configName, false);
-                  }
-                  console.log(`Finished prompting for password`);
-                  resolve(false);
-                },
-                (reason) => {
-                  console.log(`showInputBox for password dismissed: ${reason}`);
+              .then(async (password) => {
+                if (password) {
+                  await workspaceState.update(wsKey + ":password", password);
+                  resolve(
+                    api
+                      .serverInfo(true, serverInfoTimeout)
+                      .then(async (info): Promise<boolean> => {
+                        await gotServerInfo(info);
+                        _onDidChangeConnection.fire();
+                        return true;
+                      })
+                      .catch(async (err) => {
+                        error = err;
+                        if (error?.statusCode != 401) errorMessage = undefined;
+                        await workspaceState.update(wsKey + ":password", undefined);
+                        return false;
+                      })
+                      .finally(() => {
+                        checkingConnection = false;
+                      })
+                  );
+                } else if (!api.externalServer) {
+                  await setConnectionState(configName, false);
                 }
-              );
+                resolve(false);
+              });
           });
         }
         if (success) return;
-      } else {
-        errorMessage = `${message}\nCheck your server details in Settings (${connInfo}).`;
       }
-      handleError(errorMessage);
+      handleError(
+        errorMessage ?? error,
+        `Failed to connect to server '${api.serverId}'. Check your server configuration.`
+      );
       panel.text = `${connInfo} $(error)`;
       panel.tooltip = `ERROR - ${message}`;
-      throw error;
+      await setConnectionState(configName, false);
     })
     .finally(() => {
       checkingConnection = false;
@@ -536,8 +514,10 @@ export async function checkConnection(
     });
 }
 
-// Set objectscript.conn.active at WorkspaceFolder level if objectscript.conn is defined there,
-//  else set it at Workspace level
+/**
+ * Set objectscript.conn.active at WorkspaceFolder level if objectscript.conn
+ * is defined there, else set it at Workspace level.
+ */
 function setConnectionState(configName: string, active: boolean) {
   const connConfig: vscode.WorkspaceConfiguration = config("", configName);
   const target: vscode.ConfigurationTarget = connConfig.inspect("conn").workspaceFolderValue
@@ -698,7 +678,6 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
     }
   }
 
-  const languages = packageJson.contributes.languages.map((lang) => lang.id);
   // workaround for Theia, issue https://github.com/eclipse-theia/theia/issues/8435
   workspaceState = {
     keys: context.workspaceState.keys,
@@ -895,6 +874,22 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
   incLangConf = vscode.languages.setLanguageConfiguration(incLangId, getLanguageConfiguration(incLangId));
   intLangConf = vscode.languages.setLanguageConfiguration(intLangId, getLanguageConfiguration(intLangId));
 
+  // Migrate removed importOnSave setting to new, more generic syncLocalChanges
+  const conf = vscode.workspace.getConfiguration("objectscript");
+  const importOnSave = conf.inspect("importOnSave");
+  if (typeof importOnSave.globalValue == "boolean") {
+    if (!importOnSave.globalValue) {
+      conf.update("syncLocalChanges", false, vscode.ConfigurationTarget.Global);
+    }
+    conf.update("importOnSave", undefined, vscode.ConfigurationTarget.Global);
+  }
+  if (typeof importOnSave.workspaceValue == "boolean") {
+    if (!importOnSave.workspaceValue) {
+      conf.update("syncLocalChanges", false, vscode.ConfigurationTarget.Workspace);
+    }
+    conf.update("importOnSave", undefined, vscode.ConfigurationTarget.Workspace);
+  }
+
   context.subscriptions.push(
     reporter,
     panel,
@@ -1340,28 +1335,6 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
         terminals.splice(terminalIndex, 1);
       }
     }),
-    vscode.workspace.onDidSaveTextDocument((file) => {
-      if (openCustomEditors.includes(file.uri.toString())) {
-        // Saving is handled by a different event listener
-        return;
-      }
-      const conf = vscode.workspace.getConfiguration("objectscript", file.uri);
-      if (notIsfs(file.uri) && !conf.get("importOnSave")) {
-        // Don't save this local file on the server
-        return;
-      }
-      if (schemas.includes(file.uri.scheme) || languages.includes(file.languageId)) {
-        if (documentBeingProcessed !== file) {
-          return importAndCompile(false, file, conf.get("compileOnSave"));
-        }
-      } else if (notIsfs(file.uri)) {
-        if (isImportableLocalFile(file.uri) && new AtelierAPI(file.uri).active) {
-          // This local file is part of a CSP application
-          // or matches our export settings, so import it on save
-          return importFileOrFolder(file.uri, true);
-        }
-      }
-    }),
     vscode.window.onDidChangeActiveTextEditor(async (textEditor: vscode.TextEditor) => {
       if (!textEditor) return;
       posPanel.text = "";
diff --git a/src/providers/FileSystemProvider/FileSystemProvider.ts b/src/providers/FileSystemProvider/FileSystemProvider.ts
index 2d094e5a..8a0011c6 100644
--- a/src/providers/FileSystemProvider/FileSystemProvider.ts
+++ b/src/providers/FileSystemProvider/FileSystemProvider.ts
@@ -1,5 +1,6 @@
 import * as path from "path";
 import * as vscode from "vscode";
+import { isText } from "istextorbinary";
 import { AtelierAPI } from "../../api";
 import { Directory } from "./Directory";
 import { File } from "./File";
@@ -15,7 +16,9 @@ import {
   redirectDotvscodeRoot,
   workspaceFolderOfUri,
   stringifyError,
-} from "../../utils/index";
+  base64EncodeContent,
+  openCustomEditors,
+} from "../../utils";
 import {
   config,
   FILESYSTEM_READONLY_SCHEMA,
@@ -28,7 +31,7 @@ import { addIsfsFileToProject, modifyProject } from "../../commands/project";
 import { DocumentContentProvider } from "../DocumentContentProvider";
 import { Document, UserAction } from "../../api/atelier";
 
-export type Entry = File | Directory;
+type Entry = File | Directory;
 
 export function generateFileContent(
   uri: vscode.Uri,
@@ -107,7 +110,7 @@ export function generateFileContent(
     }
   }
   return {
-    content: [Buffer.from(sourceContent).toString("base64")],
+    content: base64EncodeContent(Buffer.from(sourceContent)),
     enc: true,
   };
 }
@@ -415,82 +418,111 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
     const api = new AtelierAPI(uri);
     // Use _lookup() instead of _lookupAsFile() so we send
     // our cached mtime with the GET /doc request if we have it
-    return this._lookup(uri).then(
-      async () => {
-        // Weirdly, if the file exists on the server we don't actually write its content here.
-        // Instead we simply return as though we wrote it successfully.
-        // The actual writing is done by our workspace.onDidSaveTextDocument handler.
-        // But first check cases for which we should fail the write and leave the document dirty if changed.
-        if (!csp && fileName.split(".").pop().toLowerCase() === "cls") {
-          // Check if the class is deployed
-          if (await isClassDeployed(fileName, api)) {
-            throw new Error("Cannot overwrite a deployed class");
-          }
-          // Check if the class name and file name match
-          let clsname = "";
-          const match = new TextDecoder().decode(content).match(classNameRegex);
-          if (match) {
-            [, clsname] = match;
+    return this._lookup(uri)
+      .then(
+        async () => {
+          // Check cases for which we should fail the write and leave the document dirty if changed
+          if (!csp && fileName.split(".").pop().toLowerCase() == "cls") {
+            // Check if the class is deployed
+            if (await isClassDeployed(fileName, api)) {
+              throw new Error("Cannot overwrite a deployed class");
+            }
+            // Check if the class name and file name match
+            let clsname = "";
+            const match = new TextDecoder().decode(content).match(classNameRegex);
+            if (match) {
+              [, clsname] = match;
+            }
+            if (clsname == "") {
+              throw new Error("Cannot save a malformed class");
+            }
+            if (fileName.slice(0, -4) != clsname) {
+              throw new Error("Cannot save an isfs class where the class name and file name do not match");
+            }
           }
-          if (clsname === "") {
-            throw new Error("Cannot save a malformed class");
+          if (openCustomEditors.includes(uri.toString())) {
+            // This class is open in a graphical editor, so any
+            // updates to the class will be handled by that editor
+            return;
           }
-          if (fileName.slice(0, -4) !== clsname) {
-            throw new Error("Cannot save an isfs class where the class name and file name do not match");
+          const contentBuffer = Buffer.from(content);
+          const putContent = isText(uri.path.split("/").pop(), contentBuffer)
+            ? {
+                content: new TextDecoder().decode(content).split(/\r?\n/),
+                enc: false,
+              }
+            : {
+                content: base64EncodeContent(contentBuffer),
+                enc: true,
+              };
+          // By the time we get here VS Code's built-in conflict resolution mechanism will already have interacted with the user.
+          // Therefore, it's safe to ignore any conflicts.
+          return api
+            .putDoc(
+              fileName,
+              {
+                ...putContent,
+                mtime: -1,
+              },
+              true
+            )
+            .then((data) => {
+              workspaceState.update(
+                `${workspaceFolderOfUri(uri)}:${fileName}:mtime`,
+                Number(new Date(data.result.ts + "Z"))
+              );
+            })
+            .catch((error) => {
+              // Throw all failures
+              throw vscode.FileSystemError.Unavailable(stringifyError(error) || uri);
+            });
+        },
+        (error) => {
+          if (error.code !== "FileNotFound" || !options.create) {
+            return Promise.reject();
           }
+          // File doesn't exist on the server, and we are allowed to create it.
+          // Create content (typically a stub, unless the write-phase of a copy operation).
+          const newContent = generateFileContent(uri, fileName, content);
+
+          // Write it to the server
+          return api
+            .putDoc(
+              fileName,
+              {
+                ...newContent,
+                mtime: Date.now(),
+              },
+              false
+            )
+            .catch((error) => {
+              // Throw all failures
+              throw vscode.FileSystemError.Unavailable(stringifyError(error) || uri);
+            })
+            .then((data) => {
+              // New file has been written
+              if (data && data.result.ext && data.result.ext[0] && data.result.ext[1]) {
+                fireOtherStudioAction(OtherStudioAction.CreatedNewDocument, uri, data.result.ext[0]);
+                fireOtherStudioAction(OtherStudioAction.FirstTimeDocumentSave, uri, data.result.ext[1]);
+              }
+              const params = new URLSearchParams(uri.query);
+              if (params.has("project") && params.get("project").length) {
+                // Add this document to the project if required
+                addIsfsFileToProject(params.get("project"), fileName, csp, api);
+              }
+              // Create an entry in our cache for the document
+              this._lookupAsFile(uri);
+            });
         }
-        // Set a -1 mtime cache entry so the actual write by the workspace.onDidSaveTextDocument handler always overwrites.
-        // By the time we get here VS Code's built-in conflict resolution mechanism will already have interacted with the user.
-        const uniqueId = `${workspaceFolderOfUri(uri)}:${fileName}`;
-        workspaceState.update(`${uniqueId}:mtime`, -1);
-        return;
-      },
-      (error) => {
-        if (error.code !== "FileNotFound" || !options.create) {
-          return Promise.reject();
+      )
+      .then(() => {
+        // Compile the document if required
+        if (vscode.workspace.getConfiguration("objectscript", uri).get("compileOnSave")) {
+          this.compile(uri);
+        } else {
+          this._fireSoon({ type: vscode.FileChangeType.Changed, uri });
         }
-        // File doesn't exist on the server, and we are allowed to create it.
-        // Create content (typically a stub, unless the write-phase of a copy operation).
-        const newContent = generateFileContent(uri, fileName, content);
-
-        // Write it to the server
-        return api
-          .putDoc(
-            fileName,
-            {
-              ...newContent,
-              mtime: Date.now(),
-            },
-            false
-          )
-          .catch((error) => {
-            // Throw all failures
-            throw vscode.FileSystemError.Unavailable(stringifyError(error) || uri);
-          })
-          .then(async (response) => {
-            // New file has been written
-            if (response && response.result.ext && response.result.ext[0] && response.result.ext[1]) {
-              fireOtherStudioAction(OtherStudioAction.CreatedNewDocument, uri, response.result.ext[0]);
-              fireOtherStudioAction(OtherStudioAction.FirstTimeDocumentSave, uri, response.result.ext[1]);
-            }
-            const params = new URLSearchParams(uri.query);
-            if (params.has("project") && params.get("project").length) {
-              // Add this document to the project if required
-              await addIsfsFileToProject(params.get("project"), uri, fileName, csp, api);
-            }
-            // Sanity check that we find it there, then make client side update things
-            this._lookupAsFile(uri).then(() => {
-              this._fireSoon({ type: vscode.FileChangeType.Changed, uri });
-            });
-
-            // Ask to put cursor at start of 3rd line.
-            // For CLS stub this will be where properties and methods need to be inserted.
-            // For MAC and INT stubs there is no 3rd line, so cursor goes to the end of the 2nd, which is 1st of actual routine and is ready for comment text.
-            const editor = await vscode.window.showTextDocument(uri);
-            editor.selection = new vscode.Selection(2, 0, 2, 0);
-          });
-      }
-    );
+      });
   }
 
   /** Process a Document object that was successfully deleted. */
diff --git a/src/providers/RuleEditorProvider.ts b/src/providers/RuleEditorProvider.ts
index f7172e3f..32893c8b 100644
--- a/src/providers/RuleEditorProvider.ts
+++ b/src/providers/RuleEditorProvider.ts
@@ -2,13 +2,8 @@ import * as vscode from "vscode";
 import { AtelierAPI } from "../api";
 import { loadChanges } from "../commands/compile";
 import { StudioActions } from "../commands/studio";
-import { clsLangId, cspApps } from "../extension";
-import { currentFile, handleError, outputChannel } from "../utils";
-
-/**
- * The URI strings for all documents that are open in a custom editor.
- */
-export const openCustomEditors: string[] = [];
+import { clsLangId } from "../extension";
+import { cspApps, currentFile, handleError, openCustomEditors, outputChannel } from "../utils";
 
 export class RuleEditorProvider implements vscode.CustomTextEditorProvider {
   private static readonly _webapp: string = "/ui/interop/rule-editor";
diff --git a/src/utils/classDefinition.ts b/src/utils/classDefinition.ts
index 66027589..42c835ed 100644
--- a/src/utils/classDefinition.ts
+++ b/src/utils/classDefinition.ts
@@ -34,7 +34,6 @@ export class ClassDefinition {
     return vscode.workspace.openTextDocument(this.uri);
   }
 
-  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
   public store(kind: string, data: any): any {
     return this._cache.put(kind, data, 36000).then(() => data);
   }
diff --git a/src/utils/documentIndex.ts b/src/utils/documentIndex.ts
index d3f6513d..67b2382c 100644
--- a/src/utils/documentIndex.ts
+++ b/src/utils/documentIndex.ts
@@ -1,8 +1,19 @@
 import * as vscode from "vscode";
-import { CurrentBinaryFile, CurrentTextFile, currentFileFromContent, handleError, notIsfs, outputChannel } from ".";
+import {
+  CurrentBinaryFile,
+  CurrentTextFile,
+  currentFile,
+  currentFileFromContent,
+  exportedUris,
+  getServerDocName,
+  isImportableLocalFile,
+  notIsfs,
+  openCustomEditors,
+  outputChannel,
+} from ".";
+import { isText } from "istextorbinary";
 import { AtelierAPI } from "../api";
 import { compile, importFile } from "../commands/compile";
-import { exportedUris } from "../commands/export";
 
 interface WSFolderIndex {
   /** The `FileSystemWatcher` for this workspace folder */
@@ -14,8 +25,8 @@ interface WSFolderIndex {
 }
 
 interface WSFolderIndexChange {
-  /** InterSystems document added to the index, if any */
-  added?: CurrentTextFile | CurrentBinaryFile;
+  /** InterSystems document added to the index or changed on disk, if any */
+  addedOrChanged?: CurrentTextFile | CurrentBinaryFile;
   /** InterSystems document removed from the index, if any */
   removed?: string;
 }
@@ -29,27 +40,178 @@ const filePattern = "{**/*.cls,**/*.mac,**/*.int,**/*.inc}";
 /** We want decoding errors to be thrown */
 const textDecoder = new TextDecoder("utf-8", { fatal: true });
 
+/** The number of milliseconds that we should wait before sending a compile or delete request */
+const debounceDelay = 500;
+
+/** Returns `true` if `uri` has a class or routine file extension */
+function isClassOrRtn(uri: vscode.Uri): boolean {
+  return ["cls", "mac", "int", "inc"].includes(uri.path.split(".").pop().toLowerCase());
+}
+
+/**
+ * Create an object describing the file in `uri`. Will use the version
+ * of the file in VS Code if it's loaded and supports binary files.
+ */
+async function getCurrentFile(
+  uri: vscode.Uri,
+  forceText = false
+): Promise<CurrentTextFile | CurrentBinaryFile | undefined> {
+  const uriString = uri.toString();
+  const textDocument = vscode.workspace.textDocuments.find((d) => d.uri.toString() == uriString);
+  if (textDocument) {
+    return currentFile(textDocument);
+  } else {
+    try {
+      const contentBytes = await vscode.workspace.fs.readFile(uri);
+      const contentBuffer = Buffer.from(contentBytes);
+      return currentFileFromContent(
+        uri,
+        forceText || isText(uri.path.split("/").pop(), contentBuffer) ? textDecoder.decode(contentBytes) : contentBuffer
+      );
+    } catch (error) {
+      // Either a vscode.FileSystemError from readFile()
+      // or a TypeError from decode(). Don't log TypeError
+      // since the file may be a non-text file that has
+      // an extension that we interpret as text (like cls or mac).
+      // We should ignore such files rather than alerting the user.
+      if (error instanceof vscode.FileSystemError) {
+        outputChannel.appendLine(`Failed to read contents of '${uri.toString(true)}': ${error.toString()}`);
+      }
+    }
+  }
+}
+
+/** Generate a debounced compile function */
+function generateCompileFn(): (doc: CurrentTextFile | CurrentBinaryFile) => void {
+  let timeout: NodeJS.Timeout;
+  const docs: (CurrentTextFile | CurrentBinaryFile)[] = [];
+
+  return (doc: CurrentTextFile | CurrentBinaryFile): void => {
+    docs.push(doc);
+
+    // Clear the previous timeout to reset the debounce timer
+    clearTimeout(timeout);
+
+    // Compile right away if this document is in the active text editor
+    if (vscode.window.activeTextEditor?.document.uri.toString() == doc.uri.toString()) {
+      compile([...docs]);
+      docs.length = 0;
+      return;
+    }
+
+    // Set a new timeout to call the function after the specified delay
+    timeout = setTimeout(() => {
+      compile([...docs]);
+      docs.length = 0;
+    }, debounceDelay);
+  };
+}
+
+/** Generate a debounced delete function. */
+function generateDeleteFn(wsFolderUri: vscode.Uri): (doc: string) => void {
+  let timeout: NodeJS.Timeout;
+  const docs: string[] = [];
+  const api = new AtelierAPI(wsFolderUri);
+
+  return (doc: string): void => {
+    docs.push(doc);
+
+    // Clear the previous timeout to reset the debounce timer
+    clearTimeout(timeout);
+
+    // Set a new timeout to call the function after the specified delay
+    timeout = setTimeout(() => {
+      api.deleteDocs([...docs]).then((data) => {
+        let failed = 0;
+        for (const doc of data.result) {
+          if (doc.status != "") {
+            // The document was not deleted, so log the error
+            failed++;
+            outputChannel.appendLine(`${failed == 1 ? "\n" : ""}${doc.status}`);
+          }
+        }
+        if (failed > 0) {
+          outputChannel.show(true);
+          vscode.window.showErrorMessage(
+            `Failed to delete ${failed} document${
+              failed > 1 ? "s" : ""
+            }. Check the 'ObjectScript' Output channel for details.`,
+            "Dismiss"
+          );
+        }
+      });
+      docs.length = 0;
+    }, debounceDelay);
+  };
+}
+
 /** Create index of `wsFolder` and set up a `FileSystemWatcher` to keep the index up to date */
 export async function indexWorkspaceFolder(wsFolder: vscode.WorkspaceFolder): Promise<void> {
   if (!notIsfs(wsFolder.uri)) return;
-  const pattern = new vscode.RelativePattern(wsFolder, filePattern);
   const documents: Map<string, vscode.Uri[]> = new Map();
   const uris: Map<string, string> = new Map();
-  // Index files that currently exist
-  const files = await vscode.workspace.findFiles(pattern);
+  // Index classes and routines that currently exist
+  const files = await vscode.workspace.findFiles(new vscode.RelativePattern(wsFolder, filePattern));
   for (const file of files) updateIndexForDocument(file, documents, uris);
-  // Watch for changes that may require an index update
-  const watcher = vscode.workspace.createFileSystemWatcher(pattern);
-  watcher.onDidChange((uri) => updateIndexAndSyncChanges(uri, documents, uris));
-  watcher.onDidCreate((uri) => updateIndexAndSyncChanges(uri, documents, uris));
-  watcher.onDidDelete((uri) => {
-    // Remove the class/routine in the file from the index,
-    // then delete it on the server if required
-    const change = removeDocumentFromIndex(uri, documents, uris);
+  // Watch for all file changes
+  const watcher = vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(wsFolder, "**/*"));
+  const debouncedCompile = generateCompileFn();
+  const debouncedDelete = generateDeleteFn(wsFolder.uri);
+  const updateIndexAndSyncChanges = async (uri: vscode.Uri): Promise<void> => {
+    const uriString = uri.toString();
+    if (openCustomEditors.includes(uriString)) {
+      // This class is open in a graphical editor, so its name will not change
+      // and any updates to the class will be handled by that editor
+      return;
+    }
+    const conf = vscode.workspace.getConfiguration("objectscript", uri);
+    const sync: boolean = conf.get("syncLocalChanges");
+    let change: WSFolderIndexChange = {};
+    if (isClassOrRtn(uri)) {
+      change = await updateIndexForDocument(uri, documents, uris);
+    } else if (sync && isImportableLocalFile(uri)) {
+      change.addedOrChanged = await getCurrentFile(uri);
+    }
+    if (!sync || (!change.addedOrChanged && !change.removed)) return;
+    const exportedIdx = exportedUris.findIndex((e) => e == uriString);
+    if (exportedIdx != -1) {
+      // This creation/change event was fired due to a server
+      // export, so don't re-sync the file with the server
+      exportedUris.splice(exportedIdx, 1);
+      return;
+    }
+    const api = new AtelierAPI(uri);
+    if (!api.active) return;
+    if (change.addedOrChanged) {
+      // Create or update the document on the server
+      importFile(change.addedOrChanged)
+        .then(() => {
+          if (conf.get("compileOnSave")) debouncedCompile(change.addedOrChanged);
+        })
+        .catch(() => {});
+    }
     if (change.removed) {
-      const api = new AtelierAPI(uri);
-      if (!api.active) return;
-      api.deleteDoc(change.removed).catch((error) => handleError(error));
+      // Delete document on the server
+      debouncedDelete(change.removed);
+    }
+  };
+  watcher.onDidChange((uri) => updateIndexAndSyncChanges(uri));
+  watcher.onDidCreate((uri) => updateIndexAndSyncChanges(uri));
+  watcher.onDidDelete((uri) => {
+    const sync: boolean = vscode.workspace.getConfiguration("objectscript", uri).get("syncLocalChanges");
+    const api = new AtelierAPI(uri);
+    if (isClassOrRtn(uri)) {
+      // Remove the class/routine in the file from the index,
+      // then delete it on the server if required
+      const change = removeDocumentFromIndex(uri, documents, uris);
+      if (sync && api.active && change.removed) {
+        debouncedDelete(change.removed);
+      }
+    } else if (sync && api.active && isImportableLocalFile(uri)) {
+      // Delete this web application file or Studio abstract document on the server
+      const docName = getServerDocName(uri);
+      if (!docName) return;
+      debouncedDelete(docName);
     }
   });
   wsFolderIndex.set(wsFolder.uri.toString(), { watcher, documents, uris });
@@ -81,32 +243,12 @@ export async function updateIndexForDocument(
     uris = index.uris;
   }
   const documentName = uris.get(uriString);
-  const textDocument = vscode.workspace.textDocuments.find((d) => d.uri.toString() == uriString);
-  let content: string;
-  if (textDocument) {
-    // Get the content from the text document
-    content = textDocument.getText();
-  } else {
-    // Get the content from the file system
-    try {
-      content = textDecoder.decode(await vscode.workspace.fs.readFile(uri));
-    } catch (error) {
-      // Either a vscode.FileSystemError from readFile()
-      // or a TypeError from decode(). Don't log TypeError
-      // since the file may be a non-text file
-      // with a cls, mac, int or inc extension.
-      if (error instanceof vscode.FileSystemError) {
-        outputChannel.appendLine(`Failed to read contents of '${uri.toString(true)}': ${error.toString()}`);
-      }
-      return result;
-    }
-  }
-  const file = currentFileFromContent(uri, content);
+  const file = await getCurrentFile(uri, true);
   if (!file) return result;
+  result.addedOrChanged = file;
   // This file contains an InterSystems document, so add it to the index
   if (!documentName || (documentName && documentName != file.name)) {
     const documentUris = documents.get(file.name) ?? [];
-    if (documentUris.length == 0) result.added = file;
     documentUris.push(uri);
     documents.set(file.name, documentUris);
     uris.set(uriString, file.name);
@@ -162,48 +304,6 @@ function removeDocumentFromIndex(
   return result;
 }
 
-/** Update the entries in the index for `uri` and sync any changes with the server */
-async function updateIndexAndSyncChanges(
-  uri: vscode.Uri,
-  documents?: Map<string, vscode.Uri[]>,
-  uris?: Map<string, string>
-): Promise<void> {
-  const change = await updateIndexForDocument(uri, documents, uris);
-  if (!change.added && !change.removed) return;
-  const uriString = uri.toString();
-  const exportedIdx = exportedUris.findIndex((e) => e == uriString);
-  if (exportedIdx != -1) {
-    // This creation/change event was fired due to a server
-    // export, so don't re-sync the file with the server
-    exportedUris.splice(exportedIdx, 1);
-    return;
-  }
-  if (vscode.workspace.textDocuments.some((td) => td.uri.toString() == uriString)) {
-    // Don't sync with the server because onDidSaveTextDocument will handle it
-    return;
-  }
-  const api = new AtelierAPI(uri);
-  if (!api.active) return;
-  const config = vscode.workspace.getConfiguration("objectscript", uri);
-  if (change.added && config.get("importOnSave")) {
-    // Create the document on the server
-    try {
-      await importFile(change.added);
-      if (config.get("compileOnSave")) await compile([change.added]);
-    } catch (error) {
-      handleError(error);
-    }
-  }
-  if (change.removed) {
-    try {
-      // Delete document on the server
-      await api.deleteDoc(change.removed);
-    } catch (error) {
-      handleError(error);
-    }
-  }
-}
-
 /** Get all `Uri`s for `document` in `wsFolder` */
 export function getUrisForDocument(document: string, wsFolder: vscode.WorkspaceFolder): vscode.Uri[] {
   const index = wsFolderIndex.get(wsFolder.uri.toString());
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 63a66872..cdae36a9 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -7,12 +7,10 @@ import {
   workspaceState,
   terminals,
   extensionContext,
-  cspApps,
   lsExtensionId,
   OBJECTSCRIPT_FILE_SCHEMA,
   documentContentProvider,
   filesystemSchemas,
-  otherDocExts,
 } from "../extension";
 import { getCategory } from "../commands/export";
 import { isCSPFile } from "../providers/FileSystemProvider/FileSystemProvider";
@@ -20,11 +18,37 @@ import { AtelierAPI } from "../api";
 
 export const outputChannel = vscode.window.createOutputChannel("ObjectScript", "vscode-objectscript-output");
 
+/**
+ * A map of all CSP web apps in a server-namespace.
+ * The key is either `serverName:ns`, or `host:port/pathPrefix:ns`, lowercase.
+ * The value is an array of CSP apps as returned by GET %25SYS/cspapps.
+ */
+export const cspApps: Map<string, string[]> = new Map();
+
+/**
+ * A map of all Studio Abstract Document extensions in a server-namespace.
+ * The key is either `serverName:ns`, or `host:port/pathPrefix:ns`, lowercase.
+ * The value is lowercase array of file extensions, without the dot.
+ */
+export const otherDocExts: Map<string, string[]> = new Map();
+
+/**
+ * The URI strings for all documents that are open in a custom editor.
+ */
+export const openCustomEditors: string[] = [];
+
+/**
+ * Array of stringified `Uri`s that have been exported.
+ * Used by the documentIndex to determine if a created/changed
+ * file needs to be synced with the server. If the documentIndex
+ * finds a match in this array, the element is then removed.
+ */
+export const exportedUris: string[] = [];
+
 /**
  * Return a string represenattion of `error`.
  * If `error` is `undefined`, returns the empty string.
  */
-// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
 export function stringifyError(error): string {
   try {
     return (
@@ -54,7 +78,6 @@ let lastErrorStr = "";
  * `vscode.window.showErrorMessage()` with that message plus a reminder to check
  * the Output channel, if an error was appended to it.
  */
-// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
 export function handleError(error, message?: string): void {
   if (!error) return;
   const errorStr = stringifyError(error);
@@ -93,11 +116,13 @@ export interface CurrentBinaryFile extends CurrentFile {
   content: Buffer;
 }
 
-// For workspace roots in the local filesystem, configName is the root's name
-//  which defaults to the folder name, and apiTarget is the same.
-// For isfs roots, configName is the uri.authority (i.e. isfs://this-bit/...)
-//  which is normally the server name as looked up in intersystems.servers, and
-//  apiTarget is the uri.
+/**
+ * For workspace roots in the local filesystem, configName is the root's name
+ * which defaults to the folder name, and apiTarget is the same.
+ * For isfs roots, configName is the uri.authority (i.e. isfs://this-bit/...)
+ * which is normally the server name as looked up in intersystems.servers, and
+ * apiTarget is the uri.
+ */
 export interface ConnectionTarget {
   apiTarget: string | vscode.Uri;
   configName: string;
@@ -128,35 +153,22 @@ function otherDocExtsForUri(uri: vscode.Uri): string[] {
   return otherDocExts.get(`${api.serverId}:${api.config.ns}`.toLowerCase()) ?? [];
 }
 
-/**
- * Returns the path of file `uri` relative to workspace folder `wsUri`.
- * Returns the emptry string if `uri` is not in `wsUri`.
- */
-function filePathNoWsFolder(uri: vscode.Uri, wsUri: vscode.Uri): string {
-  let wsPath = wsUri.path;
-  if (!wsPath.endsWith("/")) wsPath += "/";
-  return uri.path.startsWith(wsPath) ? uri.path.slice(wsPath.length) : "";
-}
-
-/**
- * Determine the server name of a local non-ObjectScript file (any file that's not CLS,MAC,INT,INC).
- * @param uri The uri of the file.
- * @param workspace The workspace the file is in.
- * @param fileExt The extension of the file.
- */
-function getServerDocName(uri: vscode.Uri, workspace: string, fileExt: string): string {
-  if (!workspace) {
-    // No workspace folders are open
-    return null;
-  }
-  const relativeFilePath = filePathNoWsFolder(uri, uriOfWorkspaceFolder(workspace));
-  if (relativeFilePath == "") return null;
+/** Determine the server name of a non-`isfs` non-ObjectScript file (any file that's not CLS,MAC,INT,INC). */
+export function getServerDocName(uri: vscode.Uri): string {
+  const wsFolder = vscode.workspace.getWorkspaceFolder(uri);
+  if (!wsFolder) return;
   const cspIdx = uri.path.lastIndexOf(cspAppsForUri(uri).find((cspApp) => uri.path.includes(cspApp + "/")));
   if (cspIdx != -1) {
     return uri.path.slice(cspIdx);
-  } else if (fileExt == "dfi") {
+  } else if (uri.path.toLowerCase().endsWith(".dfi")) {
+    // Determine the file path relative to the workspace folder path
+    const wsPath = wsFolder.uri.path + wsFolder.uri.path.endsWith("/") ? "" : "/";
+    const relativeFilePath = uri.path.startsWith(wsPath) ? uri.path.slice(wsPath.length) : "";
+    if (relativeFilePath == "") return;
     // Check for matching export settings first. If no match, use base name.
-    const { folder, addCategory } = config("export", workspace);
+    const config = vscode.workspace.getConfiguration("objectscript.export", uri);
+    const folder: string = config.get("folder");
+    const addCategory: boolean = config.get("addCategory");
     let root = [
       typeof folder == "string" && folder.length ? folder : null,
       addCategory ? getCategory(uri.fsPath, addCategory) : null,
@@ -191,48 +203,6 @@ export function isImportableLocalFile(uri: vscode.Uri): boolean {
     cspAppsForUri(uri).some((cspApp) => uri.path.includes(cspApp + "/")) ||
     otherDocExtsForUri(uri).includes(uri.path.split(".").pop().toLowerCase())
   );
-  /*
-  const workspace = workspaceFolderOfUri(uri);
-  if (workspace == "") {
-    // No workspace folders are open
-    return false;
-  }
-  const workspacePath = uriOfWorkspaceFolder(workspace).fsPath;
-  const filePathNoWorkspaceArr = uri.fsPath.replace(workspacePath + path.sep, "").split(path.sep);
-  if (cspAppsForUri(uri).some((cspApp) => uri.path.includes(cspApp + "/"))) {
-    return true;
-  } else {
-    // Check if this is a known "other" document
-    const fileExt = uri.path.split(".").pop().toLowerCase();
-    if (otherDocExtsForUri(uri).includes(fileExt)) {
-      // The server-namespace supports this document type
-      return true;
-    } else {
-      // Fall back to checking if this file matches our export settings
-      const { atelier, folder, addCategory } = config("export", workspace);
-      const expectedRoot = [
-        typeof folder === "string" && folder.length ? folder : null,
-        addCategory ? getCategory(uri.fsPath, addCategory) : null,
-      ]
-        .filter(notNull)
-        .join(path.sep);
-      let filePath = filePathNoWorkspaceArr.join(path.sep);
-      if (filePath.startsWith(expectedRoot)) {
-        filePath = filePath.slice(expectedRoot.length + path.sep.length);
-        if (fileExt == "dfi") {
-          // DFI files can be split using the atelier setting
-          if ((atelier && !filePath.includes("-")) || !atelier) {
-            return true;
-          }
-        } else {
-          // Non-CSP or DFI files cannot be in subdirectories
-          return !filePath.includes(path.sep);
-        }
-      }
-    }
-    return false;
-  }
-    */
 }
 
 /** A regex for extracting the name of a class from its content */
@@ -272,7 +242,7 @@ export function currentFileFromContent(uri: vscode.Uri, content: string | Buffer
     }
   } else {
     if (notIsfs(uri)) {
-      name = getServerDocName(uri, workspaceFolder, fileExt);
+      name = getServerDocName(uri);
     } else {
       name = uri.path;
     }
@@ -349,7 +319,7 @@ export function currentFile(document?: vscode.TextDocument): CurrentTextFile {
     }
   } else {
     if (notIsfs(document.uri)) {
-      name = getServerDocName(document.uri, currentWorkspaceFolder(document), fileExt);
+      name = getServerDocName(document.uri);
     } else {
       name = uri.path;
     }
@@ -499,7 +469,6 @@ export function onlyUnique(value: { name: string }, index: number, self: { name:
   return self.indexOf(value) === index;
 }
 
-// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
 export function notNull(el: any): boolean {
   return el !== null;
 }
@@ -780,6 +749,19 @@ export function notIsfs(uri: vscode.Uri): boolean {
   return !filesystemSchemas.includes(uri.scheme);
 }
 
+/** Base64 encoding must be in chunk size multiple of 3 and within the server's potential 32K string limit */
+export function base64EncodeContent(content: Buffer): string[] {
+  // Output is 4 chars for each 3 input, so 24573/3*4 = 32764
+  const chunkSize = 24573;
+  let start = 0;
+  const result = [];
+  while (start < content.byteLength) {
+    result.push(content.toString("base64", start, start + chunkSize));
+    start += chunkSize;
+  }
+  return result;
+}
+
 // ---------------------------------------------------------------------
 // Source: https://github.com/amsterdamharu/lib/blob/master/src/index.js
 

From 0f400122bce306aa5aad2c6865a2904488b95694 Mon Sep 17 00:00:00 2001
From: Brett Saviano <bsaviano@intersystems.com>
Date: Fri, 3 Jan 2025 12:15:17 -0500
Subject: [PATCH 8/9] Update package.json

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index a318e922..ebcb6c06 100644
--- a/package.json
+++ b/package.json
@@ -84,7 +84,7 @@
       },
       {
         "view": "ObjectScriptExplorer",
-        "contents": "Connect a local workspace folder to an [InterSystems server](https://docs.intersystems.com/components/csp/docbook/DocBook.UI.Page.cls?KEY=GVSCO_ssworkflow) if you want to export or import ObjectScript code.\n[Choose Server and Namespace](command:vscode-objectscript.connectFolderToServerNamespace)\nOr [hide this view](command:vscode-objectscript.hideExplorerForWorkspace) if it is not needed for the current workspace.",
+        "contents": "Connect a local workspace folder to an [InterSystems server](https://docs.intersystems.com/components/csp/docbook/DocBook.UI.Page.cls?KEY=GVSCO_clientflow) if you want to export or import ObjectScript code.\n[Choose Server and Namespace](command:vscode-objectscript.connectFolderToServerNamespace)",
         "when": "vscode-objectscript.explorerRootCount == 0"
       },
       {

From 5ba17a9f59a511d5ecf6cc2f31ba82eaef02d654 Mon Sep 17 00:00:00 2001
From: Brett Saviano <bsaviano@intersystems.com>
Date: Mon, 13 Jan 2025 07:02:19 -0500
Subject: [PATCH 9/9] small tweaks

---
 src/commands/compile.ts |  8 ++++----
 src/commands/export.ts  | 10 +++++++---
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/src/commands/compile.ts b/src/commands/compile.ts
index 73fd698c..bbc8e47a 100644
--- a/src/commands/compile.ts
+++ b/src/commands/compile.ts
@@ -750,7 +750,7 @@ export async function importXMLFiles(): Promise<any> {
       connectionUri = (
         await vscode.window.showWorkspaceFolderPick({
           ignoreFocusOut: true,
-          placeHolder: "Pick the workspace folder to get server connection information from",
+          placeHolder: "Pick a workspace folder. Server-side folders import from the local file system.",
         })
       )?.uri;
     }
@@ -773,9 +773,9 @@ export async function importXMLFiles(): Promise<any> {
         return;
       }
       let defaultUri = vscode.workspace.getWorkspaceFolder(connectionUri)?.uri ?? connectionUri;
-      if (defaultUri.scheme != "file") {
-        // Need a default URI with file scheme or the open dialog
-        // will show the virtual files from the workspace folder
+      if (defaultUri.scheme == FILESYSTEM_SCHEMA) {
+        // Need a default URI without the isfs scheme or the open dialog
+        // will show the server-side files instead of local ones
         defaultUri = vscode.workspace.workspaceFile;
         if (defaultUri.scheme != "file") {
           vscode.window.showErrorMessage(
diff --git a/src/commands/export.ts b/src/commands/export.ts
index 23d5df70..5b44dd69 100644
--- a/src/commands/export.ts
+++ b/src/commands/export.ts
@@ -312,7 +312,7 @@ export async function exportDocumentsToXMLFile(): Promise<void> {
       connectionUri = (
         await vscode.window.showWorkspaceFolderPick({
           ignoreFocusOut: true,
-          placeHolder: "Pick the workspace folder to get server connection information from",
+          placeHolder: "Pick a workspace folder. Server-side folders export to the local file system.",
         })
       )?.uri;
     }
@@ -335,8 +335,8 @@ export async function exportDocumentsToXMLFile(): Promise<void> {
         return;
       }
       let defaultUri = vscode.workspace.getWorkspaceFolder(connectionUri)?.uri ?? connectionUri;
-      if (defaultUri.scheme != "file") {
-        // Need a default URI with file scheme or the save dialog
+      if (schemas.includes(defaultUri.scheme)) {
+        // Need a default URI without the isfs scheme or the save dialog
         // will show the virtual files from the workspace folder
         defaultUri = vscode.workspace.workspaceFile;
         if (defaultUri.scheme != "file") {
@@ -349,6 +349,10 @@ export async function exportDocumentsToXMLFile(): Promise<void> {
         // Remove the file name from the URI
         defaultUri = defaultUri.with({ path: defaultUri.path.split("/").slice(0, -1).join("/") });
       }
+      if (!vscode.workspace.fs.isWritableFileSystem(defaultUri.scheme)) {
+        vscode.window.showErrorMessage(`Cannot export to read-only file system '${defaultUri.scheme}'.`, "Dismiss");
+        return;
+      }
       // Prompt the user for the documents to export
       const documents = await pickDocuments(api, "to export");
       if (documents.length == 0) {