[llvm] [LLVM][UTILS][VSCODE] Add LLVM LSP support in LLVM VS Code extension (PR #170489)

via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 3 06:47:09 PST 2025


https://github.com/Bertik23 created https://github.com/llvm/llvm-project/pull/170489

This PR is part of the LLVM IR LSP server project ([RFC](https://discourse.llvm.org/t/rfc-ir-visualization-with-vs-code-extension-using-an-lsp-server/87773))

With this PR we update the current VS Code extension, to support the new LSP server (#161969).

Most of the code and project structure was directly copied from the MLIR VS Code extension with some modifications.
It supports two custom LSP messages `llvm/getCfg` and `llvm/bbLocation` that are used for displaying CFGs and cross navigation between the IR and CFG.

>From 4349522e78bb110b8d3184bc547262641ff4f3fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Albert=20Havli=C4=8Dek?= <ahavlicek at azul.com>
Date: Wed, 3 Dec 2025 14:35:46 +0000
Subject: [PATCH] [LLVM][UTILS][VSCODE] Add LLVM LSP support in LLVM VS Code
 extension

---
 llvm/utils/vscode/llvm/.gitignore             |    7 +-
 llvm/utils/vscode/llvm/.vscode/launch.json    |   23 +
 llvm/utils/vscode/llvm/.vscode/settings.json  |   11 +
 llvm/utils/vscode/llvm/.vscode/tasks.json     |   33 +
 llvm/utils/vscode/llvm/.vscodeignore          |    2 +-
 llvm/utils/vscode/llvm/README.md              |  189 +-
 llvm/utils/vscode/llvm/package-lock.json      | 3585 ++++++++++++++---
 llvm/utils/vscode/llvm/package.json           |  301 +-
 llvm/utils/vscode/llvm/src/command.ts         |   29 +
 llvm/utils/vscode/llvm/src/config.ts          |   23 +
 llvm/utils/vscode/llvm/src/configWatcher.ts   |   88 +
 llvm/utils/vscode/llvm/src/extension.ts       |   41 +-
 llvm/utils/vscode/llvm/src/llvmCfg.ts         |  246 ++
 llvm/utils/vscode/llvm/src/llvmContext.ts     |  315 ++
 .../vscode/llvm/src/lspCustomMessages.ts      |   35 +
 .../vscode/llvm/templates/cfgViewer.html      |  609 +++
 llvm/utils/vscode/llvm/tsconfig.json          |   16 +-
 17 files changed, 4951 insertions(+), 602 deletions(-)
 create mode 100644 llvm/utils/vscode/llvm/.vscode/launch.json
 create mode 100644 llvm/utils/vscode/llvm/.vscode/settings.json
 create mode 100644 llvm/utils/vscode/llvm/.vscode/tasks.json
 create mode 100644 llvm/utils/vscode/llvm/src/command.ts
 create mode 100644 llvm/utils/vscode/llvm/src/config.ts
 create mode 100644 llvm/utils/vscode/llvm/src/configWatcher.ts
 create mode 100644 llvm/utils/vscode/llvm/src/llvmCfg.ts
 create mode 100644 llvm/utils/vscode/llvm/src/llvmContext.ts
 create mode 100644 llvm/utils/vscode/llvm/src/lspCustomMessages.ts
 create mode 100644 llvm/utils/vscode/llvm/templates/cfgViewer.html

diff --git a/llvm/utils/vscode/llvm/.gitignore b/llvm/utils/vscode/llvm/.gitignore
index 2bee7f99f4753..b5aae9daf1566 100644
--- a/llvm/utils/vscode/llvm/.gitignore
+++ b/llvm/utils/vscode/llvm/.gitignore
@@ -1,4 +1,9 @@
 node_modules
 *~
 syntaxes/ll.tmLanguage.json
-out/
\ No newline at end of file
+out/
+out
+.vscode-test
+*.vsix
+
+!.vscode
diff --git a/llvm/utils/vscode/llvm/.vscode/launch.json b/llvm/utils/vscode/llvm/.vscode/launch.json
new file mode 100644
index 0000000000000..421ba76886427
--- /dev/null
+++ b/llvm/utils/vscode/llvm/.vscode/launch.json
@@ -0,0 +1,23 @@
+{
+	"version": "0.2.0",
+	"configurations": [
+		{
+			"type": "extensionHost",
+			"request": "launch",
+			"name": "Run Extension",
+			"runtimeExecutable": "${execPath}",
+			"args": [
+				"--extensionDevelopmentPath=${workspaceRoot}"
+			],
+			"autoAttachChildProcesses": true,
+			"sourceMaps": true,
+			"outFiles": [
+				"${workspaceRoot}/out/**/*.js"
+			],
+			"preLaunchTask": {
+				"type": "npm",
+				"script": "watch"
+			}
+		}
+	]
+}
\ No newline at end of file
diff --git a/llvm/utils/vscode/llvm/.vscode/settings.json b/llvm/utils/vscode/llvm/.vscode/settings.json
new file mode 100644
index 0000000000000..cf96cd9949fd0
--- /dev/null
+++ b/llvm/utils/vscode/llvm/.vscode/settings.json
@@ -0,0 +1,11 @@
+{
+	"files.exclude": {
+		"out": false // set this to true to hide the "out" folder with the compiled JS files
+	},
+	"search.exclude": {
+		"out": true // set this to false to include "out" folder in search results
+	},
+	// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
+	"typescript.tsc.autoDetect": "off",
+	"typescript.preferences.quoteStyle": "single",
+}
\ No newline at end of file
diff --git a/llvm/utils/vscode/llvm/.vscode/tasks.json b/llvm/utils/vscode/llvm/.vscode/tasks.json
new file mode 100644
index 0000000000000..5efd8048880a1
--- /dev/null
+++ b/llvm/utils/vscode/llvm/.vscode/tasks.json
@@ -0,0 +1,33 @@
+{
+	"version": "2.0.0",
+	"tasks": [
+		{
+			"type": "npm",
+			"script": "compile",
+			"group": "build",
+			"presentation": {
+				"panel": "dedicated",
+				"reveal": "never"
+			},
+			"problemMatcher": [
+				"$tsc"
+			]
+		},
+		{
+			"type": "npm",
+			"script": "watch",
+			"isBackground": true,
+			"group": {
+				"kind": "build",
+				"isDefault": true
+			},
+			"presentation": {
+				"panel": "dedicated",
+				"reveal": "never"
+			},
+			"problemMatcher": [
+				"$tsc-watch"
+			]
+		}
+	]
+}
\ No newline at end of file
diff --git a/llvm/utils/vscode/llvm/.vscodeignore b/llvm/utils/vscode/llvm/.vscodeignore
index d63f792794e25..40247a2d11a37 100644
--- a/llvm/utils/vscode/llvm/.vscodeignore
+++ b/llvm/utils/vscode/llvm/.vscodeignore
@@ -4,4 +4,4 @@
 vsc-extension-quickstart.md
 syntaxes/ll.tmLanguage.yaml
 **/*.ts
-**/tsconfig.json
\ No newline at end of file
+**/tsconfig.json
diff --git a/llvm/utils/vscode/llvm/README.md b/llvm/utils/vscode/llvm/README.md
index 57196947ee0d5..0104c16ecdebc 100644
--- a/llvm/utils/vscode/llvm/README.md
+++ b/llvm/utils/vscode/llvm/README.md
@@ -1,46 +1,195 @@
-# VS Code Extension For LLVM Dev
+# LLVM Development VS Code Extension
+
+This VS Code extension provides a comprehensive suite of tools for working with LLVM projects. It includes syntax highlighting, LIT integration, and a custom LLVM IR visualizer with LSP-backed commands.
+
+---
 
 ## Features
- - LLVM IR files (.ll) syntax highlighting.
-    (manually translated from `llvm/utils/vim/syntax/llvm.vim`)
- - TableGen files (.td) syntax highlighting.
-    (translated from `llvm/utils/textmate`)
- - PatternMatchers for LIT test output.
-    (`$llvm-lit`, `$llvm-filecheck`)
- - Tasks to run LIT on current selected file.
-    (`Terminal` -> `Run Task` -> `llvm-lit`)
+
+### Syntax Highlighting
+- **LLVM IR (.ll)** — syntax highlighting translated from `llvm/utils/vim/syntax/llvm.vim`
+- **TableGen (.td)** — syntax highlighting from `llvm/utils/textmate`
+
+### LIT Test Integration
+- Pattern matchers for LIT test output (`$llvm-lit`, `$llvm-filecheck`)
+- VS Code Tasks to run LIT on the current file:
+  - `Terminal` → `Run Task` → `llvm-lit`
+
+### LLVM IR Visualizer
+- Integrated LSP-based webview visualization of CFGs
+- Navigation between IR and CFG nodes
+- Running of optimization pipelines and retrieving IR after arbitrary pass
+- Supports custom LSP messages:
+  - `llvm/getCfg` — view CFG as SVG
+  - `llvm/bbLocation` — jump to IR location from CFG node
+
+---
 
 ## Installation
 
-```sh
+### Prerequisites
+
+```bash
 sudo apt-get install nodejs-dev node-gyp npm
 sudo npm install -g typescript npx vsce
 ```
 
 ### Install From Source
-```sh
+
+```bash
 cd <extensions-installation-folder>
 cp -r llvm/utils/vscode/llvm .
 cd llvm
 npm install
 npm run vscode:prepublish
 ```
-`<extensions-installation-folder>` is OS dependent.
 
-Please refer to https://code.visualstudio.com/docs/editor/extension-gallery#_where-are-extensions-installed
+📌 `<extensions-installation-folder>` is OS dependent. See:  
+https://code.visualstudio.com/docs/editor/extension-gallery#_where-are-extensions-installed
 
 ### Install From Package (.vsix)
 
-First package the extension according to
-https://code.visualstudio.com/api/working-with-extensions/publishing-extension#usage.
+1. Package the extension:  
+   https://code.visualstudio.com/api/working-with-extensions/publishing-extension#usage  
+2. Install the `.vsix`:  
+   https://code.visualstudio.com/docs/editor/extension-gallery#_install-from-a-vsix
 
-Then install the package according to
-https://code.visualstudio.com/docs/editor/extension-gallery#_install-from-a-vsix.
+---
 
 ## Setup
 
-Set `cmake.buildDirectory` to your build directory.
+Set the following in your VS Code settings:
+
+```json
+"cmake.buildDirectory": "<your-cmake-build-dir>",
+"llvm.server_path": "<path-to-llvm-lsp-server>"
+```
+
+If `"llvm.server_path"` is not set, the extension will search for `llvm-lsp-server` in your system `PATH`.
+
+Resources:
+- [VS Code User Settings](https://code.visualstudio.com/docs/getstarted/settings)
+- [CMake Tools: buildDirectory](https://vector-of-bool.github.io/docs/vscode-cmake-tools/settings.html#cmake-builddirectory)
+
+---
+
+## Development
+
+### Build & Debug
+
+```bash
+npm install
+npm run compile
+```
+
+Alternatively:
+1. Open `package.json` in VS Code.
+2. Click the `Debug` button next to any script under the `scripts` section.
+3. Open `src/extension.ts`, press `F5` (Debug: Start Debugging).
+4. A new window titled `[Extension Development Host]` will launch.
+
+### Debugging LSP Communication
+
+In the Extension Development Host:
+- Open the **Output** pane (`Ctrl+Shift+U`)
+- Select `llvm-lsp-server` from the dropdown
+- Make sure the setting `llvm.trace.server` is set to `"messages"` or `"verbose"`
+
+---
+
+## Usage
+
+### Viewing the Control Flow Graph (CFG)
+
+#### Open a CFG for a Function.
+1. Place your cursor inside the function you want to visualize.
+2. A yellow lightbulb icon will appear in the gutter (to the left of the line numbers).
+3. Click the lightbulb and select **Open CFG view**.
+4. The CFG view will open. If a CFG view for this function is already open, it will be brought into focus.
+5. The view will automatically center on the basic block where your cursor is located.
+
+#### Highlighting Basic Blocks
+1. In the CFG view, click on any empty space in a basic block to highlight it in the source editor.
+2. The editor will reveal and select the corresponding block. If the file is not already open, it will be opened.
+
+#### Navigating the CFG view
+**Search:** Use the search bar at the top to highlight and iterate through all matching results.
+
+**Move:** Hold <kbd>Ctrl</kbd> and drag to move around the view.
+
+**Zoom:** Hold <kbd>Ctrl</kbd> and scroll to zoom in or out.
+
+
+All generated files, including `.dot` and `.svg` files for the CFGs, are stored in a new directory. This directory is named `Artifacts-<ll file name>` and is located next to the original `.ll` file.
+
+
+## Custom LSP Messages
+
+### `llvm/getCfg`
+
+Request:
+```json
+{
+  "method": "llvm/getCfg",
+  "params": {
+    "uri": "file:///path/to/ir.ll",
+    "position": { "line": 0, "character": 0 }
+  }
+}
+```
+
+Response:
+```json
+{
+  "result": {
+    "uri": "file:///path/to/ir.svg",
+    "node_id": "node1",
+    "function": "main"
+  }
+}
+```
+
+---
+
+### `llvm/bbLocation`
+
+Request:
+```json
+{
+  "method": "llvm/bbLocation",
+  "params": {
+    "uri": "file:///path/to/ir.svg",
+    "node_id": "node1"
+  }
+}
+```
+
+Response:
+```json
+{
+  "result": {
+    "uri": "file:///path/to/ir.ll",
+    "range": {
+      "start": { "line": 0, "character": 0 },
+      "end": { "line": 0, "character": 0 }
+    }
+  }
+}
+```
+
+---
+
+## Project Structure
 
-https://code.visualstudio.com/docs/getstarted/settings
+### `package.json`
+Metadata and configuration:
+- Extension name, version, engines, activation events, etc.
+- Contributions:
+  - `languages`, `commands`, `menus`, `configuration`
 
-https://vector-of-bool.github.io/docs/vscode-cmake-tools/settings.html#cmake-builddirectory
+### `src/` — TypeScript sources
+- `extension.ts`
+  - Entry point: creates `OutputChannel`, `LLVMContext`, and registers commands
+- `llvmContext.ts`
+  - `WorkspaceFolderContext`: manages `LanguageClient` per workspace
+  - `LLVMContext`: manages lifecycle, subscriptions, and per-folder context
diff --git a/llvm/utils/vscode/llvm/package-lock.json b/llvm/utils/vscode/llvm/package-lock.json
index 9559768c1919c..f51dd9500d007 100644
--- a/llvm/utils/vscode/llvm/package-lock.json
+++ b/llvm/utils/vscode/llvm/package-lock.json
@@ -1,467 +1,3150 @@
 {
-    "name": "llvm",
-    "version": "0.0.1",
-    "lockfileVersion": 3,
-    "requires": true,
-    "packages": {
-        "": {
-            "name": "llvm",
-            "version": "0.0.1",
-            "devDependencies": {
-                "@types/node": "^8.10.59",
-                "@types/vscode": "^1.39.0",
-                "js-yaml": "^3.13.1",
-                "tslint": "^5.16.0",
-                "typescript": "^3.8.3"
-            },
-            "engines": {
-                "vscode": "^1.42.0"
-            }
+  "name": "llvm",
+  "version": "0.0.2",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "llvm",
+      "version": "0.0.2",
+      "dependencies": {
+        "base64-js": "^1.5.1",
+        "chokidar": "3.5.2",
+        "vscode-languageclient": "^9.0.1"
+      },
+      "devDependencies": {
+        "@types/mocha": "^7.0.2",
+        "@types/node": "^14.17.0",
+        "@types/vscode": "~1.92.0",
+        "@vscode/vsce": "^2.19.0",
+        "clang-format": "^1.8.0",
+        "js-yaml": "^3.13.1",
+        "typescript": "^4.9.5",
+        "vscode-test": "^1.3.0"
+      },
+      "engines": {
+        "vscode": "^1.42.0"
+      }
+    },
+    "node_modules/@azure/abort-controller": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
+      "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@azure/core-auth": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.9.0.tgz",
+      "integrity": "sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azure/abort-controller": "^2.0.0",
+        "@azure/core-util": "^1.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@azure/core-client": {
+      "version": "1.9.4",
+      "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.4.tgz",
+      "integrity": "sha512-f7IxTD15Qdux30s2qFARH+JxgwxWLG2Rlr4oSkPGuLWm+1p5y1+C04XGLA0vmX6EtqfutmjvpNmAfgwVIS5hpw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azure/abort-controller": "^2.0.0",
+        "@azure/core-auth": "^1.4.0",
+        "@azure/core-rest-pipeline": "^1.20.0",
+        "@azure/core-tracing": "^1.0.0",
+        "@azure/core-util": "^1.6.1",
+        "@azure/logger": "^1.0.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@azure/core-rest-pipeline": {
+      "version": "1.20.0",
+      "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.20.0.tgz",
+      "integrity": "sha512-ASoP8uqZBS3H/8N8at/XwFr6vYrRP3syTK0EUjDXQy0Y1/AUS+QeIRThKmTNJO2RggvBBxaXDPM7YoIwDGeA0g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azure/abort-controller": "^2.0.0",
+        "@azure/core-auth": "^1.8.0",
+        "@azure/core-tracing": "^1.0.1",
+        "@azure/core-util": "^1.11.0",
+        "@azure/logger": "^1.0.0",
+        "@typespec/ts-http-runtime": "^0.2.2",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@azure/core-tracing": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.2.0.tgz",
+      "integrity": "sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@azure/core-util": {
+      "version": "1.12.0",
+      "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.12.0.tgz",
+      "integrity": "sha512-13IyjTQgABPARvG90+N2dXpC+hwp466XCdQXPCRlbWHgd3SJd5Q1VvaBGv6k1BIa4MQm6hAF1UBU1m8QUxV8sQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azure/abort-controller": "^2.0.0",
+        "@typespec/ts-http-runtime": "^0.2.2",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@azure/identity": {
+      "version": "4.10.0",
+      "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.10.0.tgz",
+      "integrity": "sha512-iT53Sre2NJK6wzMWnvpjNiR3md597LZ3uK/5kQD2TkrY9vqhrY5bt2KwELNjkOWQ9n8S/92knj/QEykTtjMNqQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azure/abort-controller": "^2.0.0",
+        "@azure/core-auth": "^1.9.0",
+        "@azure/core-client": "^1.9.2",
+        "@azure/core-rest-pipeline": "^1.17.0",
+        "@azure/core-tracing": "^1.0.0",
+        "@azure/core-util": "^1.11.0",
+        "@azure/logger": "^1.0.0",
+        "@azure/msal-browser": "^4.2.0",
+        "@azure/msal-node": "^3.5.0",
+        "open": "^10.1.0",
+        "tslib": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@azure/logger": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.2.0.tgz",
+      "integrity": "sha512-0hKEzLhpw+ZTAfNJyRrn6s+V0nDWzXk9OjBr2TiGIu0OfMr5s2V4FpKLTAK3Ca5r5OKLbf4hkOGDPyiRjie/jA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typespec/ts-http-runtime": "^0.2.2",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@azure/msal-browser": {
+      "version": "4.13.0",
+      "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.13.0.tgz",
+      "integrity": "sha512-n2ySryLd+wHmm/0Y1mwFI4J9UXVCu2DeWKtoWNWLVcpvK2k0Ez1qIigKleUm2ZfTbfAXdue+V8htmFft0qgyGQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azure/msal-common": "15.7.0"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/@azure/msal-common": {
+      "version": "15.7.0",
+      "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.7.0.tgz",
+      "integrity": "sha512-m9M5hoFoxhe/HlXNVa4qBHekrX60CVPkWzsjhKQGuzw/OPOmurosKRPDIMn8fug/E1hHI5v33DvT1LVJfItjcg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/@azure/msal-node": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.6.0.tgz",
+      "integrity": "sha512-MRZ38Ou6l9LiRkz/968mG0czfIvD1PxMZ/3Jyz5k00ZMnhNOwv+DIliEcy//laoWDobAAq+/cz97xefCcHPgjg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azure/msal-common": "15.7.0",
+        "jsonwebtoken": "^9.0.0",
+        "uuid": "^8.3.0"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "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==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@types/mocha": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz",
+      "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "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,
+      "license": "MIT"
+    },
+    "node_modules/@types/vscode": {
+      "version": "1.92.0",
+      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.92.0.tgz",
+      "integrity": "sha512-DcZoCj17RXlzB4XJ7IfKdPTcTGDLYvTOcTNkvtjXWF+K2TlKzHHkBEXNWQRpBIXixNEUgx39cQeTFunY0E2msw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@typespec/ts-http-runtime": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.2.2.tgz",
+      "integrity": "sha512-Gz/Sm64+Sq/vklJu1tt9t+4R2lvnud8NbTD/ZfpZtMiUX7YeVpCA8j6NSW8ptwcoLL+NmYANwqP8DV0q/bwl2w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "http-proxy-agent": "^7.0.0",
+        "https-proxy-agent": "^7.0.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@vscode/vsce": {
+      "version": "2.32.0",
+      "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.32.0.tgz",
+      "integrity": "sha512-3EFJfsgrSftIqt3EtdRcAygy/OJ3hstyI1cDmIgkU9CFZW5C+3djr6mfosndCUqcVYuyjmxOK1xmFp/Bq7+NIg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azure/identity": "^4.1.0",
+        "@vscode/vsce-sign": "^2.0.0",
+        "azure-devops-node-api": "^12.5.0",
+        "chalk": "^2.4.2",
+        "cheerio": "^1.0.0-rc.9",
+        "cockatiel": "^3.1.2",
+        "commander": "^6.2.1",
+        "form-data": "^4.0.0",
+        "glob": "^7.0.6",
+        "hosted-git-info": "^4.0.2",
+        "jsonc-parser": "^3.2.0",
+        "leven": "^3.1.0",
+        "markdown-it": "^12.3.2",
+        "mime": "^1.3.4",
+        "minimatch": "^3.0.3",
+        "parse-semver": "^1.1.1",
+        "read": "^1.0.7",
+        "semver": "^7.5.2",
+        "tmp": "^0.2.1",
+        "typed-rest-client": "^1.8.4",
+        "url-join": "^4.0.1",
+        "xml2js": "^0.5.0",
+        "yauzl": "^2.3.1",
+        "yazl": "^2.2.2"
+      },
+      "bin": {
+        "vsce": "vsce"
+      },
+      "engines": {
+        "node": ">= 16"
+      },
+      "optionalDependencies": {
+        "keytar": "^7.7.0"
+      }
+    },
+    "node_modules/@vscode/vsce-sign": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.0.5.tgz",
+      "integrity": "sha512-GfYWrsT/vypTMDMgWDm75iDmAOMe7F71sZECJ+Ws6/xyIfmB3ELVnVN+LwMFAvmXY+e6eWhR2EzNGF/zAhWY3Q==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "SEE LICENSE IN LICENSE.txt",
+      "optionalDependencies": {
+        "@vscode/vsce-sign-alpine-arm64": "2.0.2",
+        "@vscode/vsce-sign-alpine-x64": "2.0.2",
+        "@vscode/vsce-sign-darwin-arm64": "2.0.2",
+        "@vscode/vsce-sign-darwin-x64": "2.0.2",
+        "@vscode/vsce-sign-linux-arm": "2.0.2",
+        "@vscode/vsce-sign-linux-arm64": "2.0.2",
+        "@vscode/vsce-sign-linux-x64": "2.0.2",
+        "@vscode/vsce-sign-win32-arm64": "2.0.2",
+        "@vscode/vsce-sign-win32-x64": "2.0.2"
+      }
+    },
+    "node_modules/@vscode/vsce-sign-alpine-arm64": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.2.tgz",
+      "integrity": "sha512-E80YvqhtZCLUv3YAf9+tIbbqoinWLCO/B3j03yQPbjT3ZIHCliKZlsy1peNc4XNZ5uIb87Jn0HWx/ZbPXviuAQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "SEE LICENSE IN LICENSE.txt",
+      "optional": true,
+      "os": [
+        "alpine"
+      ]
+    },
+    "node_modules/@vscode/vsce-sign-alpine-x64": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.2.tgz",
+      "integrity": "sha512-n1WC15MSMvTaeJ5KjWCzo0nzjydwxLyoHiMJHu1Ov0VWTZiddasmOQHekA47tFRycnt4FsQrlkSCTdgHppn6bw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "SEE LICENSE IN LICENSE.txt",
+      "optional": true,
+      "os": [
+        "alpine"
+      ]
+    },
+    "node_modules/@vscode/vsce-sign-darwin-arm64": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.2.tgz",
+      "integrity": "sha512-rz8F4pMcxPj8fjKAJIfkUT8ycG9CjIp888VY/6pq6cuI2qEzQ0+b5p3xb74CJnBbSC0p2eRVoe+WgNCAxCLtzQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "SEE LICENSE IN LICENSE.txt",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@vscode/vsce-sign-darwin-x64": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.2.tgz",
+      "integrity": "sha512-MCjPrQ5MY/QVoZ6n0D92jcRb7eYvxAujG/AH2yM6lI0BspvJQxp0o9s5oiAM9r32r9tkLpiy5s2icsbwefAQIw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "SEE LICENSE IN LICENSE.txt",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@vscode/vsce-sign-linux-arm": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.2.tgz",
+      "integrity": "sha512-Fkb5jpbfhZKVw3xwR6t7WYfwKZktVGNXdg1m08uEx1anO0oUPUkoQRsNm4QniL3hmfw0ijg00YA6TrxCRkPVOQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "SEE LICENSE IN LICENSE.txt",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@vscode/vsce-sign-linux-arm64": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.2.tgz",
+      "integrity": "sha512-Ybeu7cA6+/koxszsORXX0OJk9N0GgfHq70Wqi4vv2iJCZvBrOWwcIrxKjvFtwyDgdeQzgPheH5nhLVl5eQy7WA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "SEE LICENSE IN LICENSE.txt",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@vscode/vsce-sign-linux-x64": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.2.tgz",
+      "integrity": "sha512-NsPPFVtLaTlVJKOiTnO8Cl78LZNWy0Q8iAg+LlBiCDEgC12Gt4WXOSs2pmcIjDYzj2kY4NwdeN1mBTaujYZaPg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "SEE LICENSE IN LICENSE.txt",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@vscode/vsce-sign-win32-arm64": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.2.tgz",
+      "integrity": "sha512-wPs848ymZ3Ny+Y1Qlyi7mcT6VSigG89FWQnp2qRYCyMhdJxOpA4lDwxzlpL8fG6xC8GjQjGDkwbkWUcCobvksQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "SEE LICENSE IN LICENSE.txt",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@vscode/vsce-sign-win32-x64": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.2.tgz",
+      "integrity": "sha512-pAiRN6qSAhDM5SVOIxgx+2xnoVUePHbRNC7OD2aOR3WltTKxxF25OfpK8h8UQ7A0BuRkSgREbB59DBlFk4iAeg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "SEE LICENSE IN LICENSE.txt",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/agent-base": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
+      "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "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,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "license": "ISC",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "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,
+      "license": "Python-2.0"
+    },
+    "node_modules/async": {
+      "version": "3.2.6",
+      "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+      "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/azure-devops-node-api": {
+      "version": "12.5.0",
+      "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz",
+      "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tunnel": "0.0.6",
+        "typed-rest-client": "^1.8.4"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "license": "MIT"
+    },
+    "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==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
         },
-        "node_modules/@babel/code-frame": {
-            "version": "7.21.4",
-            "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
-            "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==",
-            "dev": true,
-            "dependencies": {
-                "@babel/highlight": "^7.18.6"
-            },
-            "engines": {
-                "node": ">=6.9.0"
-            }
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
         },
-        "node_modules/@babel/helper-validator-identifier": {
-            "version": "7.19.1",
-            "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
-            "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
-            "dev": true,
-            "engines": {
-                "node": ">=6.9.0"
-            }
-        },
-        "node_modules/@babel/highlight": {
-            "version": "7.18.6",
-            "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
-            "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-validator-identifier": "^7.18.6",
-                "chalk": "^2.0.0",
-                "js-tokens": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=6.9.0"
-            }
-        },
-        "node_modules/@types/node": {
-            "version": "8.10.66",
-            "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz",
-            "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==",
-            "dev": true
-        },
-        "node_modules/@types/vscode": {
-            "version": "1.78.0",
-            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.78.0.tgz",
-            "integrity": "sha512-LJZIJpPvKJ0HVQDqfOy6W4sNKUBBwyDu1Bs8chHBZOe9MNuKTJtidgZ2bqjhmmWpUb0TIIqv47BFUcVmAsgaVA==",
-            "dev": true
-        },
-        "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/argparse": {
-            "version": "1.0.10",
-            "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-            "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-            "dev": true,
-            "dependencies": {
-                "sprintf-js": "~1.0.2"
-            }
-        },
-        "node_modules/balanced-match": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
-            "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
-            "dev": true
-        },
-        "node_modules/brace-expansion": {
-            "version": "1.1.11",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-            "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-            "dev": true,
-            "dependencies": {
-                "balanced-match": "^1.0.0",
-                "concat-map": "0.0.1"
-            }
-        },
-        "node_modules/builtin-modules": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
-            "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=0.10.0"
-            }
-        },
-        "node_modules/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/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/color-name": {
-            "version": "1.1.3",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-            "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
-            "dev": true
-        },
-        "node_modules/commander": {
-            "version": "2.20.3",
-            "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-            "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-            "dev": true
-        },
-        "node_modules/concat-map": {
-            "version": "0.0.1",
-            "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-            "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
-            "dev": true
-        },
-        "node_modules/diff": {
-            "version": "4.0.2",
-            "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
-            "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
-            "dev": true,
-            "engines": {
-                "node": ">=0.3.1"
-            }
-        },
-        "node_modules/escape-string-regexp": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-            "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
-            "dev": true,
-            "engines": {
-                "node": ">=0.8.0"
-            }
-        },
-        "node_modules/esprima": {
-            "version": "4.0.1",
-            "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-            "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-            "dev": true,
-            "bin": {
-                "esparse": "bin/esparse.js",
-                "esvalidate": "bin/esvalidate.js"
-            },
-            "engines": {
-                "node": ">=4"
-            }
-        },
-        "node_modules/fs.realpath": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-            "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
-            "dev": true
-        },
-        "node_modules/function-bind": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-            "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
-            "dev": true
-        },
-        "node_modules/glob": {
-            "version": "7.2.3",
-            "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
-            "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
-            "dev": true,
-            "dependencies": {
-                "fs.realpath": "^1.0.0",
-                "inflight": "^1.0.4",
-                "inherits": "2",
-                "minimatch": "^3.1.1",
-                "once": "^1.3.0",
-                "path-is-absolute": "^1.0.0"
-            },
-            "engines": {
-                "node": "*"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/isaacs"
-            }
-        },
-        "node_modules/has": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
-            "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
-            "dev": true,
-            "dependencies": {
-                "function-bind": "^1.1.1"
-            },
-            "engines": {
-                "node": ">= 0.4.0"
-            }
-        },
-        "node_modules/has-flag": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-            "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
-            "dev": true,
-            "engines": {
-                "node": ">=4"
-            }
-        },
-        "node_modules/inflight": {
-            "version": "1.0.6",
-            "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-            "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
-            "dev": true,
-            "dependencies": {
-                "once": "^1.3.0",
-                "wrappy": "1"
-            }
-        },
-        "node_modules/inherits": {
-            "version": "2.0.4",
-            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-            "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-            "dev": true
-        },
-        "node_modules/is-core-module": {
-            "version": "2.12.1",
-            "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
-            "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
-            "dev": true,
-            "dependencies": {
-                "has": "^1.0.3"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "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==",
-            "dev": true,
-            "dependencies": {
-                "argparse": "^1.0.7",
-                "esprima": "^4.0.0"
-            },
-            "bin": {
-                "js-yaml": "bin/js-yaml.js"
-            }
-        },
-        "node_modules/minimatch": {
-            "version": "3.1.2",
-            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-            "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-            "dev": true,
-            "dependencies": {
-                "brace-expansion": "^1.1.7"
-            },
-            "engines": {
-                "node": "*"
-            }
-        },
-        "node_modules/minimist": {
-            "version": "1.2.8",
-            "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
-            "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
-            "dev": true,
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/mkdirp": {
-            "version": "0.5.6",
-            "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
-            "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
-            "dev": true,
-            "dependencies": {
-                "minimist": "^1.2.6"
-            },
-            "bin": {
-                "mkdirp": "bin/cmd.js"
-            }
-        },
-        "node_modules/once": {
-            "version": "1.4.0",
-            "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-            "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
-            "dev": true,
-            "dependencies": {
-                "wrappy": "1"
-            }
-        },
-        "node_modules/path-is-absolute": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-            "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
-            "dev": true,
-            "engines": {
-                "node": ">=0.10.0"
-            }
-        },
-        "node_modules/path-parse": {
-            "version": "1.0.7",
-            "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
-            "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
-            "dev": true
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/big-integer": {
+      "version": "1.6.52",
+      "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
+      "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==",
+      "dev": true,
+      "license": "Unlicense",
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/binary": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
+      "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "buffers": "~0.1.1",
+        "chainsaw": "~0.1.0"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+      "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/bl": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+      "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "buffer": "^5.5.0",
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.4.0"
+      }
+    },
+    "node_modules/bluebird": {
+      "version": "3.4.7",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
+      "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/buffer": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
         },
-        "node_modules/resolve": {
-            "version": "1.22.2",
-            "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
-            "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
-            "dev": true,
-            "dependencies": {
-                "is-core-module": "^2.11.0",
-                "path-parse": "^1.0.7",
-                "supports-preserve-symlinks-flag": "^1.0.0"
-            },
-            "bin": {
-                "resolve": "bin/resolve"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
         },
-        "node_modules/semver": {
-            "version": "5.7.1",
-            "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
-            "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
-            "dev": true,
-            "bin": {
-                "semver": "bin/semver"
-            }
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.1.13"
+      }
+    },
+    "node_modules/buffer-crc32": {
+      "version": "0.2.13",
+      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+      "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/buffer-equal-constant-time": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+      "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
+      "dev": true,
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/buffer-indexof-polyfill": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
+      "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/buffers": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
+      "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.2.0"
+      }
+    },
+    "node_modules/bundle-name": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
+      "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "run-applescript": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/call-bind-apply-helpers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+      "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/call-bound": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+      "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.2",
+        "get-intrinsic": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/chainsaw": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
+      "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==",
+      "dev": true,
+      "license": "MIT/X11",
+      "dependencies": {
+        "traverse": ">=0.3.0 <0.4"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "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,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/cheerio": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz",
+      "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cheerio-select": "^2.1.0",
+        "dom-serializer": "^2.0.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.1.0",
+        "encoding-sniffer": "^0.2.0",
+        "htmlparser2": "^9.1.0",
+        "parse5": "^7.1.2",
+        "parse5-htmlparser2-tree-adapter": "^7.0.0",
+        "parse5-parser-stream": "^7.1.2",
+        "undici": "^6.19.5",
+        "whatwg-mimetype": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=18.17"
+      },
+      "funding": {
+        "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+      }
+    },
+    "node_modules/cheerio-select": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+      "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "boolbase": "^1.0.0",
+        "css-select": "^5.1.0",
+        "css-what": "^6.1.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
+      "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
+      "license": "MIT",
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/chownr": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+      "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+      "dev": true,
+      "license": "ISC",
+      "optional": true
+    },
+    "node_modules/clang-format": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/clang-format/-/clang-format-1.8.0.tgz",
+      "integrity": "sha512-pK8gzfu55/lHzIpQ1givIbWfn3eXnU7SfxqIwVgnn5jEM6j4ZJYjpFqFs4iSBPNedzRMmfjYjuQhu657WAXHXw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "async": "^3.2.3",
+        "glob": "^7.0.0",
+        "resolve": "^1.1.6"
+      },
+      "bin": {
+        "check-clang-format": "bin/check-clang-format.js",
+        "clang-format": "index.js",
+        "git-clang-format": "bin/git-clang-format"
+      }
+    },
+    "node_modules/cockatiel": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz",
+      "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "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,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/commander": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+      "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/css-select": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
+      "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "boolbase": "^1.0.0",
+        "css-what": "^6.1.0",
+        "domhandler": "^5.0.2",
+        "domutils": "^3.0.1",
+        "nth-check": "^2.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/css-what": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+      "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">= 6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+      "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/decompress-response": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+      "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "mimic-response": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/default-browser": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz",
+      "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "bundle-name": "^4.1.0",
+        "default-browser-id": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/default-browser-id": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz",
+      "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/define-lazy-prop": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+      "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/detect-libc": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
+      "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/dom-serializer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+      "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.2",
+        "entities": "^4.2.0"
+      },
+      "funding": {
+        "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+      }
+    },
+    "node_modules/domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ],
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/domhandler": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+      "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "domelementtype": "^2.3.0"
+      },
+      "engines": {
+        "node": ">= 4"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domhandler?sponsor=1"
+      }
+    },
+    "node_modules/domutils": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+      "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "dom-serializer": "^2.0.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domutils?sponsor=1"
+      }
+    },
+    "node_modules/dunder-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+      "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.2.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/duplexer2": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+      "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "readable-stream": "^2.0.2"
+      }
+    },
+    "node_modules/duplexer2/node_modules/readable-stream": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "node_modules/duplexer2/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/duplexer2/node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/ecdsa-sig-formatter": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+      "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/encoding-sniffer": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz",
+      "integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "iconv-lite": "^0.6.3",
+        "whatwg-encoding": "^3.1.1"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
+      }
+    },
+    "node_modules/end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "once": "^1.4.0"
+      }
+    },
+    "node_modules/entities": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/es-define-property": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "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,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-object-atoms": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+      "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-set-tostringtag": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+      "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.6",
+        "has-tostringtag": "^1.0.2",
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true,
+      "bin": {
+        "esparse": "bin/esparse.js",
+        "esvalidate": "bin/esvalidate.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/expand-template": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+      "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+      "dev": true,
+      "license": "(MIT OR WTFPL)",
+      "optional": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/fd-slicer": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+      "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "pend": "~1.2.0"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/form-data": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
+      "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "es-set-tostringtag": "^2.1.0",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fs-constants": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+      "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/fstream": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
+      "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
+      "deprecated": "This package is no longer supported.",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "graceful-fs": "^4.1.2",
+        "inherits": "~2.0.0",
+        "mkdirp": ">=0.5 0",
+        "rimraf": "2"
+      },
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/fstream/node_modules/rimraf": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+      "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+      "deprecated": "Rimraf versions prior to v4 are no longer supported",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+      "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.2",
+        "es-define-property": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.1.1",
+        "function-bind": "^1.1.2",
+        "get-proto": "^1.0.1",
+        "gopd": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "hasown": "^2.0.2",
+        "math-intrinsics": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+      "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "dunder-proto": "^1.0.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/github-from-package": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+      "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "deprecated": "Glob versions prior to v9 are no longer supported",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "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,
+      "license": "ISC"
+    },
+    "node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-tostringtag": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-symbols": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "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,
+      "license": "MIT",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/hosted-git-info": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+      "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/htmlparser2": {
+      "version": "9.1.0",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
+      "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==",
+      "dev": true,
+      "funding": [
+        "https://github.com/fb55/htmlparser2?sponsor=1",
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.1.0",
+        "entities": "^4.5.0"
+      }
+    },
+    "node_modules/http-proxy-agent": {
+      "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,
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "^7.1.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/https-proxy-agent": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+      "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "^7.1.2",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "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"
         },
-        "node_modules/sprintf-js": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-            "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
-            "dev": true
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
         },
-        "node_modules/supports-color": {
-            "version": "5.5.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-            "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-            "dev": true,
-            "dependencies": {
-                "has-flag": "^3.0.0"
-            },
-            "engines": {
-                "node": ">=4"
-            }
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "BSD-3-Clause",
+      "optional": true
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+      "dev": true,
+      "license": "ISC",
+      "optional": true
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "license": "MIT",
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-core-module": {
+      "version": "2.16.1",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+      "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-docker": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+      "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "is-docker": "cli.js"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "license": "MIT",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-inside-container": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+      "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-docker": "^3.0.0"
+      },
+      "bin": {
+        "is-inside-container": "cli.js"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-wsl": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz",
+      "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-inside-container": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/js-yaml": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/js-yaml/node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "node_modules/jsonc-parser": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
+      "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/jsonwebtoken": {
+      "version": "9.0.2",
+      "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
+      "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "jws": "^3.2.2",
+        "lodash.includes": "^4.3.0",
+        "lodash.isboolean": "^3.0.3",
+        "lodash.isinteger": "^4.0.4",
+        "lodash.isnumber": "^3.0.3",
+        "lodash.isplainobject": "^4.0.6",
+        "lodash.isstring": "^4.0.1",
+        "lodash.once": "^4.0.0",
+        "ms": "^2.1.1",
+        "semver": "^7.5.4"
+      },
+      "engines": {
+        "node": ">=12",
+        "npm": ">=6"
+      }
+    },
+    "node_modules/jwa": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
+      "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "buffer-equal-constant-time": "^1.0.1",
+        "ecdsa-sig-formatter": "1.0.11",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/jws": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+      "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "jwa": "^1.4.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/keytar": {
+      "version": "7.9.0",
+      "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
+      "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "node-addon-api": "^4.3.0",
+        "prebuild-install": "^7.0.1"
+      }
+    },
+    "node_modules/leven": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+      "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/linkify-it": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+      "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "uc.micro": "^1.0.1"
+      }
+    },
+    "node_modules/listenercount": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz",
+      "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/lodash.includes": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+      "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.isboolean": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+      "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.isinteger": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+      "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.isnumber": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+      "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.isplainobject": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+      "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.isstring": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+      "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.once": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+      "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "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,
+      "license": "ISC",
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/markdown-it": {
+      "version": "12.3.2",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+      "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1",
+        "entities": "~2.1.0",
+        "linkify-it": "^3.0.1",
+        "mdurl": "^1.0.1",
+        "uc.micro": "^1.0.5"
+      },
+      "bin": {
+        "markdown-it": "bin/markdown-it.js"
+      }
+    },
+    "node_modules/markdown-it/node_modules/entities": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+      "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/math-intrinsics": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+      "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/mdurl": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+      "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "mime": "cli.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mimic-response": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+      "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/mkdirp": {
+      "version": "0.5.6",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+      "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "minimist": "^1.2.6"
+      },
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      }
+    },
+    "node_modules/mkdirp-classic": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+      "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/mute-stream": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/napi-build-utils": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
+      "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/node-abi": {
+      "version": "3.75.0",
+      "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.75.0.tgz",
+      "integrity": "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "semver": "^7.3.5"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/node-addon-api": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
+      "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nth-check": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "boolbase": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/nth-check?sponsor=1"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.13.4",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+      "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/open": {
+      "version": "10.1.2",
+      "resolved": "https://registry.npmjs.org/open/-/open-10.1.2.tgz",
+      "integrity": "sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "default-browser": "^5.2.1",
+        "define-lazy-prop": "^3.0.0",
+        "is-inside-container": "^1.0.0",
+        "is-wsl": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/parse-semver": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
+      "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "semver": "^5.1.0"
+      }
+    },
+    "node_modules/parse-semver/node_modules/semver": {
+      "version": "5.7.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+      "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver"
+      }
+    },
+    "node_modules/parse5": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
+      "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "entities": "^6.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parse5-htmlparser2-tree-adapter": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz",
+      "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "domhandler": "^5.0.3",
+        "parse5": "^7.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parse5-parser-stream": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz",
+      "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "parse5": "^7.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parse5/node_modules/entities": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz",
+      "integrity": "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/pend": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+      "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/prebuild-install": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
+      "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "detect-libc": "^2.0.0",
+        "expand-template": "^2.0.3",
+        "github-from-package": "0.0.0",
+        "minimist": "^1.2.3",
+        "mkdirp-classic": "^0.5.3",
+        "napi-build-utils": "^2.0.0",
+        "node-abi": "^3.3.0",
+        "pump": "^3.0.0",
+        "rc": "^1.2.7",
+        "simple-get": "^4.0.0",
+        "tar-fs": "^2.0.0",
+        "tunnel-agent": "^0.6.0"
+      },
+      "bin": {
+        "prebuild-install": "bin.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/pump": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
+      "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "node_modules/qs": {
+      "version": "6.14.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+      "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "side-channel": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/rc": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+      "dev": true,
+      "license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
+      "optional": true,
+      "dependencies": {
+        "deep-extend": "^0.6.0",
+        "ini": "~1.3.0",
+        "minimist": "^1.2.0",
+        "strip-json-comments": "~2.0.1"
+      },
+      "bin": {
+        "rc": "cli.js"
+      }
+    },
+    "node_modules/read": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
+      "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "mute-stream": "~0.0.4"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "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,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "license": "MIT",
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/resolve": {
+      "version": "1.22.10",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+      "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-core-module": "^2.16.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "deprecated": "Rimraf versions prior to v4 are no longer supported",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/run-applescript": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz",
+      "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
         },
-        "node_modules/supports-preserve-symlinks-flag": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
-            "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
-            "dev": true,
-            "engines": {
-                "node": ">= 0.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
         },
-        "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
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/sax": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
+      "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/semver": {
+      "version": "7.7.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+      "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/setimmediate": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+      "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/side-channel": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+      "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.3",
+        "side-channel-list": "^1.0.0",
+        "side-channel-map": "^1.0.1",
+        "side-channel-weakmap": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-list": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+      "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-map": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+      "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-weakmap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+      "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3",
+        "side-channel-map": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/simple-concat": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+      "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
         },
-        "node_modules/tslint": {
-            "version": "5.20.1",
-            "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz",
-            "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==",
-            "dev": true,
-            "dependencies": {
-                "@babel/code-frame": "^7.0.0",
-                "builtin-modules": "^1.1.1",
-                "chalk": "^2.3.0",
-                "commander": "^2.12.1",
-                "diff": "^4.0.1",
-                "glob": "^7.1.1",
-                "js-yaml": "^3.13.1",
-                "minimatch": "^3.0.4",
-                "mkdirp": "^0.5.1",
-                "resolve": "^1.3.2",
-                "semver": "^5.3.0",
-                "tslib": "^1.8.0",
-                "tsutils": "^2.29.0"
-            },
-            "bin": {
-                "tslint": "bin/tslint"
-            },
-            "engines": {
-                "node": ">=4.8.0"
-            },
-            "peerDependencies": {
-                "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev"
-            }
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
         },
-        "node_modules/tsutils": {
-            "version": "2.29.0",
-            "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
-            "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
-            "dev": true,
-            "dependencies": {
-                "tslib": "^1.8.1"
-            },
-            "peerDependencies": {
-                "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev"
-            }
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/simple-get": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+      "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
         },
-        "node_modules/typescript": {
-            "version": "3.9.10",
-            "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz",
-            "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==",
-            "dev": true,
-            "bin": {
-                "tsc": "bin/tsc",
-                "tsserver": "bin/tsserver"
-            },
-            "engines": {
-                "node": ">=4.2.0"
-            }
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
         },
-        "node_modules/wrappy": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-            "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
-            "dev": true
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
         }
+      ],
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "decompress-response": "^6.0.0",
+        "once": "^1.3.1",
+        "simple-concat": "^1.0.0"
+      }
+    },
+    "node_modules/sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+      "dev": true
+    },
+    "node_modules/string_decoder": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "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,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/tar-fs": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz",
+      "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "chownr": "^1.1.1",
+        "mkdirp-classic": "^0.5.2",
+        "pump": "^3.0.0",
+        "tar-stream": "^2.1.4"
+      }
+    },
+    "node_modules/tar-stream": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+      "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "bl": "^4.0.3",
+        "end-of-stream": "^1.4.1",
+        "fs-constants": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^3.1.1"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/tmp": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
+      "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.14"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/traverse": {
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
+      "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==",
+      "dev": true,
+      "license": "MIT/X11",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+      "dev": true,
+      "license": "0BSD"
+    },
+    "node_modules/tunnel": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+      "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
+      }
+    },
+    "node_modules/tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "safe-buffer": "^5.0.1"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/typed-rest-client": {
+      "version": "1.8.11",
+      "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz",
+      "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "qs": "^6.9.1",
+        "tunnel": "0.0.6",
+        "underscore": "^1.12.1"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+      "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=4.2.0"
+      }
+    },
+    "node_modules/uc.micro": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+      "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/underscore": {
+      "version": "1.13.7",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
+      "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/undici": {
+      "version": "6.21.3",
+      "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz",
+      "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18.17"
+      }
+    },
+    "node_modules/unzipper": {
+      "version": "0.10.14",
+      "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz",
+      "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "big-integer": "^1.6.17",
+        "binary": "~0.3.0",
+        "bluebird": "~3.4.1",
+        "buffer-indexof-polyfill": "~1.0.0",
+        "duplexer2": "~0.1.4",
+        "fstream": "^1.0.12",
+        "graceful-fs": "^4.2.2",
+        "listenercount": "~1.0.1",
+        "readable-stream": "~2.3.6",
+        "setimmediate": "~1.0.4"
+      }
+    },
+    "node_modules/unzipper/node_modules/readable-stream": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "node_modules/unzipper/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/unzipper/node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/url-join": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
+      "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/uuid": {
+      "version": "8.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/vscode-jsonrpc": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
+      "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/vscode-languageclient": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz",
+      "integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==",
+      "license": "MIT",
+      "dependencies": {
+        "minimatch": "^5.1.0",
+        "semver": "^7.3.7",
+        "vscode-languageserver-protocol": "3.17.5"
+      },
+      "engines": {
+        "vscode": "^1.82.0"
+      }
+    },
+    "node_modules/vscode-languageclient/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/vscode-languageclient/node_modules/minimatch": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+      "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/vscode-languageserver-protocol": {
+      "version": "3.17.5",
+      "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
+      "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
+      "license": "MIT",
+      "dependencies": {
+        "vscode-jsonrpc": "8.2.0",
+        "vscode-languageserver-types": "3.17.5"
+      }
+    },
+    "node_modules/vscode-languageserver-types": {
+      "version": "3.17.5",
+      "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
+      "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==",
+      "license": "MIT"
+    },
+    "node_modules/vscode-test": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.6.1.tgz",
+      "integrity": "sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==",
+      "deprecated": "This package has been renamed to @vscode/test-electron, please update to the new name",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "http-proxy-agent": "^4.0.1",
+        "https-proxy-agent": "^5.0.0",
+        "rimraf": "^3.0.2",
+        "unzipper": "^0.10.11"
+      },
+      "engines": {
+        "node": ">=8.9.3"
+      }
+    },
+    "node_modules/vscode-test/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==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6.0.0"
+      }
+    },
+    "node_modules/vscode-test/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==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@tootallnate/once": "1",
+        "agent-base": "6",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/vscode-test/node_modules/https-proxy-agent": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "6",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/whatwg-encoding": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+      "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "iconv-lite": "0.6.3"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/whatwg-mimetype": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+      "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/xml2js": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
+      "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "sax": ">=0.6.0",
+        "xmlbuilder": "~11.0.0"
+      },
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/xmlbuilder": {
+      "version": "11.0.1",
+      "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+      "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/yauzl": {
+      "version": "2.10.0",
+      "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+      "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "buffer-crc32": "~0.2.3",
+        "fd-slicer": "~1.1.0"
+      }
+    },
+    "node_modules/yazl": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
+      "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "buffer-crc32": "~0.2.3"
+      }
     }
+  }
 }
diff --git a/llvm/utils/vscode/llvm/package.json b/llvm/utils/vscode/llvm/package.json
index fbee74954cbb3..b6b4bdc436436 100644
--- a/llvm/utils/vscode/llvm/package.json
+++ b/llvm/utils/vscode/llvm/package.json
@@ -1,122 +1,197 @@
 {
-    "name": "llvm",
-    "displayName": "llvm",
-    "description": "VS Code Externsion for LLVM development",
-    "publisher": "llvm-vs-code-extensions",
-    "version": "0.0.1",
-    "repository": "somewhere",
-    "engines": {
-        "vscode": "^1.42.0"
-    },
-    "categories": [
-        "Programming Languages"
+  "name": "llvm",
+  "displayName": "llvm",
+  "description": "VS Code Externsion for LLVM development",
+  "publisher": "llvm-vs-code-extensions",
+  "version": "0.0.2",
+  "repository": "somewhere",
+  "engines": {
+    "vscode": "^1.92.0"
+  },
+  "categories": [
+    "Programming Languages"
+  ],
+  "keywords": [
+    "LLVM"
+  ],
+  "activationEvents": [
+    "onCommand:workbench.action.tasks.runTask"
+  ],
+  "contributes": {
+    "languages": [
+      {
+        "id": "tablegen",
+        "aliases": [
+          "TableGen",
+          "tablegen"
+        ],
+        "extensions": [
+          ".td"
+        ],
+        "configuration": "./language-configuration-tablegen.json"
+      },
+      {
+        "id": "llvm",
+        "aliases": [
+          "LLVM IR",
+          "LLVM",
+          "llvm"
+        ],
+        "extensions": [
+          ".ll"
+        ],
+        "configuration": "./language-configuration.json"
+      }
     ],
-    "activationEvents": [
-        "onCommand:workbench.action.tasks.runTask"
+    "grammars": [
+      {
+        "language": "tablegen",
+        "scopeName": "source.tablegen",
+        "path": "./syntaxes/TableGen.tmLanguage"
+      },
+      {
+        "language": "llvm",
+        "scopeName": "source.llvm",
+        "path": "./syntaxes/ll.tmLanguage.json"
+      }
     ],
-    "main": "./out/extension",
-    "contributes": {
-        "languages": [
-            {
-                "id": "tablegen",
-                "aliases": [
-                    "TableGen",
-                    "tablegen"
-                ],
-                "extensions": [
-                    ".td"
-                ],
-                "configuration": "./language-configuration-tablegen.json"
-            },
-            {
-                "id": "llvm",
-                "aliases": [
-                    "LLVM IR",
-                    "LLVM",
-                    "llvm"
-                ],
-                "extensions": [
-                    ".ll"
-                ],
-                "configuration": "./language-configuration.json"
-            }
+    "taskDefinitions": [
+      {
+        "type": "llvm-lit",
+        "required": [
+          "task"
         ],
-        "grammars": [
-            {
-                "language": "tablegen",
-                "scopeName": "source.tablegen",
-                "path": "./syntaxes/TableGen.tmLanguage"
-            },
-            {
-                "language": "llvm",
-                "scopeName": "source.llvm",
-                "path": "./syntaxes/ll.tmLanguage.json"
-            }
+        "properties": {
+          "task": {
+            "type": "string",
+            "description": "The Rake task to customize"
+          }
+        }
+      }
+    ],
+    "problemMatchers": [
+      {
+        "name": "llvm-lit",
+        "fileLocation": [
+          "absolute"
         ],
-        "taskDefinitions": [
-            {
-                "type": "llvm-lit",
-                "required": [
-                    "task"
-                ],
-                "properties": {
-                    "task": {
-                        "type": "string",
-                        "description": "The Rake task to customize"
-                    }
-                }
-            }
+        "label": "LLVM LIT",
+        "source": "llvm lit",
+        "severity": "error",
+        "pattern": [
+          {
+            "regexp": "^(.+):(\\d+)\\((\\d+)\\):\\s+(.+)$",
+            "kind": "location",
+            "file": 1,
+            "line": 2,
+            "code": 3,
+            "message": 4
+          }
+        ]
+      },
+      {
+        "name": "llvm-filecheck",
+        "fileLocation": [
+          "absolute"
         ],
-        "problemMatchers": [
-            {
-                "name": "llvm-lit",
-                "fileLocation": [
-                    "absolute"
-                ],
-                "label": "LLVM LIT",
-                "source": "llvm lit",
-                "severity": "error",
-                "pattern": [
-                    {
-                        "regexp": "^(.+):(\\d+)\\((\\d+)\\):\\s+(.+)$",
-                        "kind": "location",
-                        "file": 1,
-                        "line": 2,
-                        "code": 3,
-                        "message": 4
-                    }
-                ]
-            },
-            {
-                "name": "llvm-filecheck",
-                "fileLocation": [
-                    "absolute"
-                ],
-                "label": "LLVM FileCheck",
-                "source": "llvm filecheck",
-                "pattern": [
-                    {
-                        "regexp": "^(.+):(\\d+):\\d+:\\s+(error|warning|note|remark):\\s+(.+)$",
-                        "kind": "location",
-                        "file": 1,
-                        "line": 2,
-                        "severity": 3,
-                        "message": 4
-                    }
-                ]
-            }
+        "label": "LLVM FileCheck",
+        "source": "llvm filecheck",
+        "pattern": [
+          {
+            "regexp": "^(.+):(\\d+):\\d+:\\s+(error|warning|note|remark):\\s+(.+)$",
+            "kind": "location",
+            "file": 1,
+            "line": 2,
+            "severity": 3,
+            "message": 4
+          }
         ]
+      }
+    ],
+    "configuration": {
+      "type": "object",
+      "title": "LLVM",
+      "properties": {
+        "llvm.serverPath": {
+          "scope": "resource",
+          "type": "string",
+          "description": "The file path of the llvm-lsp-server executable."
+        },
+        "llvm.additionalServerArgs": {
+          "scope": "resource",
+          "type": "array",
+          "description": "A list of additional arguments for llvm-lsp-server executable. E.g. --log-file=/tmp/my-log.",
+          "items": {
+            "type": "string"
+          },
+          "default": []
+        },
+        "llvm.trace.server": {
+          "scope": "window",
+          "type": "string",
+          "enum": [
+            "off",
+            "messages",
+            "verbose"
+          ],
+          "default": "messages",
+          "description": "Traces the communication between VS Code and the language server."
+        },
+        "llvm.onSettingsChanged": {
+          "type": "string",
+          "default": "prompt",
+          "description": "Action taken when a setting change requires a server restart to take effect.",
+          "enum": [
+            "prompt",
+            "restart",
+            "ignore"
+          ],
+          "enumDescriptions": [
+            "Prompt the user for restarting the server",
+            "Automatically restart the server",
+            "Do nothing"
+          ]
+        }
+      }
     },
-    "devDependencies": {
-        "@types/node": "^8.10.59",
-        "@types/vscode": "^1.39.0",
-        "js-yaml": "^3.13.1",
-        "tslint": "^5.16.0",
-        "typescript": "^3.8.3"
-    },
-    "extensionDependencies": ["ms-vscode.cmake-tools"],
-    "scripts": {
-        "vscode:prepublish": "npx js-yaml syntaxes/ll.tmLanguage.yaml > syntaxes/ll.tmLanguage.json && tsc -b",
-        "watch": "tsc -b -w"
+    "commands": [
+      {
+        "command": "llvm.restart",
+        "title": "llvm: Restart language server"
+      },
+      {
+        "command": "llvm.cfg",
+        "title": "llvm: Open CFG preview"
+      }
+    ],
+    "menus": {
+      "editor/context": []
     }
-}
\ No newline at end of file
+  },
+  "main": "./out/extension",
+  "dependencies": {
+    "base64-js": "^1.5.1",
+    "chokidar": "3.5.2",
+    "vscode-languageclient": "^9.0.1"
+  },
+  "devDependencies": {
+    "@types/mocha": "^7.0.2",
+    "@types/node": "^14.17.0",
+    "@types/vscode": "~1.92.0",
+    "@vscode/vsce": "^2.19.0",
+    "js-yaml": "^3.13.1",
+    "clang-format": "^1.8.0",
+    "typescript": "^4.9.5",
+    "vscode-test": "^1.3.0"
+  },
+  "extensionDependencies": [
+    "ms-vscode.cmake-tools"
+  ],
+  "scripts": {
+    "vscode:prepublish": "npx js-yaml syntaxes/ll.tmLanguage.yaml > syntaxes/ll.tmLanguage.json && tsc -b",
+    "compile": "tsc -b",
+    "package": "vsce package",
+    "watch": "tsc -b -w",
+    "lint": "eslint"
+  }
+}
diff --git a/llvm/utils/vscode/llvm/src/command.ts b/llvm/utils/vscode/llvm/src/command.ts
new file mode 100644
index 0000000000000..ee0b936bb5243
--- /dev/null
+++ b/llvm/utils/vscode/llvm/src/command.ts
@@ -0,0 +1,29 @@
+/**
+ * This file was copied from /mlir/utils/vscode/src/command.ts and adapted for use in LLVM
+  */
+
+import * as vscode from 'vscode';
+import { LLVMContext } from './llvmContext';
+
+/**
+ * This class represents a base vscode command. It handles all of the necessary
+ * command registration and disposal boilerplate.
+ */
+export abstract class Command extends vscode.Disposable {
+  private disposable: vscode.Disposable;
+  protected context: LLVMContext;
+
+  constructor(command: string, context: LLVMContext) {
+    super(() => this.dispose());
+    this.disposable =
+      vscode.commands.registerCommand(command, this.execute, this);
+    this.context = context;
+  }
+
+  dispose() { this.disposable && this.disposable.dispose(); }
+
+  /**
+   * The function executed when this command is invoked.
+   */
+  abstract execute(...args: any[]): any;
+}
diff --git a/llvm/utils/vscode/llvm/src/config.ts b/llvm/utils/vscode/llvm/src/config.ts
new file mode 100644
index 0000000000000..d248bcf79b79b
--- /dev/null
+++ b/llvm/utils/vscode/llvm/src/config.ts
@@ -0,0 +1,23 @@
+/**
+ * This file was copied from /mlir/utils/vscode/src/config.ts and adapted for use in LLVM
+ */
+
+import * as vscode from 'vscode';
+
+/**
+ *  Gets the config value `llvm.<key>`, with an optional workspace folder.
+ */
+export function get<T>(key: string,
+  workspaceFolder: vscode.WorkspaceFolder = null,
+  defaultValue: T = undefined): T {
+  return vscode.workspace.getConfiguration('llvm', workspaceFolder)
+    .get<T>(key, defaultValue);
+}
+
+/**
+ *  Sets the config value `llvm.<key>`.
+ */
+export function update<T>(key: string, value: T,
+  target?: vscode.ConfigurationTarget) {
+  return vscode.workspace.getConfiguration('llvm').update(key, value, target);
+}
diff --git a/llvm/utils/vscode/llvm/src/configWatcher.ts b/llvm/utils/vscode/llvm/src/configWatcher.ts
new file mode 100644
index 0000000000000..acdc5cccea139
--- /dev/null
+++ b/llvm/utils/vscode/llvm/src/configWatcher.ts
@@ -0,0 +1,88 @@
+/**
+ * This file was copied from /mlir/utils/vscode/src/configWatcher.ts and adapted for use in LLVM
+ */
+
+import * as chokidar from 'chokidar';
+import * as vscode from 'vscode';
+
+import * as config from './config';
+import { LLVMContext } from './llvmContext';
+
+/**
+ *  Prompt the user to see if we should restart the server.
+ */
+async function promptRestart(settingName: string, promptMessage: string) {
+  switch (config.get<string>(settingName)) {
+    case 'restart':
+      vscode.commands.executeCommand('llvm.restart');
+      break;
+    case 'ignore':
+      break;
+    case 'prompt':
+    default:
+      switch (await vscode.window.showInformationMessage(
+        promptMessage, 'Yes', 'Yes, always', 'No, never')) {
+        case 'Yes':
+          vscode.commands.executeCommand('llvm.restart');
+          break;
+        case 'Yes, always':
+          vscode.commands.executeCommand('llvm.restart');
+          config.update<string>(settingName, 'restart',
+            vscode.ConfigurationTarget.Global);
+          break;
+        case 'No, never':
+          config.update<string>(settingName, 'ignore',
+            vscode.ConfigurationTarget.Global);
+          break;
+        default:
+          break;
+      }
+      break;
+  }
+}
+
+/**
+ *  Activate watchers that track configuration changes for the given workspace
+ *  folder, or null if the workspace is top-level.
+ */
+export async function activate(
+  llvmContext: LLVMContext, workspaceFolder: vscode.WorkspaceFolder,
+  serverSettings: string[], serverPaths: string[]) {
+  // When a configuration change happens, check to see if we should restart the
+  // server.
+  llvmContext.subscriptions.push(vscode.workspace.onDidChangeConfiguration(event => {
+    for (const serverSetting of serverSettings) {
+      const expandedSetting = `llvm.${serverSetting}`;
+      if (event.affectsConfiguration(expandedSetting, workspaceFolder)) {
+        promptRestart(
+          'onSettingsChanged',
+          `setting '${expandedSetting}' has changed. Do you want to reload the server?`);
+      }
+    }
+  }));
+
+  // Setup watchers for the provided server paths.
+  const fileWatcherConfig = {
+    disableGlobbing: true,
+    followSymlinks: true,
+    ignoreInitial: true,
+    awaitWriteFinish: true,
+  };
+  for (const serverPath of serverPaths) {
+    if (serverPath === '') {
+      return;
+    }
+
+    // If the server path actually exists, track it in case it changes.
+    const fileWatcher = chokidar.watch(serverPath, fileWatcherConfig);
+    fileWatcher.on('all', (event, _filename, _details) => {
+      if (event != 'unlink') {
+        promptRestart(
+          'onSettingsChanged',
+          'LLVM language server file has changed. Do you want to reload the server?');
+      }
+    });
+    llvmContext.subscriptions.push(
+      new vscode.Disposable(() => { fileWatcher.close(); }));
+  }
+}
diff --git a/llvm/utils/vscode/llvm/src/extension.ts b/llvm/utils/vscode/llvm/src/extension.ts
index ffb8d9dc04291..33955657d1972 100644
--- a/llvm/utils/vscode/llvm/src/extension.ts
+++ b/llvm/utils/vscode/llvm/src/extension.ts
@@ -1,15 +1,36 @@
+/**
+ * This file was copied from /mlir/utils/vscode/src/extension.ts and adapted for use in LLVM
+ */
+
 import * as vscode from 'vscode';
+
 import { LITTaskProvider } from './litTaskProvider';
+import { LLVMContext } from './llvmContext';
+import { LLVMGetCfgCommand } from './llvmCfg';
 
-let litTaskProvider: vscode.Disposable | undefined;
-let customTaskProvider: vscode.Disposable | undefined;
+/**
+ *  This method is called when the extension is activated. The extension is
+ *  activated the very first time a command is executed.
+ */
+export function activate(context: vscode.ExtensionContext) {
+  context.subscriptions.push(vscode.tasks.registerTaskProvider(LITTaskProvider.LITType, new LITTaskProvider()));
 
-export function activate(_context: vscode.ExtensionContext): void {
-	litTaskProvider = vscode.tasks.registerTaskProvider(LITTaskProvider.LITType, new LITTaskProvider());
-}
+  const outputChannel = vscode.window.createOutputChannel('llvm-lsp-server', 'Log');
+  context.subscriptions.push(outputChannel);
+
+  const llvmContext = new LLVMContext(context, outputChannel);
+  context.subscriptions.push(llvmContext);
 
-export function deactivate(): void {
-	if (litTaskProvider) {
-		litTaskProvider.dispose();
-	}
-}
\ No newline at end of file
+  // Initialize the commands of the extension.
+  context.subscriptions.push(
+    vscode.commands.registerCommand('llvm.restart', async () => {
+      // Dispose and reactivate the context.
+      llvmContext.dispose();
+      await llvmContext.activate();
+    }));
+
+  new LLVMGetCfgCommand(llvmContext);
+
+  llvmContext.activate();
+  outputChannel.appendLine("LLVM: extension activated!");
+}
diff --git a/llvm/utils/vscode/llvm/src/llvmCfg.ts b/llvm/utils/vscode/llvm/src/llvmCfg.ts
new file mode 100644
index 0000000000000..e3d6b99d50b33
--- /dev/null
+++ b/llvm/utils/vscode/llvm/src/llvmCfg.ts
@@ -0,0 +1,246 @@
+import * as vscode from 'vscode';
+import * as path from 'path';
+import { Command } from './command';
+import { LLVMContext } from './llvmContext';
+import {
+  LlvmGetCfg,
+  LlvmBbLocation,
+} from './lspCustomMessages';
+
+export class LLVMGetCfgCommand extends Command {
+
+  constructor(context: LLVMContext) {
+    super('llvm.cfg', context);
+  }
+
+  async execute(...args: any[]) {
+    // Only works when there is an active open editor with a .ll file
+    const activeEditor = vscode.window.activeTextEditor;
+    if (!activeEditor) {
+      vscode.window.showInformationMessage('No active text editor.');
+      return;
+    }
+    const currentFileLanguageId = activeEditor.document.languageId;
+    if (currentFileLanguageId !== 'llvm') {
+      vscode.window.showInformationMessage('Only supported for language `llvm\'.');
+      return;
+    }
+    const currentFileUri = activeEditor.document.uri;
+    const client = await this.context.getOrActivateLanguageClient(currentFileUri, currentFileLanguageId);
+    if (!client || !client.initializeResult) {
+      vscode.window.showErrorMessage('Language server is not yet ready.');
+      return;
+    }
+
+    // Ask lsp server
+    // TODO: should we send uri.fspath instead? what's the system-agnostic way to pass uri?
+    //   In general, I think we should use vscode.Uri everywhere instead of strings (the context maps etc.)
+    let result: LlvmGetCfg.Response = undefined;
+    try {
+      const params: LlvmGetCfg.Params = {
+        uri: currentFileUri.toString(),
+        position: activeEditor.selection.active,
+      };
+      const response = await client.sendRequest(LlvmGetCfg.Type, params);
+      // TODO: should check if the IDs match??
+      if (response['error'] !== undefined) {
+        this.context.outputChannel.appendLine(`Error during custom request LlvmGetCfg: server returned error`);
+        return;
+      }
+      result = response;
+    } catch (error) {
+      this.context.outputChannel.appendLine(`Error during custom request LlvmGetCfg: ${error}`);
+      return;
+    }
+
+    // Read the cfg from the server's response
+    const cfgFileUri = vscode.Uri.parse(result['uri']);
+    const cfgFilePath = cfgFileUri.fsPath;
+    const cfgDir = path.dirname(cfgFilePath);
+    let targetFileContent: string;
+    try {
+      const targetUri = vscode.Uri.file(cfgFilePath);
+      const fileBytes = await vscode.workspace.fs.readFile(targetUri);
+      targetFileContent = Buffer.from(fileBytes).toString('utf8');
+    } catch (error) {
+      this.context.outputChannel.appendLine(`Could not read file: ${cfgFilePath}. Error: ${error}`);
+      return;
+    }
+
+    const workspaceFolder = vscode.workspace.getWorkspaceFolder(currentFileUri);
+    let workspaceFolderStr =
+      workspaceFolder ? workspaceFolder.uri.toString() : "";
+    const folderContext = this.context.workspaceFolders.get(workspaceFolderStr);
+
+    let newPanelCreated = false;
+
+    // Get saved webview panel that has the desired CFG or create a new one
+    const panel = (folderContext.cfgWebViews.has(currentFileUri.fsPath) && folderContext.cfgWebViews.get(currentFileUri.fsPath).has(result['function'])) ?
+      folderContext.cfgWebViews.get(currentFileUri.fsPath).get(result['function']) :
+
+      // Create the webview panel and show the svg in it
+      await (async () => {
+        const panel = vscode.window.createWebviewPanel(
+          'embeddedView',
+          `CFG for ${result['function']} from ${path.basename(currentFileUri.fsPath)}`,
+          vscode.ViewColumn.Beside,
+          {
+            enableScripts: true,
+            localResourceRoots: [vscode.Uri.file(cfgDir)]
+          }
+        );
+        panel.webview.html = await getWebviewContentWithInteraction(
+          this.context,
+          {
+            svgContent: targetFileContent,
+            fileName: cfgFilePath
+          });
+        newPanelCreated = true;
+        return panel;
+      })();
+    if (!folderContext.cfgWebViews.has(currentFileUri.fsPath)) {
+      folderContext.cfgWebViews.set(currentFileUri.fsPath, new Map())
+    }
+    folderContext.cfgWebViews.get(currentFileUri.fsPath).set(result['function'], panel);
+
+    // When panel is closed delete it from the map
+    panel.onDidDispose(() => folderContext.cfgWebViews.delete(currentFileUri.fsPath))
+
+    // Focus on the panel
+    panel.reveal(panel.viewColumn);
+
+    // Send message to center on node to webview
+    const nodeToCenter = result['node_id'];
+    this.context.outputChannel.appendLine(`Node To Center: ID = ${nodeToCenter}`);
+    panel.webview.postMessage({ command: "centerOn", node: nodeToCenter });
+
+    // Handle messages from the webview
+    if (newPanelCreated) {
+      this.context.subscriptions.push(
+        panel.webview.onDidReceiveMessage(
+          async message => {
+            switch (message.command) {
+              case 'cfgViewerDebug': {
+                this.context.outputChannel.appendLine(message.msg);
+                return;
+              }
+              case 'svgElementClicked':
+                const elementId = message.elementId;
+                this.context.outputChannel.appendLine(`SVG Element Clicked: ID = ${elementId}`);
+
+                let result: LlvmBbLocation.Response = undefined;
+                try {
+                  const params: LlvmBbLocation.Params = {
+                    uri: cfgFileUri.toString(),
+                    node_id: elementId,
+                  };
+                  const response = await client.sendRequest(LlvmBbLocation.Type, params);
+                  // TODO: should check if the IDs match??
+                  if (response['error'] !== undefined) {
+                    this.context.outputChannel.appendLine(`Error during custom request LlvmBbLocation: server returned error`);
+                    return;
+                  }
+                  result = response;
+                } catch (error) {
+                  this.context.outputChannel.appendLine(`Error during custom request LlvmGetCfg: ${error}`);
+                  return;
+                }
+
+                const targetUri = vscode.Uri.parse(result['uri']);
+                // can I have just this since we send the right shape?
+                // const selection = result['range'];
+                const startCol = 0;
+                const endCol = Math.max(0, result['range']['end']['character']);
+                const startLine = Math.max(0, result['range']['start']['line']);
+                // hack since the bb end is marked as the line with the following one
+                const endLine = Math.max(startLine, Math.max(0, result['range']['end']['line']) - (endCol == 0 ? 1 : 0));
+                const targetEditor = vscode.window.visibleTextEditors.find(editor => {
+                  return editor.document.uri.toString() === targetUri.toString();
+                });
+                if (targetEditor) {
+                  const selection = new vscode.Range(
+                    new vscode.Position(startLine, startCol),
+                    targetEditor.document.lineAt(endLine).range.end);
+                  await vscode.window.showTextDocument(targetEditor.document, {
+                    viewColumn: targetEditor.viewColumn,
+                    selection: selection,
+                    preserveFocus: false,
+                  });
+                  targetEditor.revealRange(selection, vscode.TextEditorRevealType.InCenter);
+                } else {
+                  const document = await vscode.workspace.openTextDocument(targetUri);
+                  const selection = new vscode.Range(
+                    new vscode.Position(startLine, startCol),
+                    document.lineAt(endLine).range.end);
+                  await vscode.window.showTextDocument(document, {
+                    viewColumn: findTabGroupColumn(targetUri, vscode.ViewColumn.Beside),
+                    selection: selection,
+                    preserveFocus: false,
+                    preview: false,
+                  });
+                }
+
+                this.context.outputChannel.appendLine(`Navigated to: ${targetUri.fsPath}`);
+                return;
+            }
+          },
+          undefined,
+          this.context.subscriptions
+        )
+      );
+    }
+  }
+}
+
+/**
+ * Find column of open document or fallback
+ *
+ * @param uri URI of file to open
+ * @param column Fallback column
+ * @returns Column with open editor of `uri`
+ */
+function findTabGroupColumn(uri: vscode.Uri, column: vscode.ViewColumn): vscode.ViewColumn {
+  if (vscode.window.tabGroups.all.length === 1) {
+    return column;
+  }
+
+  for (const tab of vscode.window.tabGroups.activeTabGroup.tabs) {
+    if (isTabOfUri(tab, uri)) {
+      return tab.group.viewColumn;
+    }
+  }
+
+  for (const tabGroup of vscode.window.tabGroups.all) {
+    if (tabGroup.viewColumn === column)
+      continue;
+
+    for (const tab of tabGroup.tabs) {
+      if (isTabOfUri(tab, uri)) {
+        return tab.group.viewColumn;
+      }
+    }
+  }
+
+  return column;
+}
+
+function isTabOfUri(tab: vscode.Tab, uri: vscode.Uri): boolean {
+  return tab.input instanceof vscode.TabInputText &&
+    tab.input.uri.fsPath.toLocaleLowerCase() === uri.fsPath.toLocaleLowerCase()
+}
+
+async function getWebviewContentWithInteraction(context: LLVMContext, data: Record<string, string>) {
+  const filePath = path.join(context.context.extensionPath, 'templates', 'cfgViewer.html');
+  let templateBytes = await vscode.workspace.fs.readFile(vscode.Uri.file(filePath));
+  let targetFileContent = Buffer.from(templateBytes).toString('utf8');
+
+  // TODO: safety!
+  for (const [key, value] of Object.entries(data)) {
+    const placeholder = new RegExp(`\\$\\{${key}\\}`, 'g');
+    targetFileContent = targetFileContent.replace(placeholder, value);
+  }
+
+  context.outputChannel.appendLine(`--- WEBVIEW SOURCE ---\n${targetFileContent}`);
+
+  return targetFileContent;
+}
diff --git a/llvm/utils/vscode/llvm/src/llvmContext.ts b/llvm/utils/vscode/llvm/src/llvmContext.ts
new file mode 100644
index 0000000000000..a71380f361d46
--- /dev/null
+++ b/llvm/utils/vscode/llvm/src/llvmContext.ts
@@ -0,0 +1,315 @@
+/**
+ * This file was copied from /mlir/utils/vscode/src/mlirContext.ts and adapted for use in LLVM
+ */
+
+
+import * as fs from 'fs';
+import * as path from 'path';
+import * as vscode from 'vscode';
+import * as vscodelc from 'vscode-languageclient/node';
+
+import * as config from './config';
+import * as configWatcher from './configWatcher';
+
+/**
+ *  This class represents the context of a specific workspace folder.
+ */
+class WorkspaceFolderContext implements vscode.Disposable {
+  dispose() {
+    // Close all clients for this workspace
+    this.clients.forEach(async client => await client.stop());
+    this.clients.clear();
+
+    // Close all open CFG views
+    this.cfgWebViews.forEach((value, key) => {
+      const webviews = Array.from(value.values());
+      for (const webview of webviews) {
+        webview.dispose();
+      }
+    })
+    this.cfgWebViews.clear();
+  }
+
+  clients: Map<string, vscodelc.LanguageClient> = new Map();
+  // Map of IR files and functions to tabs with their CFG
+  cfgWebViews = new Map<string, Map<string, vscode.WebviewPanel>>;
+}
+
+/**
+ *  This class manages all of the LLVM extension state,
+ *  including the language client.
+ */
+export class LLVMContext implements vscode.Disposable {
+  subscriptions: vscode.Disposable[] = [];
+  workspaceFolders: Map<string, WorkspaceFolderContext> = new Map();
+  outputChannel: vscode.OutputChannel;
+  context: vscode.ExtensionContext;
+
+  constructor(context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel) {
+    this.outputChannel = outputChannel;
+    this.context = context;
+  }
+
+  /**
+   *  Activate the LLVM context, and start the language clients.
+   */
+  async activate() {
+    // This lambda is used to lazily start language clients for the given
+    // document. It removes the need to pro-actively start language clients for
+    // every folder within the workspace and every language type we provide.
+    const startClientOnOpenDocument = async (document: vscode.TextDocument) => {
+      await this.getOrActivateLanguageClient(document.uri, document.languageId);
+    };
+    // Process any existing documents.
+    for (const textDoc of vscode.workspace.textDocuments) {
+      await startClientOnOpenDocument(textDoc);
+    }
+
+    // Watch any new documents to spawn servers when necessary.
+    this.subscriptions.push(
+      vscode.workspace.onDidOpenTextDocument(startClientOnOpenDocument));
+    this.subscriptions.push(
+      vscode.workspace.onDidChangeWorkspaceFolders((event) => {
+        for (const folder of event.removed) {
+          const client = this.workspaceFolders.get(folder.uri.toString());
+          if (client) {
+            client.dispose();
+            this.workspaceFolders.delete(folder.uri.toString());
+          }
+        }
+      }));
+  }
+
+  /**
+   * Open or return a language server for the given uri and language.
+   */
+  async getOrActivateLanguageClient(uri: vscode.Uri, languageId: string):
+    Promise<vscodelc.LanguageClient> {
+    let serverSettingName: string;
+    if (languageId === 'llvm') {
+      serverSettingName = 'serverPath';
+    } else {
+      return null;
+    }
+
+    // Check the scheme of the uri.
+    let validSchemes = ['file'];
+    if (!validSchemes.includes(uri.scheme)) {
+      return null;
+    }
+
+    // Resolve the workspace folder if this document is in one. We use the
+    // workspace folder when determining if a server needs to be started.
+    let workspaceFolder = vscode.workspace.getWorkspaceFolder(uri);
+    let workspaceFolderStr =
+      workspaceFolder ? workspaceFolder.uri.toString() : "";
+
+    // Get or create a client context for this folder.
+    let folderContext = this.workspaceFolders.get(workspaceFolderStr);
+    if (!folderContext) {
+      folderContext = new WorkspaceFolderContext();
+      this.workspaceFolders.set(workspaceFolderStr, folderContext);
+    }
+    // Start the client for this language if necessary.
+    let client = folderContext.clients.get(languageId);
+    if (!client) {
+      client = await this.activateWorkspaceFolder(
+        workspaceFolder, serverSettingName, languageId, this.outputChannel);
+      folderContext.clients.set(languageId, client);
+    }
+    return client;
+  }
+
+  /**
+   *  Activate the language client for the given language in the given workspace
+   *  folder.
+   */
+  async activateWorkspaceFolder(workspaceFolder: vscode.WorkspaceFolder,
+    serverSettingName: string, languageName: string,
+    outputChannel: vscode.OutputChannel):
+    Promise<vscodelc.LanguageClient> {
+    let configsToWatch: string[] = [];
+    let filepathsToWatch: string[] = [];
+    let additionalServerArgs: string[] = [];
+    additionalServerArgs = config.get<string[]>("additionalServerArgs", null, []);
+
+    // Try to activate the language client.
+    const [server, serverPath] = await this.startLanguageClient(
+      workspaceFolder, outputChannel, serverSettingName, languageName,
+      additionalServerArgs);
+    configsToWatch.push(serverSettingName);
+    configsToWatch.push('additionalServerArgs');
+    configsToWatch.push('trace.server');
+    filepathsToWatch.push(serverPath);
+
+    // Watch for configuration changes on this folder.
+    await configWatcher.activate(this, workspaceFolder, configsToWatch,
+      filepathsToWatch);
+    return server;
+  }
+
+  /**
+   *  Start a new language client for the given language. Returns an array
+   *  containing the opened server, or null if the server could not be started,
+   *  and the resolved server path.
+   */
+  async startLanguageClient(workspaceFolder: vscode.WorkspaceFolder,
+    outputChannel: vscode.OutputChannel,
+    serverSettingName: string, languageName: string,
+    additionalServerArgs: string[]):
+    Promise<[vscodelc.LanguageClient, string]> {
+    const clientTitle = languageName.toUpperCase() + ' Language Client';
+
+    // Get the path of the lsp-server that is used to provide language
+    // functionality.
+    var serverPath =
+      await this.resolveServerPath(serverSettingName, workspaceFolder);
+
+    // If the server path is empty, bail. We don't emit errors if the user
+    // hasn't explicitly configured the server.
+    if (serverPath === '') {
+      return [null, serverPath];
+    }
+
+    // Check that the file actually exists.
+    if (!fs.existsSync(serverPath)) {
+      vscode.window
+        .showErrorMessage(
+          `${clientTitle}: Unable to resolve path for '${serverSettingName}', please ensure the path is correct`,
+          "Open Setting")
+        .then((value) => {
+          if (value === "Open Setting") {
+            vscode.commands.executeCommand(
+              'workbench.action.openWorkspaceSettings',
+              { openToSide: false, query: `llvm.${serverSettingName}` });
+          }
+        });
+      return [null, serverPath];
+    }
+
+    // Configure the server options.
+    const serverOptions: vscodelc.ServerOptions = {
+      command: serverPath,
+      args: additionalServerArgs
+    };
+
+    // Configure file patterns relative to the workspace folder.
+    let filePattern: vscode.GlobPattern = '**/*.' + languageName; // TODO: langageName is wrong, we need extension?
+    let selectorPattern: string = null;
+    if (workspaceFolder) {
+      filePattern = new vscode.RelativePattern(workspaceFolder, filePattern);
+      selectorPattern = `${workspaceFolder.uri.fsPath}/**/*`;
+    }
+
+    // Configure the middleware of the client. This is sort of abused to allow
+    // for defining a "fallback" language server that operates on non-workspace
+    // folders. Workspace folder language servers can properly filter out
+    // documents not within the folder, but we can't effectively filter for
+    // documents outside of the workspace. To support this, and avoid having two
+    // servers targeting the same set of files, we use middleware to inject the
+    // dynamic logic for checking if a document is in the workspace.
+    let middleware = {};
+    if (!workspaceFolder) {
+      middleware = {
+        didOpen: (document, next): Promise<void> => {
+          if (!vscode.workspace.getWorkspaceFolder(document.uri)) {
+            return next(document);
+          }
+          return Promise.resolve();
+        }
+      };
+    }
+
+    // Configure the client options.
+    const clientOptions: vscodelc.LanguageClientOptions = {
+      documentSelector: [
+        { language: languageName, pattern: selectorPattern },
+      ],
+      synchronize: {
+        // Notify the server about file changes to language files contained in
+        // the workspace.
+        fileEvents: vscode.workspace.createFileSystemWatcher(filePattern)
+      },
+      outputChannel: outputChannel,
+      workspaceFolder: workspaceFolder,
+      middleware: middleware,
+
+      // Don't switch to output window when the server returns output.
+      revealOutputChannelOn: vscodelc.RevealOutputChannelOn.Never,
+    };
+
+    // Create the language client and start the client.
+    let languageClient = new vscodelc.LanguageClient(
+      languageName, clientTitle, serverOptions, clientOptions);
+    languageClient.start();
+    return [languageClient, serverPath];
+  }
+
+  /**
+   * Given a server setting, return the default server path.
+   */
+  static getDefaultServerFilename(serverSettingName: string): string {
+    if (serverSettingName === 'serverPath') {
+      return 'llvm-lsp-server';
+    }
+    return '';
+  }
+
+  /**
+   * Try to resolve the given path, or the default path, with an optional
+   * workspace folder. If a path could not be resolved, just returns the
+   * input filePath.
+   */
+  async resolvePath(filePath: string, defaultPath: string,
+    workspaceFolder: vscode.WorkspaceFolder): Promise<string> {
+    const configPath = filePath;
+
+    // If the path is already fully resolved, there is nothing to do.
+    if (path.isAbsolute(filePath)) {
+      return filePath;
+    }
+
+    // If a path hasn't been set, try to use the default path.
+    if (filePath === '') {
+      if (defaultPath === '') {
+        return filePath;
+      }
+      filePath = defaultPath;
+
+      // Fallthrough to try resolving the default path.
+    }
+
+    // Try to resolve the path relative to the workspace.
+    let filePattern: vscode.GlobPattern = '**/' + filePath;
+    if (workspaceFolder) {
+      filePattern = new vscode.RelativePattern(workspaceFolder, filePattern);
+    }
+    let foundUris = await vscode.workspace.findFiles(filePattern, null, 1);
+    if (foundUris.length === 0) {
+      // If we couldn't resolve it, just return the original path anyways. The
+      // file might not exist yet.
+      return configPath;
+    }
+    // Otherwise, return the resolved path.
+    return foundUris[0].fsPath;
+  }
+
+  /**
+   * Try to resolve the path for the given server setting, with an optional
+   * workspace folder.
+   */
+  async resolveServerPath(serverSettingName: string,
+    workspaceFolder: vscode.WorkspaceFolder):
+    Promise<string> {
+    const serverPath = config.get<string>(serverSettingName, workspaceFolder);
+    const defaultPath = LLVMContext.getDefaultServerFilename(serverSettingName);
+    return this.resolvePath(serverPath, defaultPath, workspaceFolder);
+  }
+
+  dispose() {
+    this.subscriptions.forEach((d) => { d.dispose(); });
+    this.subscriptions = [];
+    this.workspaceFolders.forEach((d) => { d.dispose(); });
+    this.workspaceFolders.clear();
+  }
+}
diff --git a/llvm/utils/vscode/llvm/src/lspCustomMessages.ts b/llvm/utils/vscode/llvm/src/lspCustomMessages.ts
new file mode 100644
index 0000000000000..010c8558aa175
--- /dev/null
+++ b/llvm/utils/vscode/llvm/src/lspCustomMessages.ts
@@ -0,0 +1,35 @@
+import {
+  RequestType,
+  URI,
+  Position,
+  Range,
+  uinteger,
+} from 'vscode-languageclient';
+
+
+/* CFG-related messages */
+
+export namespace LlvmGetCfg {
+  export interface Params {
+    uri: URI;
+    position: Position;
+  }
+  export interface Response {
+    uri: URI;
+    node_id: string;
+    function: string;
+  }
+  export const Type = new RequestType<Params, Response, void>('llvm/getCfg');
+}
+
+export namespace LlvmBbLocation {
+  export interface Params {
+    uri: URI;
+    node_id: string;
+  }
+  export interface Response {
+    uri: URI;
+    range: Range;
+  }
+  export const Type = new RequestType<Params, Response, void>('llvm/bbLocation');
+}
diff --git a/llvm/utils/vscode/llvm/templates/cfgViewer.html b/llvm/utils/vscode/llvm/templates/cfgViewer.html
new file mode 100644
index 0000000000000..423a27874e3f3
--- /dev/null
+++ b/llvm/utils/vscode/llvm/templates/cfgViewer.html
@@ -0,0 +1,609 @@
+<!-- Most of the code in this file was created using Gemini 2.5 -->
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Interactive View of ${fileName}</title>
+    <style>
+        body,
+        html {
+            margin: 0;
+            padding: 0;
+            width: 100%;
+            height: 100%;
+            overflow: hidden;
+            /* Darker background, common in IDEs */
+            background-color: #1e1e1e;
+            display: flex;
+            flex-direction: column;
+            /* A more common IDE font */
+            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+            /* Lighter default text color for dark theme */
+            color: #d4d4d4;
+        }
+
+        h2 {
+            padding: 10px 15px;
+            margin: 0;
+            /* Slightly lighter than body for header */
+            background-color: #252526;
+            border-bottom: 1px solid #333;
+            font-size: 1.1em;
+            font-weight: normal;
+            color: #d4d4d4;
+            flex-shrink: 0;
+        }
+
+        #search-controls {
+            padding: 8px 15px;
+            /* Distinct from header and body */
+            background-color: #2c2c2c;
+            display: flex;
+            align-items: center;
+            gap: 10px;
+            flex-shrink: 0;
+            border-bottom: 1px solid #3c3c3c;
+        }
+
+        #search-input {
+            flex-grow: 1;
+            padding: 6px 10px;
+            border: 1px solid #444;
+            background-color: #333;
+            color: #d4d4d4;
+            border-radius: 4px;
+            outline: none;
+            transition: border-color 0.2s ease-in-out;
+        }
+
+        #search-input:focus {
+            /* VS Code blue highlight on focus */
+            border-color: #007acc;
+        }
+
+        #search-controls button {
+            padding: 6px 12px;
+            /* VS Code primary button color */
+            background-color: #007acc;
+            color: white;
+            border: none;
+            cursor: pointer;
+            border-radius: 4px;
+            transition: background-color 0.2s ease-in-out, transform 0.1s ease-out;
+            font-size: 0.9em;
+        }
+
+        #search-controls button:hover {
+            background-color: #005f99;
+            transform: translateY(-1px);
+        }
+
+        #search-controls button:active {
+            transform: translateY(0);
+        }
+
+        #search-status {
+            color: #a0a0a0;
+            font-size: 0.85em;
+            /* Prevent text jumping */
+            min-width: 80px;
+            text-align: right;
+        }
+
+        #clear-search {
+            margin-left: auto;
+            /* Different color for clear button */
+            background-color: #5a5a5a;
+        }
+
+        #clear-search:hover {
+            background-color: #7a7a7a;
+        }
+
+        #svg-container {
+            width: 100%;
+            flex-grow: 1;
+            cursor: default;
+            overflow: hidden;
+            user-select: none;
+            position: relative;
+            /* Match body background */
+            background-color: #1e1e1e;
+        }
+
+        #svg-container.pannable-ctrl {
+            cursor: grab;
+        }
+
+        #svg-container.panning {
+            cursor: grabbing;
+        }
+
+        svg {
+            transform-origin: 0 0;
+            user-select: none;
+            width: 100%;
+            height: 100%;
+        }
+
+        /* Highlighting for search results */
+        /* Using a more subtle green/blue for highlights that fits a dark theme */
+        .search-highlight {
+            /* Greenish */
+            fill: #4CAF50 !important;
+            font-weight: bold;
+            transition: fill 0.2s ease-in-out;
+        }
+
+        .current-search-highlight {
+            /* Sky Blue */
+            fill: #00BFFF !important;
+            font-weight: bold;
+            transition: fill 0.2s ease-in-out;
+            /* A thin border for the current match */
+            outline: 1px solid #00BFFF;
+            outline-offset: 2px;
+        }
+
+        svg *[id].node:hover,
+        svg *[id].edge:hover {
+            opacity: 0.9;
+            cursor: pointer;
+            /* Subtle hover outline */
+            outline: 1px dashed #66b3ff;
+            outline-offset: 2px;
+            transition: opacity 0.2s ease-in-out, outline-color 0.2s ease-in-out;
+        }
+
+        svg *[id].node text,
+        svg *[id].edge text,
+        svg *[id].node tspan,
+        svg *[id].edge tspan {
+            cursor: text;
+            user-select: text;
+        }
+    </style>
+</head>
+
+<body>
+    <h2>Interactive view of ${fileName}</h2>
+    <div id="search-controls">
+        <input type="text" id="search-input" placeholder="Search text in SVG...">
+        <button id="prev-match">Previous</button>
+        <button id="next-match">Next</button>
+        <span id="search-status"></span>
+        <button id="clear-search" style="margin-left: auto;">Clear</button>
+    </div>
+    <div id="svg-container">
+        ${svgContent}
+    </div>
+
+    <script>
+            // --- VS Code API Communication ---
+            const vscode = typeof acquireVsCodeApi === 'function' ? acquireVsCodeApi() : null;
+
+            function postVsCodeMessage(command, data = {}) {
+                if (vscode) {
+                    vscode.postMessage({ command, ...data });
+                } else {
+                    console.warn('VS Code API not available. Cannot post message:', command, data);
+                }
+        }
+
+            function debugLog(msg) {
+                postVsCodeMessage('cfgViewerDebug', { msg: `[InteractiveView script DEBUG] ${msg}` });
+            }
+
+            // --- DOM Elements ---
+            const svgContainer = document.getElementById('svg-container');
+        const searchInput = document.getElementById('search-input');
+        const prevMatchButton = document.getElementById('prev-match');
+        const nextMatchButton = document.getElementById('next-match');
+        const searchStatus = document.getElementById('search-status');
+        const clearSearchButton = document.getElementById('clear-search');
+
+            let svgElement = null; // Will be set after SVG content is loaded
+
+            // --- State Variables ---
+            const P_Z_STATE = { // Pan/Zoom State
+                scale: 1,
+                panOffset: { x: 0, y: 0 },
+                isPanning: false,
+                ctrlPressed: false,
+                startPoint: { x: 0, y: 0 }, // Mouse position at mousedown
+                dragThreshold: 3, // Pixels before a mousemove becomes a drag
+                hasDragged: false,
+                panInitiatorButton: -1 // 0 for left, 1 for middle
+            };
+
+            const SEARCH_STATE = {
+                results: [],
+                currentIndex: -1
+            };
+
+            // --- Utility Functions ---
+
+            /**
+             * Applies the current pan and zoom transform to the SVG element.
+             */
+            function updateSvgTransform() {
+                if (svgElement) {
+                    const { panOffset, scale } = P_Z_STATE;
+                    svgElement.style.transform = `translate(${panOffset.x}px, ${panOffset.y}px) scale(${scale})`;
+            }
+        }
+
+            /**
+             * Centers the view on a given SVG element.
+             * @param {SVGElement} element - The SVG element to center on.
+             */
+            function centerOnElement(element) {
+                debugLog('centerOnElement()');
+                if (!element || !svgContainer || !svgElement) return;
+
+            // Ensure element has correct layout properties
+            element.getBoundingClientRect();
+
+            const elementRect = element.getBoundingClientRect(); // Relative to viewport
+            const containerRect = svgContainer.getBoundingClientRect(); // Relative to viewport
+
+            if (elementRect.width === 0 && elementRect.height === 0) {
+                console.warn("Cannot center on an element with zero dimensions:", element);
+                return;
+            }
+
+            const currentSvgScale = P_Z_STATE.scale;
+
+            // Calculate centers in viewport coordinates
+            const elementCenterX = elementRect.left + elementRect.width / 2;
+            const elementCenterY = elementRect.top + elementRect.height / 2;
+            const containerCenterX = containerRect.left + containerRect.width / 2;
+            const containerCenterY = containerRect.top + containerRect.height / 2;
+
+            // Desired shift in viewport pixels
+            const dxViewport = containerCenterX - elementCenterX;
+            const dyViewport = containerCenterY - elementCenterY;
+
+            // Convert viewport shift to SVG pan units
+            P_Z_STATE.panOffset.x += dxViewport;
+            P_Z_STATE.panOffset.y += dyViewport;
+
+            updateSvgTransform();
+        }
+
+            // --- SVG Content Initialization ---
+            function initializeSvgContent() {
+                svgElement = svgContainer.querySelector('svg');
+                if (svgElement) {
+                    svgElement.style.transformOrigin = '0 0';
+                    updateSvgTransform();
+                    debugLog('SVG element initialized.');
+                } else {
+                    console.error("SVG element not found inside #svg-container.");
+                }
+            }
+
+            // Call on initial load
+            initializeSvgContent();
+
+            // --- Event Handlers ---
+
+            // Panning and Zooming
+            const handleWheel = (event) => {
+                // Only zoom with Ctrl or if search input is not focused
+                if (!P_Z_STATE.ctrlPressed && document.activeElement !== searchInput) return;
+                if (document.activeElement === searchInput && !P_Z_STATE.ctrlPressed) return;
+
+            event.preventDefault(); // Prevent page scrolling
+
+            const zoomIntensity = 0.1;
+            const direction = event.deltaY < 0 ? 1 : -1; // -1 for wheel down (zoom out), 1 for wheel up (zoom in)
+            const oldScale = P_Z_STATE.scale;
+
+            P_Z_STATE.scale += direction * zoomIntensity * P_Z_STATE.scale;
+            P_Z_STATE.scale = Math.max(0.05, Math.min(P_Z_STATE.scale, 20)); // Clamp scale
+
+            const rect = svgContainer.getBoundingClientRect();
+            const mouseX = event.clientX - rect.left;
+            const mouseY = event.clientY - rect.top;
+
+            P_Z_STATE.panOffset.x = mouseX - (mouseX - P_Z_STATE.panOffset.x) * (P_Z_STATE.scale / oldScale);
+            P_Z_STATE.panOffset.y = mouseY - (mouseY - P_Z_STATE.panOffset.y) * (P_Z_STATE.scale / oldScale);
+
+            updateSvgTransform();
+        };
+
+            const handleMouseDown = (event) => {
+                if (event.target.closest('#search-controls')) return;
+
+            // Check if clicking directly on text within a node/edge
+            let target = event.target;
+            let isTextElement = false;
+            while (target && target !== svgElement) {
+                if ((target.tagName === 'text' || target.tagName === 'tspan') &&
+                    target.closest && target.closest('.node, .edge')) {
+                    isTextElement = true;
+                    break;
+                }
+                target = target.parentElement;
+            }
+            if (isTextElement && !P_Z_STATE.ctrlPressed && event.button === 0) {
+                // Allow default text selection for left-click on text without Ctrl
+                return;
+            }
+
+            // Initiate pan with Ctrl+Left or Middle Mouse Button
+            if ((P_Z_STATE.ctrlPressed && event.button === 0) || event.button === 1) {
+                P_Z_STATE.isPanning = true;
+                P_Z_STATE.panInitiatorButton = event.button;
+                P_Z_STATE.hasDragged = false;
+                svgContainer.classList.remove('pannable-ctrl');
+                svgContainer.classList.add('panning');
+                P_Z_STATE.dragStartPos = { x: event.clientX, y: event.clientY };
+                P_Z_STATE.startPoint = { x: event.clientX - P_Z_STATE.panOffset.x, y: event.clientY - P_Z_STATE.panOffset.y };
+                event.preventDefault(); // Prevent default browser drag behaviors
+            } else if (event.button === 0) {
+                // Left click without Ctrl for potential click event (not drag)
+                P_Z_STATE.hasDragged = false;
+                P_Z_STATE.dragStartPos = { x: event.clientX, y: event.clientY };
+            }
+        };
+
+            const handleMouseMove = (event) => {
+                if (!P_Z_STATE.isPanning) return;
+
+            if (!P_Z_STATE.hasDragged) {
+                const dx = event.clientX - P_Z_STATE.dragStartPos.x;
+                const dy = event.clientY - P_Z_STATE.dragStartPos.y;
+                if (Math.abs(dx) > P_Z_STATE.dragThreshold || Math.abs(dy) > P_Z_STATE.dragThreshold) {
+                    P_Z_STATE.hasDragged = true;
+                }
+            }
+
+            if (P_Z_STATE.hasDragged) {
+                event.preventDefault();
+                P_Z_STATE.panOffset.x = event.clientX - P_Z_STATE.startPoint.x;
+                P_Z_STATE.panOffset.y = event.clientY - P_Z_STATE.startPoint.y;
+                updateSvgTransform();
+            }
+        };
+
+            const handleMouseUp = (event) => {
+                const clickedOnSearchControls = event.target.closest('#search-controls');
+
+            if (P_Z_STATE.isPanning && (event.button === P_Z_STATE.panInitiatorButton || P_Z_STATE.panInitiatorButton === -1)) {
+                P_Z_STATE.isPanning = false;
+                P_Z_STATE.panInitiatorButton = -1;
+                svgContainer.classList.remove('panning');
+                if (P_Z_STATE.ctrlPressed) {
+                    svgContainer.classList.add('pannable-ctrl');
+                } else {
+                    svgContainer.classList.remove('pannable-ctrl');
+                }
+            }
+
+            // Handle non-dragged left clicks on SVG elements
+            if (!P_Z_STATE.hasDragged && event.button === 0 && !P_Z_STATE.ctrlPressed && !clickedOnSearchControls) {
+                let clickedElement = event.target;
+                let actionableElement = null;
+                while (clickedElement && clickedElement !== svgElement) {
+                    if (clickedElement.id && (clickedElement.classList.contains('node') || clickedElement.classList.contains('edge'))) {
+                        actionableElement = clickedElement;
+                        break;
+                    }
+                    clickedElement = clickedElement.parentElement;
+                }
+
+                if (actionableElement) {
+                    let actualClickTarget = event.target;
+                    let isTextClick = false;
+                    while (actualClickTarget && actualClickTarget !== actionableElement.parentElement) {
+                        if ((actualClickTarget.tagName === 'text' || actualClickTarget.tagName === 'tspan') && actualClickTarget.closest('#' + actionableElement.id)) {
+                            isTextClick = true;
+                            break;
+                        }
+                        if (actualClickTarget === actionableElement) break;
+                        actualClickTarget = actualClickTarget.parentElement;
+                    }
+
+                    if (!isTextClick) {
+                        postVsCodeMessage('svgElementClicked', { elementId: actionableElement.id });
+                        debugLog(`SVG element clicked: ${actionableElement.id}`);
+                    }
+                }
+            }
+            P_Z_STATE.hasDragged = false;
+        };
+
+            const handleKeyDown = (event) => {
+                if (event.key === 'Control' && !P_Z_STATE.ctrlPressed) {
+                    P_Z_STATE.ctrlPressed = true;
+                    if (!P_Z_STATE.isPanning) svgContainer.classList.add('pannable-ctrl');
+                }
+                if (document.activeElement === searchInput) {
+                    if (event.key === 'Enter') {
+                        event.preventDefault();
+                        SEARCH_MODULE.navigateNextMatch(true); // Navigate and refocus input
+                    } else if (event.key === 'Escape') {
+                        SEARCH_MODULE.clearSearchAndResults();
+                    }
+                }
+            };
+
+            const handleKeyUp = (event) => {
+                if (event.key === 'Control') {
+                    P_Z_STATE.ctrlPressed = false;
+                    if (!P_Z_STATE.isPanning) {
+                        svgContainer.classList.remove('pannable-ctrl');
+                        svgContainer.classList.remove('panning');
+                    }
+                }
+            };
+
+            const handleWindowBlur = () => {
+                // Reset Ctrl state and panning when window loses focus
+                if (P_Z_STATE.ctrlPressed) {
+                    P_Z_STATE.ctrlPressed = false;
+                    svgContainer.classList.remove('pannable-ctrl');
+            }
+            if (P_Z_STATE.isPanning) {
+                P_Z_STATE.isPanning = false;
+                svgContainer.classList.remove('panning');
+                P_Z_STATE.panInitiatorButton = -1;
+            }
+        };
+
+            // --- Search Module ---
+            const SEARCH_MODULE = (() => {
+            function clearHighlights() {
+                if (!svgElement) return;
+                svgElement.querySelectorAll('.search-highlight, .current-search-highlight').forEach(el => {
+                    el.classList.remove('search-highlight', 'current-search-highlight');
+                    // Potentially remove outline as well
+                    el.style.outline = '';
+                    el.style.outlineOffset = '';
+                });
+            }
+
+            function performSearch() {
+                clearHighlights();
+                SEARCH_STATE.results = [];
+                SEARCH_STATE.currentIndex = -1;
+                const searchTerm = searchInput.value.trim().toLowerCase();
+
+                if (!searchTerm) {
+                    searchStatus.textContent = "";
+                    return;
+                }
+                if (!svgElement) {
+                    searchStatus.textContent = "SVG not loaded.";
+                    return;
+                }
+
+                const textElements = svgElement.querySelectorAll('text, tspan');
+                textElements.forEach(el => {
+                    if (el.textContent.toLowerCase().includes(searchTerm)) {
+                        SEARCH_STATE.results.push(el);
+                        el.classList.add('search-highlight');
+                    }
+                });
+
+                if (SEARCH_STATE.results.length > 0) {
+                    SEARCH_STATE.currentIndex = 0;
+                    navigateToMatch(SEARCH_STATE.currentIndex);
+                } else {
+                    searchStatus.textContent = "No matches";
+                }
+            }
+
+            function navigateToMatch(index, refocusInput = false) {
+                if (SEARCH_STATE.results.length === 0 || index < 0 || index >= SEARCH_STATE.results.length) {
+                    searchStatus.textContent = SEARCH_STATE.results.length > 0 ?
+                        `${SEARCH_STATE.currentIndex + 1} of ${SEARCH_STATE.results.length}` : "No matches";
+                    return;
+                }
+
+                // Remove 'current' highlight from previous match
+                if (SEARCH_STATE.currentIndex !== -1 && SEARCH_STATE.results[SEARCH_STATE.currentIndex]) {
+                    SEARCH_STATE.results[SEARCH_STATE.currentIndex].classList.remove('current-search-highlight');
+                    SEARCH_STATE.results[SEARCH_STATE.currentIndex].classList.add('search-highlight');
+                }
+
+                SEARCH_STATE.currentIndex = index;
+                const currentElement = SEARCH_STATE.results[SEARCH_STATE.currentIndex];
+                currentElement.classList.add('current-search-highlight');
+                currentElement.classList.remove('search-highlight');
+
+                searchStatus.textContent = `${SEARCH_STATE.currentIndex + 1} of ${SEARCH_STATE.results.length}`;
+                centerOnElement(currentElement);
+
+                if (refocusInput) {
+                    searchInput.focus();
+                    searchInput.select();
+                }
+            }
+
+            function navigateNextMatch(refocus = false) {
+                if (SEARCH_STATE.results.length > 0) {
+                    const nextIndex = (SEARCH_STATE.currentIndex + 1) % SEARCH_STATE.results.length;
+                    navigateToMatch(nextIndex, refocus);
+                } else {
+                    performSearch(); // If no results, try to search again
+                }
+            }
+
+            function navigatePrevMatch() {
+                if (SEARCH_STATE.results.length > 0) {
+                    const prevIndex = (SEARCH_STATE.currentIndex - 1 + SEARCH_STATE.results.length) % SEARCH_STATE.results.length;
+                    navigateToMatch(prevIndex);
+                } else {
+                    performSearch(); // If no results, try to search again
+                }
+            }
+
+            function clearSearchAndResults() {
+                searchInput.value = "";
+                clearHighlights();
+                SEARCH_STATE.results = [];
+                SEARCH_STATE.currentIndex = -1;
+                searchStatus.textContent = "";
+            }
+
+            // Public API for the search module
+            return {
+                performSearch,
+                navigateNextMatch,
+                navigatePrevMatch,
+                clearSearchAndResults,
+                clearHighlights // Expose for external use if needed (e.g., SVG content update)
+            };
+        })();
+
+            // --- Event Listener Registrations ---
+            svgContainer.addEventListener('wheel', handleWheel, { passive: false });
+            svgContainer.addEventListener('mousedown', handleMouseDown);
+            document.addEventListener('mousemove', handleMouseMove); // Listen on document for continuous drag
+            document.addEventListener('mouseup', handleMouseUp);   // Listen on document to capture release outside container
+
+            window.addEventListener('keydown', handleKeyDown);
+            window.addEventListener('keyup', handleKeyUp);
+            window.addEventListener('blur', handleWindowBlur);
+
+            searchInput.addEventListener('input', SEARCH_MODULE.performSearch);
+            nextMatchButton.addEventListener('click', () => SEARCH_MODULE.navigateNextMatch());
+            prevMatchButton.addEventListener('click', SEARCH_MODULE.navigatePrevMatch);
+            clearSearchButton.addEventListener('click', SEARCH_MODULE.clearSearchAndResults);
+
+            // --- VS Code Message Handling ---
+            window.addEventListener("message", event => {
+                const message = event.data;
+                switch (message.command) {
+                    case 'centerOn':
+                        // Re-query svgElement in case it was updated dynamically
+                        if (!svgElement) initializeSvgContent();
+                        const elementToCenter = svgElement ? svgElement.querySelector(`#${message.node}`) : null;
+                        if (elementToCenter) centerOnElement(elementToCenter);
+                        else console.warn(`Element with ID ${message.node} not found for centering.`);
+                        break;
+                    case 'updateSvgContent':
+                        if (message.content) {
+                            svgContainer.innerHTML = message.content;
+                            initializeSvgContent(); // Re-initialize SVG element and transform
+                            SEARCH_MODULE.clearSearchAndResults(); // Clear search on new SVG content
+                            debugLog('SVG content updated.');
+                    }
+                    break;
+                case 'resetView': // Added command to reset pan and zoom
+                    P_Z_STATE.scale = 1;
+                    P_Z_STATE.panOffset = { x: 0, y: 0 };
+                    updateSvgTransform();
+                    debugLog('View reset.');
+                    break;
+            }
+        });
+    </script>
+</body>
+
+</html>
diff --git a/llvm/utils/vscode/llvm/tsconfig.json b/llvm/utils/vscode/llvm/tsconfig.json
index 6b4dc05c1492c..40116607ffa91 100644
--- a/llvm/utils/vscode/llvm/tsconfig.json
+++ b/llvm/utils/vscode/llvm/tsconfig.json
@@ -1,20 +1,24 @@
 {
 	"compilerOptions": {
 		"module": "commonjs",
-		"target": "es6",
-		"outDir": "out",
+		"target": "es2020",
 		"lib": [
-			"es6"
+			"es2020"
 		],
-		"sourceMap": true,
+		"outDir": "out",
 		"rootDir": "src",
-		"strict": true   /* enable all strict type-checking options */
+		"sourceMap": true,
+		// "strict": true   /* enable all strict type-checking options */
 		/* Additional Checks */
 		// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
 		// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
 		// "noUnusedParameters": true,  /* Report errors on unused parameters. */
 	},
+	"include": [
+		"src"
+	],
 	"exclude": [
-		"node_modules"
+		"node_modules",
+		".vscode-test"
 	]
 }



More information about the llvm-commits mailing list