diff --git a/MagicEyes/src/visualization/vscode_ext/README.md b/MagicEyes/src/visualization/vscode_ext/README.md new file mode 100644 index 000000000..1f1a6c5e1 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/README.md @@ -0,0 +1,46 @@ +# lmp vscode 插件使用指南 + +### 1. 运行效果 + +![](./images/lmp_vscode_ext.gif) + +### 2. 相关提示 + +设置可视化面板存放路径 + +> 注意:别忘记面板路径后面加 "/" + +![](./images/set_panel_addr.png) + +面板命名必须遵循如下规则: + +![](./images/panel_name.png) + +若面板不存在,或路径,或名称不对,将出现如下错误提示: + +![](./images/error_info.png) + +### 3. 开发注意事项 + +1. yo code生成的框架,vscode最小版本是1.90,需要修改为1.74,不然我当前的版本。1.89无法运行插件 +2. tsconfig + +```json +{ + "compilerOptions": { + "module": "commonjs", // 不要用Node16,不然命令会触发失败 + "target": "ES2021", + "lib": ["ES2021"], + "sourceMap": true, + "rootDir": "src", + "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. */ + } +} +``` + + + diff --git a/MagicEyes/src/visualization/vscode_ext/images/error_info.png b/MagicEyes/src/visualization/vscode_ext/images/error_info.png new file mode 100644 index 000000000..90ef0fb71 Binary files /dev/null and b/MagicEyes/src/visualization/vscode_ext/images/error_info.png differ diff --git a/MagicEyes/src/visualization/vscode_ext/images/lmp_vscode_ext.gif b/MagicEyes/src/visualization/vscode_ext/images/lmp_vscode_ext.gif new file mode 100644 index 000000000..e875aa485 Binary files /dev/null and b/MagicEyes/src/visualization/vscode_ext/images/lmp_vscode_ext.gif differ diff --git a/MagicEyes/src/visualization/vscode_ext/images/panel_name.png b/MagicEyes/src/visualization/vscode_ext/images/panel_name.png new file mode 100644 index 000000000..103edbfd4 Binary files /dev/null and b/MagicEyes/src/visualization/vscode_ext/images/panel_name.png differ diff --git a/MagicEyes/src/visualization/vscode_ext/images/set_panel_addr.png b/MagicEyes/src/visualization/vscode_ext/images/set_panel_addr.png new file mode 100644 index 000000000..20b6d5e5c Binary files /dev/null and b/MagicEyes/src/visualization/vscode_ext/images/set_panel_addr.png differ diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.eslintrc.json b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.eslintrc.json new file mode 100644 index 000000000..5dfecab7e --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module" + }, + "plugins": ["@typescript-eslint"], + "rules": { + "@typescript-eslint/naming-convention": "warn", + "@typescript-eslint/semi": "warn", + "curly": "warn", + "eqeqeq": "warn", + "no-throw-literal": "warn", + "semi": "off" + }, + "ignorePatterns": ["out", "dist", "**/*.d.ts"] +} diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.github/workflows/dashboards.yml b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.github/workflows/dashboards.yml new file mode 100644 index 000000000..fdcb9c114 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.github/workflows/dashboards.yml @@ -0,0 +1,39 @@ +name: Update dashboards + +on: + push: + branches: + - main + paths: + - dashboards/**.json + +jobs: + update-dashboards: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Get changed dashboards + id: changed-files + uses: tj-actions/changed-files@v41 + with: + files: dashboards/**.json + + - name: Update changed dashboards in Grafana + if: steps.changed-files.outputs.any_changed == 'true' + run: | + tmp=$(mktemp) + for file in ${{ steps.changed-files.outputs.all_changed_files }}; do + uid=$(jq -r '.uid' $file) + dashboardInfo=$(curl -H "Authorization: Bearer $GRAFANA_API_TOKEN" $GRAFANA_INSTANCE_URL/api/dashboards/uid/$uid) + currentVersion=$(echo $dashboardInfo | jq -r '.meta.version') + jq --argjson v $currentVersion '.version = $v' $file > $tmp && mv $tmp $file + dashboardJson='{"dashboard":'"$(jq -c . $file)"',"message":"'"$COMMIT_MESSAGE"'"}' + curl -X POST $GRAFANA_INSTANCE_URL/api/dashboards/db -H "Content-Type: application/json" -H "Authorization: Bearer $GRAFANA_API_TOKEN" -d "$dashboardJson" + done + env: + GRAFANA_INSTANCE_URL: ${{ secrets.GRAFANA_INSTANCE_URL }} + GRAFANA_API_TOKEN: ${{ secrets.GRAFANA_API_TOKEN }} + COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.github/workflows/publish.yml b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.github/workflows/publish.yml new file mode 100644 index 000000000..281dfad47 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.github/workflows/publish.yml @@ -0,0 +1,48 @@ +on: + push: + tags: + - "*" + +# These permissions are needed to assume roles from Github's OIDC. +permissions: + contents: write + id-token: write + +name: Publish Extension +jobs: + eslint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: npm run compile + - run: npm run lint + publish: + needs: eslint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - id: get-secrets + uses: grafana/shared-workflows/actions/get-vault-secrets@main + with: + # Secrets placed in the ci/repo/grafana// path in Vault + repo_secrets: | + OPEN_VSX_TOKEN=openvsx:token + VS_MARKETPLACE_TOKEN=vscode-marketplace:token + - name: Publish to Open VSX + uses: HaaLeo/publish-vscode-extension@v0 + with: + pat: ${{ env.OPEN_VSX_TOKEN }} + registryUrl: https://open-vsx.org + - name: Publish to Visual Studio Marketplace + id: publishToMarketplace + uses: HaaLeo/publish-vscode-extension@v0 + with: + pat: ${{ env.VS_MARKETPLACE_TOKEN }} + registryUrl: https://marketplace.visualstudio.com + - uses: ncipollo/release-action@v1 + with: + allowUpdates: true + artifacts: "${{ steps.publishToMarketplace.outputs.vsixPath }}" + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.gitignore b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.gitignore new file mode 100644 index 000000000..f27bbfb36 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.gitignore @@ -0,0 +1,5 @@ +!.vscode +.yarn +node_modules +.idea +dist \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.prettierrc.json b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.prettierrc.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscode/extensions.json b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscode/extensions.json new file mode 100644 index 000000000..57dbdae42 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher"] +} diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscode/launch.json b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscode/launch.json new file mode 100644 index 000000000..0fcf4f973 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscode/launch.json @@ -0,0 +1,35 @@ +// A launch configuration that compiles the extension and then opens it inside a new window +// Use IntelliSense to learn about possible attributes. +// Hover to view descriptions of existing attributes. +// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension", + "type": "extensionHost", + "request": "launch", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}", + "--disable-extensions" + ], + "outFiles": ["${workspaceFolder}/dist/**/*.js"], + "preLaunchTask": "${defaultBuildTask}" + }, + { + "name": "Extension Tests", + "type": "extensionHost", + "request": "launch", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}", + "--extensionTestsPath=${workspaceFolder}/out/test/suite/index", + "--disable-extensions" + ], + "outFiles": [ + "${workspaceFolder}/out/**/*.js", + "${workspaceFolder}/dist/**/*.js" + ], + "preLaunchTask": "tasks: watch-tests" + } + ] +} diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscode/settings.json b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscode/settings.json new file mode 100644 index 000000000..64ee92966 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscode/settings.json @@ -0,0 +1,13 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.exclude": { + "out": false, // set this to true to hide the "out" folder with the compiled JS files + "dist": false // set this to true to hide the "dist" folder with the compiled JS files + }, + "search.exclude": { + "out": true, // set this to false to include "out" folder in search results + "dist": true // set this to false to include "dist" folder in search results + }, + // Turn off tsc task auto detection since we have the necessary tasks as npm scripts + "typescript.tsc.autoDetect": "off" +} diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscode/tasks.json b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscode/tasks.json new file mode 100644 index 000000000..9e3300b04 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscode/tasks.json @@ -0,0 +1,37 @@ +// See https://go.microsoft.com/fwlink/?LinkId=733558 +// for the documentation about the tasks.json format +{ + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "watch", + "problemMatcher": "$ts-webpack-watch", + "isBackground": true, + "presentation": { + "reveal": "never", + "group": "watchers" + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "type": "npm", + "script": "watch-tests", + "problemMatcher": "$tsc-watch", + "isBackground": true, + "presentation": { + "reveal": "never", + "group": "watchers" + }, + "group": "build" + }, + { + "label": "tasks: watch-tests", + "dependsOn": ["npm: watch", "npm: watch-tests"], + "problemMatcher": [] + } + ] +} diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscodeignore b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscodeignore new file mode 100644 index 000000000..c6136798a --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.vscodeignore @@ -0,0 +1,13 @@ +.vscode/** +.vscode-test/** +out/** +node_modules/** +src/** +.gitignore +.yarnrc +webpack.config.js +vsc-extension-quickstart.md +**/tsconfig.json +**/.eslintrc.json +**/*.map +**/*.ts diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.yarnrc b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.yarnrc new file mode 100644 index 000000000..f757a6ac5 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/.yarnrc @@ -0,0 +1 @@ +--ignore-engines true \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/CHANGELOG.md b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/CHANGELOG.md new file mode 100644 index 000000000..c8a5139de --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/CHANGELOG.md @@ -0,0 +1,34 @@ +# Change Log + +All notable changes to the "grafana-vscode" extension will be documented in this file. + +## v0.0.16 +- Add additional proxy endpoints (to support more dashboards/etc) (#80) + +## v0.0.15 +- Follow redirects and don't fail on trailing slashes (#77) +- Theming (light/dark) support for Grafana (#74) + +## v0.0.14 +- Improved readme (#62) + +## v0.0.13 +- Add telemetry that will allow us to evaluate usefulness of this extension (#48) + +## v0.0.12 +- Removed Kiosk mode - this was preventing the 'add panel' option from showing (#59) + +## v0.0.11 +- Fixed usage on Windows (#57) + +## v0.0.10 +- Readme tweaks (#54) + +## v0.0.9 +- Added support for vscodium (#53) + +## v0.0.8 +- Improved readme (#52) + +## v0.0.7 +- First release to VSCode Marketplace diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/CODEOWNERS b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/CODEOWNERS new file mode 100644 index 000000000..d2c7fd858 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/CODEOWNERS @@ -0,0 +1,7 @@ +# Docs on CODEOWNERS: +# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners +# +# Later codeowner matches take precedence over earlier ones. + +# Default owner +* @grafana/platform-cat diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/LICENSE b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/LICENSE new file mode 100644 index 000000000..373dde574 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2015 Grafana Labs + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/README.md b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/README.md new file mode 100644 index 000000000..3937cb2a0 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/README.md @@ -0,0 +1,78 @@ +# VS Code Extension for Grafana + +Grafana has an extensive UI for editing its dashboards. For many, this is sufficient for their needs. If this is you, this extension is not for you. + +However, some wish to use software development tools (e.g. git) to manage their dashboards and other observability resources. Dashboards can be exported as JSON, however this JSON is hard to understand and interpret. This extension allows you to: +- Open a Grafana dashboard JSON file +- Start a live preview of that dashboard inside VS Code, connected to live data from a Grafana instance of your choice +- Edit the dashboard in the preview, using the normal Grafana dashboard editor UI +- From the editor UI, save the updated dashboard back to the original JSON file + +Managing dashboards as code moves the single source of truth from Grafana itself to your version control system, which allows for dashboards to participate in gitops style workflows that are commonly used for much of the rest of software development. + +> **This library is experimental** +> +> The code in this repository should be considered experimental. Documentation is only +> available alongside the code. It comes without support, but we are keen to receive +> feedback on the product and suggestions on how to improve it, though we cannot commit to +> resolution of any particular issue. No SLAs are available. It is not meant to be used in +> production environments, and the risks are unknown/high. +> +> Additional information can be found in [Release life cycle for Grafana Labs](https://grafana.com/docs/release-life-cycle/). + +## Why Work With Dashboards as Code? + +- JSON dashboards can be stored in your version control system. This provides a simple solution for rollback, history, auditing, and even change control. +- If you have change-control policies for your Grafana stack, this extension allows you and other developers to test and verify dashboard changes before deploying them +- Dashboards can be generated with tools like [Grafonnet](https://grafana.github.io/grafonnet/index.html) +- Dashboards can be integrated into your IaC practices using [Terraform, Ansible, Grafana Operator, or Grizzly](https://grafana.com/blog/2022/12/06/a-complete-guide-to-managing-grafana-as-code-tools-tips-and-tricks/) + +## Features + +- Reads a dashboard JSON you have locally. +- Opens the dashboard configured in the JSON in a running Grafana instance, right inside your IDE. +- Allows you to edit the dashboard from the UI. +- Saves your changes to _your_ JSON when you hit "Save" in the preview. + +## Requirements + +- Have a dashboard JSON handy. +- Have a running instance of Grafana locally _or_ have access to a hosted Grafana instance. +- If you intend to use a dashboard across multiple Grafana instances, you will need to use datasources that have been deployed via the API, as these datasources will require consistent UIDs. + +## Usage: + +### Install from the Marketplace + +1. Select the Extensions icon (![extensions icon](./public/extensions-icon.png)) on the left bar in VSCode. +2. Enter `Grafana` into the search box. Select the option for `Grafana / Grafana Editor` and click `Install`. +3. Open the Settings tab inside the extension (CTRL+, (comma) or `cmd` + `,` on Mac) and search for `grafana`. Then select `Extensions`. + +### Configure the Extension +1. Provide the default URL for your Grafana instance in the `URL` field. If you are using a local Grafana instance, the default value is `http://localhost:3000`. +2. Create a [Service account in Grafana](https://grafana.com/docs/grafana/latest/administration/service-accounts/#create-a-service-account-in-grafana) and add a token to it. +3. In the VS Code settings, click `Set your token, securely` then paste your token into the popup. Press ENTER. + +### Using the Extension +1. Open a folder on your computer that has some dashboard JSON (if you don't have any of your own, navigate to the `dashboards` folder of [this repo](https://github.com/grafana/grafana-vs-code-extension/tree/main/dashboards)). +2. Right-click on a dashboard JSON file in the file explorer and select `Edit in Grafana`. +3. Have fun! +4. Note, clicking `save` on your dashboard will update the JSON file in your local folder. + +### Run from Repository +1. If using local Grafana, start Grafana locally or via Docker. +2. Run `yarn install` in this repo. +3. Open this repo VS Code, then press `F5` to start the extension locally. +4. Continue from step 4 above. + +### Develop +To make changes to this codebase, follow the instructions about how to run from this repository. Then, in your original VS Code window, make changes to the extension. Then, restart the extension with either CTRL+SHIFT+F5 (CMD+SHIFT+F5 on a Mac) or by clicking the green restart circle. + +To view debug logs, use CTRL+SHIFT+P (CMD+SHIFT+P on Mac) then select "Developer: Open Webview Developer Tools". + +## Extension Settings +- `grafana-vscode.URL`: Set the URL of the Grafana instance you want to open the dashboard in. Defaults to 'http://localhost:3000'. +- `grafana-vscode.service-account-token`: A Service Account token. This is stored in the operating system secret store. Defaults to an empty string. + +## Extension communication with Grafana +Details of how this extension communicates with Grafana is available [here](https://github.com/grafana/grafana-vs-code-extension/blob/main/how-it-works.md). diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/dashboards/streaming.grafana b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/dashboards/streaming.grafana new file mode 100644 index 000000000..20d0d69fe --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/dashboards/streaming.grafana @@ -0,0 +1,703 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 4194, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "channel": "plugin/testdata/random-20Hz-stream", + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "queryType": "measurements", + "refId": "A" + } + ], + "title": "Streaming", + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "description": "Should be smaller given the longer value", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 15, + "options": { + "barRadius": 0, + "barWidth": 1, + "fullHighlight": false, + "groupWidth": 0.82, + "legend": { + "calcs": [ + "max" + ], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "csvContent": "Name,Stat1,Stat2\nStockholm, 10, 15\nNew York, 19, 5\nLondon, 10, 1\nNegative, 15, -5\nLong value, 15,10", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Auto sizing & auto show values", + "type": "barchart" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 0, + "y": 10 + }, + "id": 16, + "options": { + "barRadius": 0, + "barWidth": 1, + "fullHighlight": false, + "groupWidth": 0.89, + "legend": { + "calcs": [ + "max" + ], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "csvContent": "Name,Stat1,Stat2,Stat3,Stat4,Stat5,Stat6,Stat7,Stat8,Stat9,Stat10\nA, 10, 15,8,3,4,12,14,1,5,10\nB, 19, 5,8,3,4,12,14,6,7,2\nC, 15, 5,8,3,4,10,4,6,7,2\n", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "auto show values & No room for value", + "type": "barchart" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 8, + "y": 10 + }, + "id": 17, + "options": { + "barRadius": 0, + "barWidth": 1, + "fullHighlight": false, + "groupWidth": 0.89, + "legend": { + "calcs": [ + "max" + ], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "orientation": "auto", + "showValue": "always", + "stacking": "none", + "text": { + "valueSize": 100 + }, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "csvContent": "Name,Stat1,Stat2,Stat3,Stat4,Stat5,Stat6,Stat7,Stat8,Stat9,Stat10\nA, 10, 15,8,3,4,12,14,1,5,10\nB, 19, 5,8,3,4,12,14,6,7,2\nC, 15, 5,8,3,4,10,4,6,7,2\n", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "auto show values & Always show value", + "type": "barchart" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 10 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 9, + "refId": "A" + } + ], + "title": "Fixed value sizing", + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 7, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 21 + }, + "id": 18, + "options": { + "barRadius": 0, + "barWidth": 1, + "fullHighlight": false, + "groupWidth": 0.82, + "legend": { + "calcs": [ + "max" + ], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "orientation": "horizontal", + "showValue": "auto", + "stacking": "none", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "csvContent": "Name,Stat1,Stat2\nStockholm, 10, 15\nNew York, 19, -5\nLondon, 10, 1\nLong value, 15,10", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Auto sizing & auto show values", + "type": "barchart" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 12, + "x": 12, + "y": 21 + }, + "id": 19, + "options": { + "barRadius": 0, + "barWidth": 1, + "fullHighlight": false, + "groupWidth": 0.89, + "legend": { + "calcs": [ + "max" + ], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "orientation": "horizontal", + "showValue": "auto", + "stacking": "none", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "csvContent": "Name,Stat1,Stat2,Stat3,Stat4,Stat5,Stat6,Stat7,Stat8,Stat9,Stat10\nA, 10, 15,8,3,4,12,14,1,5,10\nB, 19, 5,8,3,4,12,14,6,7,2\nC, 15, 5,8,3,4,10,4,6,7,2\n", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "auto show values & little room", + "type": "barchart" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": [ + "gdev", + "panel-tests", + "barchart" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "BarChart - Panel Tests - Value sizing Copy", + "uid": "wziLqrvnz", + "version": 5, + "weekStart": "" +} \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/dashboards/streaming.json b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/dashboards/streaming.json new file mode 100644 index 000000000..20d0d69fe --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/dashboards/streaming.json @@ -0,0 +1,703 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 4194, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "channel": "plugin/testdata/random-20Hz-stream", + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "queryType": "measurements", + "refId": "A" + } + ], + "title": "Streaming", + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "description": "Should be smaller given the longer value", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 15, + "options": { + "barRadius": 0, + "barWidth": 1, + "fullHighlight": false, + "groupWidth": 0.82, + "legend": { + "calcs": [ + "max" + ], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "csvContent": "Name,Stat1,Stat2\nStockholm, 10, 15\nNew York, 19, 5\nLondon, 10, 1\nNegative, 15, -5\nLong value, 15,10", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Auto sizing & auto show values", + "type": "barchart" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 0, + "y": 10 + }, + "id": 16, + "options": { + "barRadius": 0, + "barWidth": 1, + "fullHighlight": false, + "groupWidth": 0.89, + "legend": { + "calcs": [ + "max" + ], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "csvContent": "Name,Stat1,Stat2,Stat3,Stat4,Stat5,Stat6,Stat7,Stat8,Stat9,Stat10\nA, 10, 15,8,3,4,12,14,1,5,10\nB, 19, 5,8,3,4,12,14,6,7,2\nC, 15, 5,8,3,4,10,4,6,7,2\n", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "auto show values & No room for value", + "type": "barchart" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 8, + "y": 10 + }, + "id": 17, + "options": { + "barRadius": 0, + "barWidth": 1, + "fullHighlight": false, + "groupWidth": 0.89, + "legend": { + "calcs": [ + "max" + ], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "orientation": "auto", + "showValue": "always", + "stacking": "none", + "text": { + "valueSize": 100 + }, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "csvContent": "Name,Stat1,Stat2,Stat3,Stat4,Stat5,Stat6,Stat7,Stat8,Stat9,Stat10\nA, 10, 15,8,3,4,12,14,1,5,10\nB, 19, 5,8,3,4,12,14,6,7,2\nC, 15, 5,8,3,4,10,4,6,7,2\n", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "auto show values & Always show value", + "type": "barchart" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 10 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 9, + "refId": "A" + } + ], + "title": "Fixed value sizing", + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 7, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 21 + }, + "id": 18, + "options": { + "barRadius": 0, + "barWidth": 1, + "fullHighlight": false, + "groupWidth": 0.82, + "legend": { + "calcs": [ + "max" + ], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "orientation": "horizontal", + "showValue": "auto", + "stacking": "none", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "csvContent": "Name,Stat1,Stat2\nStockholm, 10, 15\nNew York, 19, -5\nLondon, 10, 1\nLong value, 15,10", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Auto sizing & auto show values", + "type": "barchart" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 12, + "x": 12, + "y": 21 + }, + "id": 19, + "options": { + "barRadius": 0, + "barWidth": 1, + "fullHighlight": false, + "groupWidth": 0.89, + "legend": { + "calcs": [ + "max" + ], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "orientation": "horizontal", + "showValue": "auto", + "stacking": "none", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "csvContent": "Name,Stat1,Stat2,Stat3,Stat4,Stat5,Stat6,Stat7,Stat8,Stat9,Stat10\nA, 10, 15,8,3,4,12,14,1,5,10\nB, 19, 5,8,3,4,12,14,6,7,2\nC, 15, 5,8,3,4,10,4,6,7,2\n", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "auto show values & little room", + "type": "barchart" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": [ + "gdev", + "panel-tests", + "barchart" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "BarChart - Panel Tests - Value sizing Copy", + "uid": "wziLqrvnz", + "version": 5, + "weekStart": "" +} \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/dashboards/test-dashboard.grafana b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/dashboards/test-dashboard.grafana new file mode 100644 index 000000000..416609ee5 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/dashboards/test-dashboard.grafana @@ -0,0 +1,227 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 4278, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "channel": "plugin/testdata/random-2s-stream", + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "filter": { + "fields": [ + "Time", + "Min" + ] + }, + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Panel Title", + "type": "barchart" + }, + { + "datasource": { + "type": "grafana", + "uid": "grafana" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Panel Title", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Test dashboard", + "uid": "e9abc1a5-1b8f-4327-83e4-0b3c2b3722a9", + "version": 6, + "weekStart": "" +} \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/dashboards/test-dashboard.json b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/dashboards/test-dashboard.json new file mode 100644 index 000000000..416609ee5 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/dashboards/test-dashboard.json @@ -0,0 +1,227 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 4278, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "channel": "plugin/testdata/random-2s-stream", + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "filter": { + "fields": [ + "Time", + "Min" + ] + }, + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Panel Title", + "type": "barchart" + }, + { + "datasource": { + "type": "grafana", + "uid": "grafana" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Panel Title", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Test dashboard", + "uid": "e9abc1a5-1b8f-4327-83e4-0b3c2b3722a9", + "version": 6, + "weekStart": "" +} \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/how-it-works.md b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/how-it-works.md new file mode 100644 index 000000000..06432bd5d --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/how-it-works.md @@ -0,0 +1,24 @@ +# Extension communication with Grafana + +The below diagram explains how this extension communicates with Grafana. + +For best viewing, view this page on GitHub. + +```mermaid +sequenceDiagram + participant Webview as Webview
(inside the VS Code Extension) + participant Iframe as Iframe (Grafana)
(rendered inside the extension's webview) + participant ProxyServer as Proxy server
(running inside the extension) + participant Grafana as Grafana Instance
(running outside the extension) + participant FileSystem as File system + + Note over ProxyServer: Starts on random port + Webview->>Iframe: Render an iframe for Grafana. Callback URL to the proxy is an iframe src URL param + Iframe->>ProxyServer: Requests HTML dashboard page/etc + ProxyServer->>Grafana: Requests HTML dashboards page/etc + Iframe->>ProxyServer: Request to retrieve the JSON for opened dashboard + FileSystem->>ProxyServer: Retrieve JSON + ProxyServer-->>Iframe: JSON for opened dashboard + Iframe->>ProxyServer: Edited dashboard JSON on save + ProxyServer->>FileSystem: Edited dashboard JSON +``` diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/media/StartTV.svg b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/media/StartTV.svg new file mode 100644 index 000000000..af08a09f7 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/media/StartTV.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/package.json b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/package.json new file mode 100644 index 000000000..b8c3691e1 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/package.json @@ -0,0 +1,185 @@ +{ + "name": "grafana-vscode", + "author": "Grafana Labs", + "displayName": "lmp_Grafana", + "description": "Grafana Editor for lmp", + "icon": "public/grafana_icon.png", + "version": "0.0.16", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/grafana/grafana-vs-code-extension" + }, + "engines": { + "vscode": "^1.76.0" + }, + "publisher": "Grafana", + "categories": [ + "Visualization" + ], + "keywords": [ + "Grafana", + "dashboards" + ], + "activationEvents": [ + "onStartupFinished" + ], + "main": "./dist/extension.js", + "contributes": { + "customEditors": [ + { + "viewType": "grafana.dashboard", + "displayName": "Grafana", + "selector": [ + { + "filenamePattern": "*.grafana" + } + ] + } + ], + "commands": [ + { + "command": "grafana-vscode.openUrl", + "title": "Edit in Grafana" + } + ], + "menus": { + "commandPalette": [ + { + "command": "grafana-vscode.openUrl", + "when": "false" + } + ], + "explorer/context": [ + { + "command": "grafana-vscode.openUrl", + "when": "resourceExtname == .json" + } + ] + }, + "iconThemes": [ + { + "id": "grafana", + "label": "Grafana", + "path": "./public/icon-theme.json" + } + ], + "configuration": { + "title": "Grafana", + "properties": { + "grafana-vscode.URL": { + "type": "string", + "default": "http://localhost:3000", + "description": "Grafana instance URL", + "order": 1 + }, + "grafana-vscode.service-account-token": { + "type": "boolean", + "default": true, + "markdownDescription": "A service account token for your Grafana instance. Click the link below to add this to secure storage.\n\n[Set your token, securely](command:grafana-vscode.setPassword)", + "order": 2 + }, + "grafana-vscode.theme": { + "type": "string", + "default": "inherit", + "enum": ["inherit", "fixed", "dark", "light"], + "enumDescriptions": [ + "Inherit Grafana theme from VSCode", + "Use Grafana's own default theme", + "Use dark Grafana theme", + "Use light Grafana theme" + ] + }, + "grafana-vscode.telemetry": { + "type": "boolean", + "default": true, + "markdownDescription": "Enable basic telemetry. All data is anonymous and only used to help with feature prioritization/gloating/etc.", + "order": 3 + }, + "grafana-vscode.default_panel_path": { + "type": "string", + "default": "/home/fzy/Desktop/panels/", + "description": "the default panels search path", + "order": 4 + } + } + }, + "viewsContainers": { + "activitybar": [ + { + "id": "lmp_visualization", + "title": "lmp_visualization", + "icon": "media/StartTV.svg" + } + ] + }, + "views": { + "lmp_visualization": [ + { + "id": "lmp_visualization.panel", + "name": "Panel" + }, + { + "id": "lmp_visualization.about", + "name": "about" + } + ] + }, + "viewsWelcome": [ + { + "view": "lmp_visualization.panel", + "contents": "this is welcome content", + "when": "true" + }, + { + "view": "lmp_visualization.about", + "contents": "基于grafana与prometheus的vscode可视化插件, 隶属于智能车载OS诊断与优化专家系统", + "when": "true" + } + ] + }, + "scripts": { + "vscode:prepublish": "yarn run package", + "compile": "webpack", + "watch": "webpack --watch", + "package": "webpack --mode production --devtool hidden-source-map", + "compile-tests": "tsc -p . --outDir out", + "watch-tests": "tsc -p . -w --outDir out", + "pretest": "yarn run compile-tests && yarn run compile && yarn run lint", + "lint": "eslint src --ext ts", + "test": "node ./out/test/runTest.js" + }, + "devDependencies": { + "@types/cors": "^2.8.13", + "@types/express": "^4.17.17", + "@types/glob": "^8.1.0", + "@types/http-proxy": "^1.17.10", + "@types/mocha": "^10.0.1", + "@types/node": "16.x", + "@types/source-map-support": "^0.5.8", + "@types/vscode": "^1.76.0", + "@typescript-eslint/eslint-plugin": "^5.53.0", + "@typescript-eslint/parser": "^5.53.0", + "@vscode/test-electron": "^2.2.3", + "eslint": "^8.34.0", + "glob": "^8.1.0", + "mocha": "^10.2.0", + "prettier": "3.0.2", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "webpack": "^5.75.0", + "webpack-cli": "^5.0.1" + }, + "dependencies": { + "@types/uuid": "^9.0.6", + "axios": "^1.4.0", + "cors": "^2.8.5", + "express": "^4.18.2", + "http-proxy": "^1.18.1", + "http-proxy-middleware": "^2.0.6", + "open": "^8.4.2", + "source-map-support": "^0.5.21", + "transformer-proxy": "^0.3.5", + "uuid": "^9.0.1" + } +} diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/error.html b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/error.html new file mode 100644 index 000000000..2a6c37c1b --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/error.html @@ -0,0 +1,25 @@ + +

A problem occurred connecting to Grafana

${error} +

+ diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/extensions-icon.png b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/extensions-icon.png new file mode 100644 index 000000000..e461ccdba Binary files /dev/null and b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/extensions-icon.png differ diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/grafana_icon.png b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/grafana_icon.png new file mode 100644 index 000000000..4332a33f2 Binary files /dev/null and b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/grafana_icon.png differ diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/icon-theme.json b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/icon-theme.json new file mode 100644 index 000000000..c24a46150 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/icon-theme.json @@ -0,0 +1,10 @@ +{ + "iconDefinitions": { + "grafana": { + "iconPath": "./grafana_icon.png" + } + }, + "fileExtensions": { + "grafana": "grafana" + } +} diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/iframe.css b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/iframe.css new file mode 100644 index 000000000..23551dc65 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/iframe.css @@ -0,0 +1,31 @@ + +.sidemenu { + display: none !important; +} + +[aria-label="Share dashboard or panel"] { + display: none !important; +} + +[aria-label="Search links"] { + pointer-events: none; + cursor: default; +} + +[aria-label="Breadcrumbs"] { + pointer-events: none; + cursor: default; +} + +[aria-label="Toggle menu"] { + pointer-events: none; + cursor: default; +} + +[title="Toggle top search bar"] { + display: none !important; +} + +.main-view > div:first-of-type > div:first-of-type { + display: none !important; +} \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/webview.html b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/webview.html new file mode 100644 index 000000000..482fc12a6 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/public/webview.html @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/editor.ts b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/editor.ts new file mode 100644 index 000000000..7f0ab80ce --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/editor.ts @@ -0,0 +1,84 @@ +import * as vscode from "vscode"; +import * as fs from "fs"; +import { port } from "./server"; + +export class GrafanaEditorProvider implements vscode.CustomTextEditorProvider { + static webviewContent = ""; + static webviewErrorContent = ""; + + static readonly viewType = "grafana.dashboard"; + + public static register(context: vscode.ExtensionContext): vscode.Disposable { + const provider = new GrafanaEditorProvider(context); + const providerRegistration = vscode.window.registerCustomEditorProvider( + GrafanaEditorProvider.viewType, + provider, + { + webviewOptions: { + retainContextWhenHidden: true, + }, + }, + ); + this.webviewContent = fs.readFileSync( + context.asAbsolutePath("public/webview.html"), + "utf-8", + ); + this.webviewContent = this.webviewContent.replaceAll("${editor}", "VSCode"); + + return providerRegistration; + } + + constructor(private readonly context: vscode.ExtensionContext) {} + + /** + * Called when our custom editor is opened. + */ + public async resolveCustomTextEditor( + document: vscode.TextDocument, + webviewPanel: vscode.WebviewPanel, + _token: vscode.CancellationToken, + ) { + webviewPanel.webview.options = { + enableScripts: true, + }; + + webviewPanel.webview.html = this.getHtmlForWebview(document); + } + + private getTheme(): string { + + const settings = vscode.workspace.getConfiguration("grafana-vscode"); + const theme = settings.get("theme"); + if (theme === "dark" || theme === "light") { + return `theme=${theme}&`; + } + if (theme === "fixed") { + return ""; + } + + const kind = vscode.window.activeColorTheme.kind; + if (kind === vscode.ColorThemeKind.Light || kind === vscode.ColorThemeKind.HighContrastLight) { + return "theme=light&"; + } else { + return "theme=dark&"; + } + } + + /** + * Get the static html used for the editor webviews. + */ + private getHtmlForWebview(document: vscode.TextDocument): string { + const dash = JSON.parse(document.getText()); + const uid: string = dash.uid; + const theme = this.getTheme(); + + let view = GrafanaEditorProvider.webviewContent.replaceAll( + "${filename}", + document.uri.fsPath, + ); + view = view.replaceAll("${port}", port.toString()); + view = view.replaceAll("${uid}", uid); + view = view.replaceAll("${theme}", theme); + return view; + } +} diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/extension.ts b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/extension.ts new file mode 100644 index 000000000..388c2b339 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/extension.ts @@ -0,0 +1,393 @@ +// The module 'vscode' contains the VS Code extensibility API +// Import the module and reference it with the alias vscode in your code below +import * as vscode from "vscode"; +import { startServer, restartServer, stopServer, TOKEN_SECRET } from "./server"; +import { GrafanaEditorProvider } from "./editor"; +import { install as installSourceMapSupport } from 'source-map-support'; +import { sendTelemetry } from "./telemetry"; +import { setVersion } from "./util"; + +import * as fs from 'fs' // fzy: 为了检查面板文件是否存在 + + +let default_panel_path = "/home/fzy/Desktop/panels/" // fzy: 为了检查面板文件是否存在 + +// This method is called when your extension is activated +// Your extension is activated the very first time the command is executed +export async function activate(ctx: vscode.ExtensionContext) { + + setVersion(ctx.extension.packageJSON.version); + startServer(ctx.secrets, ctx.extensionPath); + + ctx.subscriptions.push(GrafanaEditorProvider.register(ctx)); + + ctx.subscriptions.push( + vscode.commands.registerCommand( + "grafana-vscode.openUrl", + (uri: vscode.Uri) => { + sendTelemetry(ctx); + vscode.commands.executeCommand( + "vscode.openWith", + uri, + GrafanaEditorProvider.viewType, + ); + }), + ); + // fzy + // ------------------------------------------------------------------------------------- + TreeViewProvider.initTreeViewItem(); + ctx.subscriptions.push(vscode.commands.registerCommand('itemClick', (label) => { + let file_path = default_panel_path + label + '.json'; + //console.log('file_path = ', file_path); + if (fs.existsSync(file_path)) { + let uri = vscode.Uri.file(file_path); + // 获取label + // 根据label确定uri + //console.log('uri = ', uri); + //console.log('lable = ', label); + sendTelemetry(ctx); + vscode.commands.executeCommand( + "vscode.openWith", + uri, + GrafanaEditorProvider.viewType, + ); + } + else { + let panel_search_info = label + " 可视化面板文件不存在,请检查!" + vscode.window.showErrorMessage(panel_search_info); + } + + })); + // ------------------------------------------------------------------------------------- + + vscode.workspace.onDidChangeConfiguration(async(event) => { + if (event.affectsConfiguration("grafana-vscode.URL")) { + restartServer(ctx.secrets, ctx.extensionPath); + } + // fzy, 让用户可以在设置中修改面板放置路径 + if (event.affectsConfiguration("grafana-vscode.default_panel_path")) { + const settings = vscode.workspace.getConfiguration("grafana-vscode"); + + default_panel_path = String(settings.get("default_panel_path")); + //console.log("path = ", default_panel_path); + } + + }); + + vscode.commands.registerCommand('grafana-vscode.setPassword', async () => { + const passwordInput = await vscode.window.showInputBox({ + password: true, + placeHolder: "My Grafana service account token", + title: "Enter the service account token for your Grafana instance. This value will be stored securely in your operating system's secure key store." + }) ?? ''; + await ctx.secrets.store(TOKEN_SECRET, passwordInput); + restartServer(ctx.secrets, ctx.extensionPath); + }); + + installSourceMapSupport(); +} + +// This method is called when your extension is deactivated +export function deactivate() { + stopServer(); +} + + + +// --------------------------------------------------------------------------------- +// fzy +import { CancellationToken, Event, ProviderResult, TreeDataProvider, TreeItem, TreeItemCollapsibleState, window} from "vscode"; + +// 扩展 TreeItem +/* +export class TreeItemNode extends TreeItem { + constructor( + public readonly label: string = '', + public readonly collapsibleState: TreeItemCollapsibleState, + ){ + super(label, collapsibleState); + } + + command = { + title: this.label, + command: 'itemClick', + tooltip: this.label, + arguments: [ + this.label, + ] + }; + // 获取json文件路径 + // path = TreeItemNode.getPanelUrl(this.label); + + //static getPanelUrl(label: string):Uri { + // return Uri.file(join(__filename)); + //} +} +*/ + +export class TreeViewProvider implements TreeDataProvider { + onDidChangeTreeData?: Event | undefined; + + getTreeItem(element: TreeItem): TreeItem | Thenable { + return element; + } + getChildren(element?: TreeItem | undefined): ProviderResult { + let arr: TreeItem[] = new Array(); + // treeview 根节点 + if (element == undefined) { + let item1: TreeItem = new TreeItem("CPU", TreeItemCollapsibleState.Expanded); + item1.description = "Linux CPU子系统观测工具集"; + arr.push(item1); + + let item2: TreeItem = new TreeItem("network", TreeItemCollapsibleState.Expanded); + item2.description = "Linux 网络子系统观测工具集"; + arr.push(item2); + + let item3: TreeItem = new TreeItem("memory", TreeItemCollapsibleState.Expanded); + item3.description = "Linux 内存子系统观测工具集"; + arr.push(item3); + + let item4: TreeItem = new TreeItem("system_diagnosis", TreeItemCollapsibleState.Expanded); + item4.description = "Linux 系统诊断工具集"; + arr.push(item4); + + let item5: TreeItem = new TreeItem("hypervisior", TreeItemCollapsibleState.Expanded); + item5.description = "Linux 虚拟化子系统工具集"; + arr.push(item5); + + return arr; + } + // treeview 子节点 + else { + if (element.label == 'CPU') { + // ***************************************************************************** + //let item1: TreeItem = new TreeItem("cpu_watcher", TreeItemCollapsibleState.None); + let cpu_watcher_label = "cpu_watcher"; + let item1:TreeItem = new TreeItem(cpu_watcher_label, TreeItemCollapsibleState.None); + item1.description = "cpu观测"; + let command_cpu_watcher = { + title: cpu_watcher_label, + command: 'itemClick', + tooltip: "点击将呈现net_watcher的grafana的可视化面板", + arguments: [ + cpu_watcher_label + ] + } + item1.command = command_cpu_watcher; + arr.push(item1); + // ***************************************************************************** + let proc_iamge_label = "proc_image"; + let item2: TreeItem = new TreeItem(proc_iamge_label, TreeItemCollapsibleState.None); + item2.description = "进程画像"; + let command_proc_image = { + title: proc_iamge_label, + command: 'itemClick', + tooltip: "点击将呈现net_watcher的grafana的可视化面板", + arguments: [ + proc_iamge_label + ] + } + item2.command = command_proc_image; + arr.push(item2); + // ***************************************************************************** + return arr; + } + else if (element.label == 'network') { + // ***************************************************************************** + let net_watcher_label = "net_watcher"; + let network_item1: TreeItem = new TreeItem(net_watcher_label, TreeItemCollapsibleState.None); + network_item1.description = "网络观测"; + let command_net_watcher = { + title: net_watcher_label, + command: 'itemClick', + tooltip: "点击将呈现net_watcher的grafana的可视化面板", + arguments: [ + net_watcher_label + ] + } + network_item1.command = command_net_watcher; + arr.push(network_item1); + // ***************************************************************************** + let net_manager_label = "net_manager"; + let network_item2: TreeItem = new TreeItem(net_manager_label, TreeItemCollapsibleState.None); + network_item2.description = "网络管理"; + let command_net_manager = { + title: net_manager_label, + command: 'itemClick', + tooltip: "点击将呈现net_watcher的grafana的可视化面板", + arguments: [ + net_manager_label + ] + } + network_item2.command = command_net_manager; + arr.push(network_item2); + // ***************************************************************************** + return arr; + } + else if (element.label == 'memory') { + let mem_watcher_label = "mem_watcher"; + let memory_item1: TreeItem = new TreeItem(mem_watcher_label, TreeItemCollapsibleState.None); + memory_item1.description = "内存观测"; + let command_mem_watcher = { + title: mem_watcher_label, + command: 'itemClick', + tooltip: "点击将呈现net_watcher的grafana的可视化面板", + arguments: [ + mem_watcher_label + ] + } + memory_item1.command = command_mem_watcher; + arr.push(memory_item1); + + return arr; + } + else if (element.label == 'system_diagnosis') { + let stack_analyzer_label = "stack_analyzer"; + let system_diagnosis_item1: TreeItem = new TreeItem(stack_analyzer_label, TreeItemCollapsibleState.None); + system_diagnosis_item1.description = "栈调用分析器"; + let command_stack_analyzer = { + title: stack_analyzer_label, + command: 'itemClick', + tooltip: "点击将呈现net_watcher的grafana的可视化面板", + arguments: [ + stack_analyzer_label + ] + } + system_diagnosis_item1.command = command_stack_analyzer; + arr.push(system_diagnosis_item1); + + return arr; + } + else if (element.label == 'hypervisior') { + let kvm_watcher_label = "kvm_watcher"; + let hypervisior_item1: TreeItem = new TreeItem(kvm_watcher_label, TreeItemCollapsibleState.None); + hypervisior_item1.description = "kvm虚拟化"; + let command_kvm_watcher = { + title: kvm_watcher_label, + command: 'itemClick', + tooltip: "点击将呈现net_watcher的grafana的可视化面板", + arguments: [ + kvm_watcher_label + ] + } + hypervisior_item1.command = command_kvm_watcher; + arr.push(hypervisior_item1); + + return arr; + } + else { + return null; + } + } + } + public static initTreeViewItem(){ + const treeViewProvider = new TreeViewProvider(); + window.registerTreeDataProvider('lmp_visualization.panel',treeViewProvider); + } + +} +// fzy end +// --------------------------------------------------------------------------------- + +// backup +/** + export class TreeViewProvider implements TreeDataProvider { + onDidChangeTreeData?: Event | undefined; + + getTreeItem(element: TreeItemNode): TreeItem | Thenable { + return element; + } + getChildren(element?: TreeItem | undefined): ProviderResult { + let arr: TreeItem[] = new Array(); + // treeview 根节点 + if (element == undefined) { + let item1: TreeItem = new TreeItem("CPU", TreeItemCollapsibleState.Expanded); + item1.description = "Linux CPU子系统观测工具集"; + arr.push(item1); + + let item2: TreeItem = new TreeItem("network", TreeItemCollapsibleState.Expanded); + item2.description = "Linux 网络子系统观测工具集"; + arr.push(item2); + + let item3: TreeItem = new TreeItem("memory", TreeItemCollapsibleState.Expanded); + item3.description = "Linux 内存子系统观测工具集"; + arr.push(item3); + + let item4: TreeItem = new TreeItem("system_diagnosis", TreeItemCollapsibleState.Expanded); + item4.description = "Linux 系统诊断工具集"; + arr.push(item4); + + let item5: TreeItem = new TreeItem("hypervisior", TreeItemCollapsibleState.Expanded); + item5.description = "Linux 虚拟化子系统工具集"; + arr.push(item5); + + return arr; + } + // treeview 子节点 + else { + if (element.label == 'CPU') { + //let item1: TreeItem = new TreeItem("cpu_watcher", TreeItemCollapsibleState.None); + let item1:TreeItemNode = new TreeItemNode("cpu_watcher", TreeItemCollapsibleState.None); + item1.description = "cpu观测"; + arr.push(item1); + + let item2: TreeItemNode = new TreeItemNode("proc_image", TreeItemCollapsibleState.None); + item2.description = "进程画像"; + arr.push(item2); + + return arr; + } + else if (element.label == 'network') { + let network_item1: TreeItemNode = new TreeItemNode("net_watcher", TreeItemCollapsibleState.None); + network_item1.description = "网络观测"; + + //let command = { + //title: 'net_watcher', + //command: 'itemClick', + //tooltip: "点击将呈现net_watcher的grafana的可视化面板", + //arguments: [ + //] + //} + //network_item1.command = command; + + arr.push(network_item1); + + let network_item2: TreeItemNode = new TreeItemNode("net_manager", TreeItemCollapsibleState.None); + network_item2.description = "网络管理"; + arr.push(network_item2); + + return arr; + } + else if (element.label == 'memory') { + let memory_item1: TreeItemNode = new TreeItemNode("mem_watcher", TreeItemCollapsibleState.None); + memory_item1.description = "内存观测"; + arr.push(memory_item1); + + return arr; + } + else if (element.label == 'system_diagnosis') { + let system_diagnosis_item1: TreeItemNode = new TreeItemNode("stack_analyzer", TreeItemCollapsibleState.None); + system_diagnosis_item1.description = "栈调用分析器"; + arr.push(system_diagnosis_item1); + + return arr; + } + else if (element.label == 'hypervisior') { + let hypervisior_item1: TreeItemNode = new TreeItemNode("kvm_watcher", TreeItemCollapsibleState.None); + hypervisior_item1.description = "kvm虚拟化"; + arr.push(hypervisior_item1); + + return arr; + } + else { + return null; + } + } + } + public static initTreeViewItem(){ + const treeViewProvider = new TreeViewProvider(); + window.registerTreeDataProvider('lmp_visualization.panel',treeViewProvider); + } + +} + */ \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/middleware.ts b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/middleware.ts new file mode 100644 index 000000000..43b5aa00a --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/middleware.ts @@ -0,0 +1,16 @@ +import { Response, Request, NextFunction } from "express"; + +export function detectRequestSource( + req: Request, + res: Response, + next: NextFunction, +) { + const userAgent = req.headers["user-agent"]; + + if ((userAgent?.includes("Code") || userAgent?.includes("code")) + && userAgent?.includes("Electron")) { + next(); + } else { + res.status(403).send("Access Denied"); + } +} diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/server.ts b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/server.ts new file mode 100644 index 000000000..9f618c3ee --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/server.ts @@ -0,0 +1,261 @@ +import * as express from "express"; +import { Server, createServer } from "http"; +import { createProxyServer } from "http-proxy"; +import * as fs from "fs"; +import * as vscode from "vscode"; +import * as cors from "cors"; +import { detectRequestSource } from "./middleware"; +import axios from "axios"; +import * as path from "path"; +import * as util from "./util"; + +export let port = 0; + +let server: Server; + +export const TOKEN_SECRET = "grafana-vscode.token"; + +export async function startServer(secrets: vscode.SecretStorage, extensionPath: string) { + const settings = vscode.workspace.getConfiguration("grafana-vscode"); + const token = await secrets.get(TOKEN_SECRET); + let URL = String(settings.get("URL")); + if (URL.slice(-1) === "/") { + URL = URL.slice(0, -1); + } + + const corsOptions = { + origin: `http://localhost:${port}`, + optionsSuccessStatus: 200, + }; + + const app = express(); + app.use(detectRequestSource); + server = createServer(app); + + const proxy = createProxyServer({ + target: URL, + changeOrigin: !URL.includes("localhost"), + ws: true, + headers: { + // eslint-disable-next-line @typescript-eslint/naming-convention + Authorization: `Bearer ${token}`, + // eslint-disable-next-line @typescript-eslint/naming-convention + 'User-Agent': util.getUserAgent(), + }, + }); + + server.on("upgrade", function (req, socket, head) { + proxy.ws(req, socket, head, {}); + }); + + const sendErrorPage = (res: express.Response, message: string) => { + const errorFile = path.join(extensionPath, "public/error.html"); + let content = fs.readFileSync(errorFile, "utf-8"); + content = content.replaceAll("${error}", message); + res.write(content); + }; + + /* + * Note, this method avoids using `proxy.web`, implementing its own proxy + * event using Axios. This is because Grafana returns `X-Frame-Options: deny` + * which breaks our ability to place Grafana inside an iframe. `http-proxy` + * will not remove that header once it is added. Therefore we need a different + * form of proxy. + * + * This security protection does not apply to this situation - given we own + * both the connection to the backend as well as the webview. Therefore + * it is reasonable remove this header in this context. + * + * This method also doubles as connection verification. If an issue is + * encountered connecting to Grafana, rather than reporting an HTTP error, + * it returns an alternate HTML page to the user explaining the error, and + * offering a "refresh" option. + */ + app.get("/d/:uid/:slug", async function (req, res) { + try { + const resp = await axios.get(URL + req.url, { + maxRedirects: 5, + headers: { + // eslint-disable-next-line @typescript-eslint/naming-convention + Authorization: `Bearer ${token}`, + // eslint-disable-next-line @typescript-eslint/naming-convention + 'User-Agent': util.getUserAgent(), + }, + }); + res.write(resp.data); + } catch (e) { + let msg = ""; + if (URL === "") { + msg += "

Error: URL is not defined

"; + } + if (token === "") { + msg += "

Warning: No service account token specified.

"; + } + if (axios.isAxiosError(e)) { + if (e.response?.status === 302) { + sendErrorPage(res, msg+ "

Authentication error

"); + } else { + sendErrorPage(res, msg + `

${e.message}

`); + } + } else if (e instanceof Error) { + sendErrorPage(res, msg + `

${e.message}

`); + } else { + sendErrorPage(res, msg + "

" + String(e) + "

"); + } + } + }); + + app.get( + "/api/dashboards/uid/:uid", + express.json(), + cors(corsOptions), + (req, res) => { + const refererParams = new URLSearchParams(req.headers.referer); + const filename = refererParams.get("filename"); + if (filename === null) { + console.log("Filename not specified in referer"); + res.sendStatus(500); + return; + } + fs.readFile(filename, "utf-8", (err, data) => { + if (err) { + console.error("Error reading file:", err); + res.sendStatus(500); + return; + } + const dash: any = JSON.parse(data); + const wrapper = { + dashboard: dash, + meta: { + isStarred: false, + folderId: 0, + folderUid: "", + url: `/d/${dash.uid}/slug`, + }, + }; + + res.send(wrapper); + }); + }, + ); + + app.post( + "/api/dashboards/db/", + express.json(), + cors(corsOptions), + (req, res) => { + const refererParams = new URLSearchParams(req.headers.referer); + const filename = refererParams.get("filename"); + if (!filename) { + res.send(500); + return; + } + const uid = req.headers.referer?.split("/")[4]; + const jsonData = JSON.stringify(req.body.dashboard, null, 2); + + fs.writeFile(filename, jsonData, "utf-8", (err) => { + if (err) { + console.error("Error writing file:", err); + res.sendStatus(500); + } else { + res.send({ + id: 1, + slug: "slug", + status: "success", + uid: uid, + url: `/d/${uid}/slug`, + version: 1, + }); + } + }); + }, + ); + + app.get( + "/api/access-control/user/actions", + express.json(), + cors(corsOptions), + (req, res) => { + res.send({ + /* eslint-disable-next-line @typescript-eslint/naming-convention */ + "dashboards:write": true, + }); + return; + }, + ); + + const mustProxyGET = [ + "/public/*", + "/api/datasources/proxy/*", + "/api/datasources/*", + "/api/plugins/*", + ]; + for (const path of mustProxyGET) { + app.get(path, function (req, res) { + proxy.web(req, res, {}); + }); + } + + const mustProxyPOST = [ + "/api/ds/query", + "/api/datasources/proxy/*", + ]; + for (const path of mustProxyPOST) { + app.post(path, function (req, res) { + proxy.web(req, res, {}); + }); + } + + const blockJSONget: { [name: string]: any } = { + /* eslint-disable @typescript-eslint/naming-convention */ + "/api/ma/events": [], + "/api/live/publish": [], + "/api/live/list": [], + "/api/user/orgs": [], + "/api/annotations": [], + "/api/search": [], + "/api/usage/*": [], + "/api/prometheus/grafana/api/v1/rules": { + status: "success", + data: { groups: [] }, + }, + "/avatar/*": "", + "/api/folders": [], + /* eslint-enable @typescript-eslint/naming-convention */ + }; + for (const path in blockJSONget) { + app.get(path, function (req, res) { + res.send(blockJSONget[path]); + }); + } + + const blockJSONpost: { [name: string]: any } = { + /* eslint-disable @typescript-eslint/naming-convention */ + "/api/frontend-metrics": [], + "/api/search-v2": [], + "/api/live/publish": {}, + /* eslint-enable @typescript-eslint/naming-convention */ + }; + for (const path in blockJSONpost) { + app.post(path, function (req, res) { + res.send(blockJSONpost[path]); + }); + } + + server.listen(port, () => { + //@ts-expect-error + port = server?.address()?.port; + console.log("Server started"); + }); +} + +export function restartServer(secrets: vscode.SecretStorage, extensionPath: string) { + console.log("Restarting server"); + stopServer(); + startServer(secrets, extensionPath); +} +export function stopServer() { + if (server) { + server.close(); + } +} diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/telemetry.ts b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/telemetry.ts new file mode 100644 index 000000000..b6bcc7854 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/telemetry.ts @@ -0,0 +1,88 @@ +import * as vscode from "vscode"; +import axios from "axios"; +import {v4 as uuidv4} from 'uuid'; +import * as util from "./util"; + +const LAST_UPDATED_DATE = "lastUpdatedDate"; +const INSTALLATION_DATE = "installDate"; +const INSTALLATION_UUID = "installUUID"; +const RECENT_VIEWS = "recentViews"; + +const URL = "https://stats.grafana.org/vscode-usage-report"; + +/* + * Sends a single anonymous telemetry call once per day, allowing tracking of + * usage - reports on first opening of a dashboard each day. + */ +export async function sendTelemetry(ctx: vscode.ExtensionContext) { + + const settings = vscode.workspace.getConfiguration("grafana-vscode"); + const enableTelemetry = settings.get("telemetry"); + if (!enableTelemetry) { + return; + } + const lastUpdatedDate = ctx.globalState.get(LAST_UPDATED_DATE); + const today = new Date(); + + if (lastUpdatedDate === undefined) { + const uuid = uuidv4(); + await sendEvent("first", uuid, today.toISOString(), 1); + ctx.globalState.update(LAST_UPDATED_DATE, today); + ctx.globalState.update(INSTALLATION_UUID, uuid); + ctx.globalState.update(INSTALLATION_DATE, today); + ctx.globalState.update(RECENT_VIEWS, 0); + } else { + let recentViews = ctx.globalState.get(RECENT_VIEWS); + recentViews = (recentViews === undefined) ? 1 : recentViews+1; + + if (differentDay(new Date(lastUpdatedDate), today)) { + let uuid = ctx.globalState.get(INSTALLATION_UUID); + let installDate = ctx.globalState.get(INSTALLATION_DATE); + if (uuid === undefined) { + console.log("UUID undefined. Shouldn't happen."); + uuid = uuidv4(); + ctx.globalState.update(INSTALLATION_UUID, uuid); + } + if (installDate === undefined) { + console.log("Install date undefined. Shouldn't happen."); + installDate = (new Date(lastUpdatedDate)).toISOString(); + ctx.globalState.update(INSTALLATION_DATE, installDate); + } + await sendEvent("subsequent", uuid as string, installDate as string, recentViews); + ctx.globalState.update(LAST_UPDATED_DATE, today); + recentViews = 0; + } + ctx.globalState.update(RECENT_VIEWS, recentViews); + } +} + +function differentDay(d1: Date, d2: Date) { + return d1.getDate() !== d2.getDate() || + d1.getMonth() !== d2.getMonth() || + d1.getFullYear() !== d2.getFullYear(); +} + +async function sendEvent(eventType: string, uuid: string, installDate: string, views: number | undefined) { + try { + const data = { + uuid: uuid, + eventType: eventType, + timestamp: Date(), + createdAt: installDate, + os: process.platform, + arch: process.arch, + packaging: "unknown", + views: views, + version: util.getVersion(), + }; + + await axios.post(URL, data, { + headers: { + // eslint-disable-next-line @typescript-eslint/naming-convention + 'User-Agent': util.getUserAgent(), + }, + }); + } catch(e) { + console.log("Telemetry error", e, "for event", eventType); + } +} \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/test/runTest.ts b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/test/runTest.ts new file mode 100644 index 000000000..8a6ab0e15 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/test/runTest.ts @@ -0,0 +1,23 @@ +import * as path from "path"; + +import { runTests } from "@vscode/test-electron"; + +async function main() { + try { + // The folder containing the Extension Manifest package.json + // Passed to `--extensionDevelopmentPath` + const extensionDevelopmentPath = path.resolve(__dirname, "../../"); + + // The path to test runner + // Passed to --extensionTestsPath + const extensionTestsPath = path.resolve(__dirname, "./suite/index"); + + // Download VS Code, unzip it and run the integration test + await runTests({ extensionDevelopmentPath, extensionTestsPath }); + } catch (err) { + console.error("Failed to run tests", err); + process.exit(1); + } +} + +main(); diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/test/suite/extension.test.ts b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/test/suite/extension.test.ts new file mode 100644 index 000000000..2f671d3c7 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/test/suite/extension.test.ts @@ -0,0 +1,15 @@ +import * as assert from "assert"; + +// You can import and use all API from the 'vscode' module +// as well as import your extension to test it +import * as vscode from "vscode"; +// import * as myExtension from '../../extension'; + +suite("Extension Test Suite", () => { + vscode.window.showInformationMessage("Start all tests."); + + test("Sample test", () => { + assert.strictEqual(-1, [1, 2, 3].indexOf(5)); + assert.strictEqual(-1, [1, 2, 3].indexOf(0)); + }); +}); diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/test/suite/index.ts b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/test/suite/index.ts new file mode 100644 index 000000000..2cb7d7d8b --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/test/suite/index.ts @@ -0,0 +1,38 @@ +import * as path from "path"; +import * as Mocha from "mocha"; +import * as glob from "glob"; + +export function run(): Promise { + // Create the mocha test + const mocha = new Mocha({ + ui: "tdd", + color: true, + }); + + const testsRoot = path.resolve(__dirname, ".."); + + return new Promise((c, e) => { + glob("**/**.test.js", { cwd: testsRoot }, (err, files) => { + if (err) { + return e(err); + } + + // Add files to the test suite + files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); + + try { + // Run the mocha test + mocha.run((failures) => { + if (failures > 0) { + e(new Error(`${failures} tests failed.`)); + } else { + c(); + } + }); + } catch (err) { + console.error(err); + e(err); + } + }); + }); +} diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/util.ts b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/util.ts new file mode 100644 index 000000000..55ef02df8 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/util.ts @@ -0,0 +1,15 @@ +let userAgent: string; +let version: string; + +export function setVersion(v: string) { + version = v; + userAgent = `Grafana VSCode Extension/v${version}`; +} + +export function getVersion(): string { + return version; +} + +export function getUserAgent(): string { + return userAgent; +} \ No newline at end of file diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/tsconfig.json b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/tsconfig.json new file mode 100644 index 000000000..708b31212 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "ES2021", + "lib": ["ES2021"], + "sourceMap": true, + "rootDir": "src", + "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. */ + } +} diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/webpack.config.js b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/webpack.config.js new file mode 100644 index 000000000..e6ed48c6e --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/webpack.config.js @@ -0,0 +1,48 @@ +//@ts-check + +"use strict"; + +const path = require("path"); + +//@ts-check +/** @typedef {import('webpack').Configuration} WebpackConfig **/ + +/** @type WebpackConfig */ +const extensionConfig = { + target: "node", // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ + mode: "none", // this leaves the source code as close as possible to the original (when packaging we set this to 'production') + + entry: "./src/extension.ts", // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ + output: { + // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ + path: path.resolve(__dirname, "dist"), + filename: "extension.js", + libraryTarget: "commonjs2", + }, + externals: { + vscode: "commonjs vscode", // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ + // modules added here also need to be added in the .vscodeignore file + }, + resolve: { + // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader + extensions: [".ts", ".js"], + }, + module: { + rules: [ + { + test: /\.ts$/, + exclude: /node_modules/, + use: [ + { + loader: "ts-loader", + }, + ], + }, + ], + }, + devtool: "nosources-source-map", + infrastructureLogging: { + level: "log", // enables logging required for problem matchers + }, +}; +module.exports = [extensionConfig]; diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/yarn.lock b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/yarn.lock new file mode 100644 index 000000000..e3f584062 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/yarn.lock @@ -0,0 +1,2707 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + +"@eslint/eslintrc@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" + integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.52.0.tgz#78fe5f117840f69dc4a353adf9b9cd926353378c" + integrity sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA== + +"@humanwhocodes/config-array@^0.11.13": + version "0.11.13" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" + integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== + dependencies: + "@humanwhocodes/object-schema" "^2.0.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" + integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== + +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.3": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" + integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.20" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@types/body-parser@*": + version "1.19.4" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.4.tgz#78ad68f1f79eb851aa3634db0c7f57f6f601b462" + integrity sha512-N7UDG0/xiPQa2D/XrVJXjkWbpqHCd2sBaB32ggRF2l83RhPfamgKGF8gwwqyksS95qUS5ZYF9aF+lLPRlwI2UA== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.37" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.37.tgz#c66a96689fd3127c8772eb3e9e5c6028ec1a9af5" + integrity sha512-zBUSRqkfZ59OcwXon4HVxhx5oWCJmc0OtBTK05M+p0dYjgN6iTwIL2T/WbsQZrEsdnwaF9cWQ+azOnpPvIqY3Q== + dependencies: + "@types/node" "*" + +"@types/cors@^2.8.13": + version "2.8.15" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.15.tgz#eb143aa2f8807ddd78e83cbff141bbedd91b60ee" + integrity sha512-n91JxbNLD8eQIuXDIChAN1tCKNWCEgpceU9b7ZMbFA+P+Q4yIeh80jizFLEvolRPc1ES0VdwFlGv+kJTSirogw== + dependencies: + "@types/node" "*" + +"@types/eslint-scope@^3.7.3": + version "3.7.6" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.6.tgz#585578b368ed170e67de8aae7b93f54a1b2fdc26" + integrity sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.44.6" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.6.tgz#60e564551966dd255f4c01c459f0b4fb87068603" + integrity sha512-P6bY56TVmX8y9J87jHNgQh43h6VVU+6H7oN7hgvivV81K2XY8qJZ5vqPy/HdUoVIelii2kChYVzQanlswPWVFw== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.4.tgz#d9748f5742171b26218516cf1828b8eafaf8a9fa" + integrity sha512-2JwWnHK9H+wUZNorf2Zr6ves96WHoWDJIftkcxPKsS7Djta6Zu519LarhRNljPXkpsZR2ZMwNCPeW7omW07BJw== + +"@types/express-serve-static-core@^4.17.33": + version "4.17.39" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.39.tgz#2107afc0a4b035e6cb00accac3bdf2d76ae408c8" + integrity sha512-BiEUfAiGCOllomsRAZOiMFP7LAnrifHpt56pc4Z7l9K6ACyN06Ns1JLMBxwkfLOjJRlSf06NwWsT7yzfpaVpyQ== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@^4.17.17": + version "4.17.20" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.20.tgz#e7c9b40276d29e38a4e3564d7a3d65911e2aa433" + integrity sha512-rOaqlkgEvOW495xErXMsmyX3WKBInbhG5eqojXYi3cGUaLoRDlXa5d52fkfWZT963AZ3v2eZ4MbKE6WpDAGVsw== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/glob@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-8.1.0.tgz#b63e70155391b0584dce44e7ea25190bbc38f2fc" + integrity sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w== + dependencies: + "@types/minimatch" "^5.1.2" + "@types/node" "*" + +"@types/http-errors@*": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.3.tgz#c54e61f79b3947d040f150abd58f71efb422ff62" + integrity sha512-pP0P/9BnCj1OVvQR2lF41EkDG/lWWnDyA203b/4Fmi2eTyORnBtcDoKDwjWQthELrBvWkMOrvSOnZ8OVlW6tXA== + +"@types/http-proxy@^1.17.10", "@types/http-proxy@^1.17.8": + version "1.17.13" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.13.tgz#dd3a4da550580eb0557d4c7128a2ff1d1a38d465" + integrity sha512-GkhdWcMNiR5QSQRYnJ+/oXzu0+7JJEPC8vkWXK351BkhjraZF+1W13CUYARUvX9+NqIU2n6YHA4iwywsc/M6Sw== + dependencies: + "@types/node" "*" + +"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.14" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.14.tgz#74a97a5573980802f32c8e47b663530ab3b6b7d1" + integrity sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw== + +"@types/mime@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.3.tgz#886674659ce55fe7c6c06ec5ca7c0eb276a08f91" + integrity sha512-i8MBln35l856k5iOhKk2XJ4SeAWg75mLIpZB4v6imOagKL6twsukBZGDMNhdOVk7yRFTMPpfILocMos59Q1otQ== + +"@types/mime@^1": + version "1.3.4" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.4.tgz#a4ed836e069491414bab92c31fdea9e557aca0d9" + integrity sha512-1Gjee59G25MrQGk8bsNvC6fxNiRgUlGn2wlhGf95a59DrprnnHk80FIMMFG9XHMdrfsuA119ht06QPDXA1Z7tw== + +"@types/minimatch@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== + +"@types/mocha@^10.0.1": + version "10.0.3" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.3.tgz#4804fe9cd39da26eb62fa65c15ea77615a187812" + integrity sha512-RsOPImTriV/OE4A9qKjMtk2MnXiuLLbcO3nCXK+kvq4nr0iMfFgpjaX3MPLb6f7+EL1FGSelYvuJMV6REH+ZPQ== + +"@types/node@*": + version "20.8.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.10.tgz#a5448b895c753ae929c26ce85cab557c6d4a365e" + integrity sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w== + dependencies: + undici-types "~5.26.4" + +"@types/node@16.x": + version "16.18.60" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.60.tgz#0b0f4316906f1bd0e03b640363f67bd4e86958bd" + integrity sha512-ZUGPWx5vKfN+G2/yN7pcSNLkIkXEvlwNaJEd4e0ppX7W2S8XAkdc/37hM4OUNJB9sa0p12AOvGvxL4JCPiz9DA== + +"@types/qs@*": + version "6.9.9" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.9.tgz#66f7b26288f6799d279edf13da7ccd40d2fa9197" + integrity sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg== + +"@types/range-parser@*": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.6.tgz#7cb33992049fd7340d5b10c0098e104184dfcd2a" + integrity sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA== + +"@types/semver@^7.3.12": + version "7.5.4" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.4.tgz#0a41252ad431c473158b22f9bfb9a63df7541cff" + integrity sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ== + +"@types/send@*": + version "0.17.3" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.3.tgz#81b2ea5a3a18aad357405af2d643ccbe5a09020b" + integrity sha512-/7fKxvKUoETxjFUsuFlPB9YndePpxxRAOfGC/yJdc9kTjTeP5kRCTzfnE8kPUKCeyiyIZu0YQ76s50hCedI1ug== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-static@*": + version "1.15.4" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.4.tgz#44b5895a68ca637f06c229119e1c774ca88f81b2" + integrity sha512-aqqNfs1XTF0HDrFdlY//+SGUxmdSUbjeRXb5iaZc3x0/vMbYmdw9qvOgHWOyyLFxSSRnUuP5+724zBgfw8/WAw== + dependencies: + "@types/http-errors" "*" + "@types/mime" "*" + "@types/node" "*" + +"@types/source-map-support@^0.5.8": + version "0.5.9" + resolved "https://registry.yarnpkg.com/@types/source-map-support/-/source-map-support-0.5.9.tgz#750860ba0dc3eb2929a940ac630e6ef60407f6b6" + integrity sha512-91Jf4LyPAObBTFbpW3bSDK1ncdwXohvlBmzffSj7/44SY+1mD/HhesdfspCMxPIJwllgN2G4eVFatGs4Zw/lnw== + dependencies: + source-map "^0.6.0" + +"@types/uuid@^9.0.6": + version "9.0.6" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.6.tgz#c91ae743d8344a54b2b0c691195f5ff5265f6dfb" + integrity sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew== + +"@types/vscode@^1.76.0": + version "1.83.1" + resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.83.1.tgz#fe51b3d913a5c5b265a622179ae4ab6c0af7d54e" + integrity sha512-BHu51NaNKOtDf3BOonY3sKFFmZKEpRkzqkZVpSYxowLbs5JqjOQemYFob7Gs5rpxE5tiGhfpnMpcdF/oKrLg4w== + +"@typescript-eslint/eslint-plugin@^5.53.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db" + integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag== + dependencies: + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/type-utils" "5.62.0" + "@typescript-eslint/utils" "5.62.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.53.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7" + integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA== + dependencies: + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/typescript-estree" "5.62.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" + integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== + dependencies: + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" + +"@typescript-eslint/type-utils@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a" + integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew== + dependencies: + "@typescript-eslint/typescript-estree" "5.62.0" + "@typescript-eslint/utils" "5.62.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" + integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== + +"@typescript-eslint/typescript-estree@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" + integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== + dependencies: + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" + integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/typescript-estree" "5.62.0" + eslint-scope "^5.1.1" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" + integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== + dependencies: + "@typescript-eslint/types" "5.62.0" + eslint-visitor-keys "^3.3.0" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +"@vscode/test-electron@^2.2.3": + version "2.3.6" + resolved "https://registry.yarnpkg.com/@vscode/test-electron/-/test-electron-2.3.6.tgz#61a6ec1b4bdc9a2a694a9d7d86b9cb8b82c5a116" + integrity sha512-M31xGH0RgqNU6CZ4/9g39oUMJ99nLzfjA+4UbtIQ6TcXQ6+2qkjOOxedmPBDDCg26/3Al5ubjY80hIoaMwKYSw== + dependencies: + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + jszip "^3.10.1" + semver "^7.5.2" + +"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" + integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== + +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== + +"@webassemblyjs/helper-buffer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" + integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== + +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== + +"@webassemblyjs/helper-wasm-section@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" + integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" + integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-opt" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + "@webassemblyjs/wast-printer" "1.11.6" + +"@webassemblyjs/wasm-gen@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" + integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" + integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + +"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" + integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" + integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" + integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== + +"@webpack-cli/info@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" + integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== + +"@webpack-cli/serve@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" + integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-import-assertions@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" + integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0: + version "8.11.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" + integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^1.4.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102" + integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +body-parser@1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserslist@^4.14.5: + version "4.22.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619" + integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ== + dependencies: + caniuse-lite "^1.0.30001541" + electron-to-chromium "^1.4.535" + node-releases "^2.0.13" + update-browserslist-db "^1.0.13" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001541: + version "1.0.30001559" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001559.tgz#95a982440d3d314c471db68d02664fb7536c5a30" + integrity sha512-cPiMKZgqgkg5LY3/ntGeLFUpi6tzddBNS58A4tnTgQw1zON7u2sZMU7SzOeVH4tj20++9ggL+V6FDOFMTaFFYA== + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.14: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4, debug@4.3.4, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.535: + version "1.4.572" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.572.tgz#ed9876658998138fe9e3aa47ecfa0bf914192a86" + integrity sha512-RlFobl4D3ieetbnR+2EpxdzFl9h0RAJkPK3pfiwMug2nhBin2ZCsGIAJWdpNniLz43sgXam/CgipOmvTA+rUiA== + +emitter-component@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/emitter-component/-/emitter-component-1.1.1.tgz#065e2dbed6959bf470679edabeaf7981d1003ab6" + integrity sha512-G+mpdiAySMuB7kesVRLuyvYRqDmshB7ReKEVuyBPkzQlmiDiLrt7hHHIy4Aff552bgknVN7B2/d3lzhGO5dvpQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +enhanced-resolve@^5.0.0, enhanced-resolve@^5.15.0: + version "5.15.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" + integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +envinfo@^7.7.3: + version "7.11.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.11.0.tgz#c3793f44284a55ff8c82faf1ffd91bc6478ea01f" + integrity sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg== + +es-module-lexer@^1.2.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.1.tgz#c1b0dd5ada807a3b3155315911f364dc4e909db1" + integrity sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@5.1.1, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.34.0: + version "8.52.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.52.0.tgz#d0cd4a1fac06427a61ef9242b9353f36ea7062fc" + integrity sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.2" + "@eslint/js" "8.52.0" + "@humanwhocodes/config-array" "^0.11.13" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +express@^4.18.2: + version "4.18.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" + integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.5.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-up@5.0.0, find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.1.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.1.tgz#a02a15fdec25a8f844ff7cc658f03dd99eb4609b" + integrity sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^3.2.9: + version "3.2.9" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" + integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== + +follow-redirects@^1.0.0, follow-redirects@^1.15.0: + version "1.15.5" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020" + integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== + dependencies: + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + 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" + +glob@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +globals@^13.19.0: + version "13.23.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.23.0.tgz#ef31673c926a0976e1f61dab4dca57e0c0a8af02" + integrity sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== + dependencies: + get-intrinsic "^1.2.2" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +http-proxy-middleware@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f" + integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw== + dependencies: + "@types/http-proxy" "^1.17.8" + http-proxy "^1.18.1" + is-glob "^4.0.1" + is-plain-obj "^3.0.0" + micromatch "^4.0.2" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" + integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +js-yaml@4.1.0, js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +jszip@^3.10.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" + integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + setimmediate "^1.0.5" + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +mocha@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" + integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== + dependencies: + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + nanoid "3.3.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== + +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +object-assign@^4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +open@^8.4.2: + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pako@~1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.2.tgz#78fcecd6d870551aa5547437cdae39d4701dca5b" + integrity sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +promise@^7.0.4: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + 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" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== + dependencies: + resolve "^1.20.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.20.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@5.2.1, safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +schema-utils@^3.1.1, schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +semver@^7.3.4, semver@^7.3.7, semver@^7.5.2: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +serialize-javascript@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" + integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== + dependencies: + randombytes "^2.1.0" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@^0.5.21, source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +stream@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stream/-/stream-0.0.2.tgz#7f5363f057f6592c5595f00bc80a27f5cec1f0ef" + integrity sha512-gCq3NDI2P35B2n6t76YJuOp7d6cN/C7Rt0577l91wllh0sY9ZBuw9KaSGqH/b0hzn3CWWJbpbW0W0WvQ1H/Q7g== + dependencies: + emitter-component "^1.1.1" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@3.1.1, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@8.1.1, supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.3.7: + version "5.3.9" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1" + integrity sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.17" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.1" + terser "^5.16.8" + +terser@^5.16.8: + version "5.24.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.24.0.tgz#4ae50302977bca4831ccc7b4fef63a3c04228364" + integrity sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +transformer-proxy@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/transformer-proxy/-/transformer-proxy-0.3.5.tgz#40ecf87f846e8b1603a6d22b49d60d81f57ce512" + integrity sha512-mBbKwpGq45DAa4AJQU8osDL7rV065VKCEhVH7g7EwVT3oYogABso+ZwFz5XuvNVI9+tfgwk9NMKE+JL+bue/mw== + dependencies: + promise "^7.0.4" + stream "0.0.2" + util "^0.10.3" + +ts-loader@^9.4.2: + version "9.5.0" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.5.0.tgz#f0a51dda37cc4d8e43e6cb14edebbc599b0c3aa2" + integrity sha512-LLlB/pkB4q9mW2yLdFMnK3dEHbrBjeZTYguaaIfusyojBgAGf5kF+O6KcWqiGzWqHk0LBsoolrp4VftEURhybg== + dependencies: + chalk "^4.1.0" + enhanced-resolve "^5.0.0" + micromatch "^4.0.0" + semver "^7.3.4" + source-map "^0.7.4" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@^4.9.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +watchpack@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +webpack-cli@^5.0.1: + version "5.1.4" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" + integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^2.1.1" + "@webpack-cli/info" "^2.0.2" + "@webpack-cli/serve" "^2.0.5" + colorette "^2.0.14" + commander "^10.0.1" + cross-spawn "^7.0.3" + envinfo "^7.7.3" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^3.1.1" + rechoir "^0.8.0" + webpack-merge "^5.7.3" + +webpack-merge@^5.7.3: + version "5.10.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" + integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== + dependencies: + clone-deep "^4.0.1" + flat "^5.0.2" + wildcard "^2.0.0" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@^5.75.0: + version "5.89.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.89.0.tgz#56b8bf9a34356e93a6625770006490bf3a7f32dc" + integrity sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^1.0.0" + "@webassemblyjs/ast" "^1.11.5" + "@webassemblyjs/wasm-edit" "^1.11.5" + "@webassemblyjs/wasm-parser" "^1.11.5" + acorn "^8.7.1" + acorn-import-assertions "^1.9.0" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.15.0" + es-module-lexer "^1.2.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.2.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.7" + watchpack "^2.4.0" + webpack-sources "^3.2.3" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== + +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_grafana-vscode-0.0.16.vsix b/MagicEyes/src/visualization/vscode_ext/lmp_grafana-vscode-0.0.16.vsix new file mode 100644 index 000000000..3f2f86320 Binary files /dev/null and b/MagicEyes/src/visualization/vscode_ext/lmp_grafana-vscode-0.0.16.vsix differ diff --git a/eBPF_Supermarket/Memory_Subsystem/bpftool b/eBPF_Supermarket/Memory_Subsystem/bpftool deleted file mode 160000 index 06c61eccd..000000000 --- a/eBPF_Supermarket/Memory_Subsystem/bpftool +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 06c61eccd3b8a6ff3df3e451a2a93058913124fc diff --git "a/eBPF_Supermarket/Memory_Subsystem/docs/mem_watcher\345\217\257\350\247\206\345\214\226.md" b/eBPF_Supermarket/Memory_Subsystem/docs/mem_watcher_vision.md similarity index 100% rename from "eBPF_Supermarket/Memory_Subsystem/docs/mem_watcher\345\217\257\350\247\206\345\214\226.md" rename to eBPF_Supermarket/Memory_Subsystem/docs/mem_watcher_vision.md diff --git a/eBPF_Supermarket/Memory_Subsystem/libbpf b/eBPF_Supermarket/Memory_Subsystem/libbpf deleted file mode 160000 index 46eafba62..000000000 --- a/eBPF_Supermarket/Memory_Subsystem/libbpf +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 46eafba62ee380a1f8230e2d5e81f65e0e030f15 diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/Makefile b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/Makefile index e08470014..06e256892 100644 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/Makefile +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/Makefile @@ -1,13 +1,13 @@ # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) OUTPUT := .output CLANG ?= clang -LIBBPF_SRC := $(abspath ../libbpf/src) -BPFTOOL_SRC := $(abspath ../bpftool/src) +LIBBPF_SRC := $(abspath ../../lib/libbpf/src) +BPFTOOL_SRC := $(abspath ../../lib/bpftool/src) LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool LIBBLAZESYM_SRC := $(abspath ../blazesym/) -LIBBLAZESYM_INC := $(abspath $(LIBBLAZESYM_SRC)/capi/include) +LIBBLAZESYM_INC := $(abspath ../blazesym/capi/include) LIBBLAZESYM_OBJ := $(abspath $(OUTPUT)/libblazesym_c.a) ARCH ?= $(shell uname -m | sed 's/x86_64/x86/' \ | sed 's/arm.*/arm/' \ @@ -20,7 +20,7 @@ VMLINUX := ../vmlinux/$(ARCH)/vmlinux.h # Use our own libbpf API headers and Linux UAPI headers distributed with # libbpf to avoid dependency on system-wide headers, which could be missing or # outdated -INCLUDES := -I$(OUTPUT) -I../libbpf/include/uapi -I$(dir $(VMLINUX)) -I$(LIBBLAZESYM_INC) +INCLUDES := -I$(OUTPUT) -I../../libbpf/include/uapi -I$(dir $(VMLINUX)) -I$(LIBBLAZESYM_INC) -I./include CFLAGS := -g -Wall ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS) @@ -30,8 +30,9 @@ CARGO ?= $(shell which cargo) ifeq ($(strip $(CARGO)),) BZS_APPS := else -BZS_APPS := mem_watcher -APPS += $(BZS_APPS) +BZS_APPS := +TARGETS= mem_watcher + # Required by libblazesym ALL_LDFLAGS += -lrt -ldl -lpthread -lm endif @@ -69,12 +70,12 @@ $(call allow-override,CC,$(CROSS_COMPILE)cc) $(call allow-override,LD,$(CROSS_COMPILE)ld) .PHONY: all -all: $(APPS) +all: $(TARGETS) .PHONY: clean clean: $(call msg,CLEAN) - $(Q)rm -rf $(OUTPUT) $(APPS) + $(Q)rm -rf $(OUTPUT) $(TARGETS) $(OUTPUT) $(OUTPUT)/libbpf $(BPFTOOL_OUTPUT): $(call msg,MKDIR,$@) @@ -102,7 +103,7 @@ $(LIBBLAZESYM_OBJ): $(LIBBLAZESYM_SRC)/target/release/libblazesym_c.a | $(OUTPUT $(Q)cp $(LIBBLAZESYM_SRC)/target/release/libblazesym_c.a $@ # Build BPF code -$(OUTPUT)/%.bpf.o: %.bpf.c $(LIBBPF_OBJ) $(wildcard %.h) $(VMLINUX) | $(OUTPUT) $(BPFTOOL) +$(OUTPUT)/%.bpf.o: bpf/%.bpf.c $(LIBBPF_OBJ) $(wildcard %.h) $(VMLINUX) | $(OUTPUT) $(BPFTOOL) $(call msg,BPF,$@) $(Q)$(CLANG) -g -O2 -target bpf -D__TARGET_ARCH_$(ARCH) \ $(INCLUDES) $(CLANG_BPF_SYS_INCLUDES) \ @@ -110,25 +111,28 @@ $(OUTPUT)/%.bpf.o: %.bpf.c $(LIBBPF_OBJ) $(wildcard %.h) $(VMLINUX) | $(OUTPUT) $(Q)$(BPFTOOL) gen object $@ $(patsubst %.bpf.o,%.tmp.bpf.o,$@) # Generate BPF skeletons -$(OUTPUT)/%.skel.h: $(OUTPUT)/%.bpf.o | $(OUTPUT) $(BPFTOOL) +.PHONY: $(APPS) +$(APPS): %: $(OUTPUT)/%.bpf.o | $(OUTPUT) $(BPFTOOL) $(call msg,GEN-SKEL,$@) - $(Q)$(BPFTOOL) gen skeleton $< > $@ + $(Q)$(BPFTOOL) gen skeleton $< > $(OUTPUT)/$@.skel.h # Build user-space code -$(patsubst %,$(OUTPUT)/%.o,$(APPS)): %.o: %.skel.h - $(OUTPUT)/%.o: %.c $(wildcard %.h) | $(OUTPUT) + $(call msg,CC,$@) + $(Q)$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +$(OUTPUT)/$(TARGETS).o: $(TARGETS).c $(APPS) | $(OUTPUT) $(call msg,CC,$@) $(Q)$(CC) $(CFLAGS) $(INCLUDES) -c $(filter %.c,$^) -o $@ -$(patsubst %,$(OUTPUT)/%.o,$(BZS_APPS)): $(LIBBLAZESYM_OBJ) +$(patsubst %,$(OUTPUT)/%.o,$(TARGETS)): $(LIBBLAZESYM_OBJ) -$(BZS_APPS): $(LIBBLAZESYM_OBJ) +$(TARGETS): $(LIBBLAZESYM_OBJ) # Build application binary -$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) | $(OUTPUT) +$(TARGETS): %: $(OUTPUT)/%.o $(COMMON_OBJ) $(LIBBPF_OBJ) | $(OUTPUT) $(call msg,BINARY,$@) - $(Q)$(CC) $(CFLAGS) $^ $(ALL_LDFLAGS) -lelf -lz -o $@ + $(Q)$(CC) $(CFLAGS) $^ $(ALL_LDFLAGS) -lstdc++ -lelf -lz -o $@ SUCCESS_MESSAGE: @echo "\e[38;2;255;102;204m _ _ \e[0m" diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.bpf.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/mem_watcher.bpf.c similarity index 100% rename from eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.bpf.c rename to eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/mem_watcher.bpf.c diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/memleak.bpf.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/memleak.bpf.c similarity index 100% rename from eBPF_Supermarket/Memory_Subsystem/mem_watcher/memleak.bpf.c rename to eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/memleak.bpf.c diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/paf.bpf.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/paf.bpf.c similarity index 100% rename from eBPF_Supermarket/Memory_Subsystem/mem_watcher/paf.bpf.c rename to eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/paf.bpf.c diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/pr.bpf.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/pr.bpf.c similarity index 100% rename from eBPF_Supermarket/Memory_Subsystem/mem_watcher/pr.bpf.c rename to eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/pr.bpf.c diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/procstat.bpf.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/procstat.bpf.c similarity index 96% rename from eBPF_Supermarket/Memory_Subsystem/mem_watcher/procstat.bpf.c rename to eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/procstat.bpf.c index 13d08e593..6d44f33ac 100644 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/procstat.bpf.c +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/procstat.bpf.c @@ -33,7 +33,7 @@ pid_t user_pid = 0; SEC("kprobe/finish_task_switch") int BPF_KPROBE(finish_task_switch, struct task_struct *prev) { struct procstat_event *e; - struct percpu_counter rss = {}; + struct mm_rss_stat rss = {}; struct mm_struct *mms; long long *t; pid_t pid = bpf_get_current_pid_tgid() >> 32; @@ -65,7 +65,7 @@ int BPF_KPROBE(finish_task_switch, struct task_struct *prev) { e->nvcsw = BPF_CORE_READ(prev, nvcsw); e->nivcsw = BPF_CORE_READ(prev, nivcsw); - rss = *BPF_CORE_READ(prev, mm, rss_stat); + rss = BPF_CORE_READ(prev, mm, rss_stat); t = (long long *)(rss.count); e->rssfile = *t; e->rssanon = *(t + 1); diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/sysstat.bpf.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/sysstat.bpf.c similarity index 100% rename from eBPF_Supermarket/Memory_Subsystem/mem_watcher/sysstat.bpf.c rename to eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/sysstat.bpf.c diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.h b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/include/mem_watcher.h similarity index 100% rename from eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.h rename to eBPF_Supermarket/Memory_Subsystem/mem_watcher/include/mem_watcher.h diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/memleak.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/memleak.c deleted file mode 100644 index fa926527c..000000000 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/memleak.c +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2023 The LMP Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// author: zai953879556@163.com -// -// mem_watcher libbpf user mode code - -#include -#include -#include -#include -#include -#include -#include -#include "memleak.skel.h" -#include "mem_watcher.h" - -#include "blazesym.h" - -int main(int argc, char **argv) { - -} diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/paf.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/paf.c deleted file mode 100644 index 3057fae61..000000000 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/paf.c +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) -/* Copyright (c) 2020 Facebook */ -#include -#include -#include -#include -#include -#include -#include "mem_watcher.h" -#include "paf.skel.h" -#include -#include - -int main(int argc, char **argv) { - -} diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/pr.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/pr.c deleted file mode 100644 index c4dcd6f3f..000000000 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/pr.c +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) -/* Copyright (c) 2020 Facebook */ -#include -#include -#include -#include -#include -#include -#include "mem_watcher.h" -#include "pr.skel.h" -#include -#include - -int main(int argc, char **argv){ - -} diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/procstat.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/procstat.c deleted file mode 100644 index 90876c125..000000000 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/procstat.c +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) -/* Copyright (c) 2020 Facebook */ -#include -#include -#include -#include -#include -#include -#include "mem_watcher.h" -#include "procstat.skel.h" -#include -#include - -int main(int argc, char **argv) { - -} \ No newline at end of file diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/sysstat.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/sysstat.c deleted file mode 100644 index 448210d90..000000000 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/sysstat.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "mem_watcher.h" -#include "sysstat.skel.h" -#include -#include - -int main(int argc, char **argv) { - -} \ No newline at end of file diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/Makefile b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/Makefile new file mode 100644 index 000000000..cbe5710b9 --- /dev/null +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/Makefile @@ -0,0 +1,12 @@ +CC = gcc +CFLAGS = -g + +.PHONY: all clean + +all: test_mem + +test_mem: test_mem.c + $(CC) $(CFLAGS) -o test_mem test_mem.c + +clean: + rm -f test_mem diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/pr_test/Makefile b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/pr_test/Makefile new file mode 100644 index 000000000..55d78fca0 --- /dev/null +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/pr_test/Makefile @@ -0,0 +1,22 @@ +# Compiler and flags +CC = gcc +CFLAGS = -Wall + +# Source files +C_SRC = pr_test.c + +# Output binary +C_OUT = pr_test + +.PHONY: all clean run + +all: $(C_OUT) + +$(C_OUT): $(C_SRC) + $(CC) $(CFLAGS) $< -o $@ + +clean: + rm -f $(C_OUT) + +run: $(C_OUT) + sudo ./$(C_OUT) diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/pr_test/pr_test.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/pr_test/pr_test.c new file mode 100644 index 000000000..e10e25bf5 --- /dev/null +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/pr_test/pr_test.c @@ -0,0 +1,36 @@ +#include +#include +#include + +#define ALLOC_SIZE 1024*1024*1024 // 分配 512 MB 内存 + +int main() { + void *memory; + printf("Allocating memory...\n"); + memory = malloc(ALLOC_SIZE); + if (!memory) { + perror("Failed to allocate memory"); + return -1; + } + + // 填充内存以确保页面被分配 + printf("Filling memory...\n"); + for (size_t i = 0; i < ALLOC_SIZE; ++i) { + ((char*)memory)[i] = (char)i; + } + + printf("Freeing memory...\n"); + free(memory); + + // 给内核更多时间处理回收 + printf("Sleeping for 10 seconds...\n"); + sleep(10); // 增加等待时间到 10 秒 + + printf("Memory management demo finished.\n"); + return 0; +} + +// 分配大量内存。 +//填充内存以确保页面分配。 +//释放内存。 +//等待一段时间以允许内核处理任何可能的内存回收。 \ No newline at end of file diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/test_mem.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/test_mem.c new file mode 100644 index 000000000..9396ace1f --- /dev/null +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/test_mem.c @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include +#include +#include + +#define ALLOC_SIZE_SMALL 4 +#define ALLOC_SIZE_MEDIUM 64 +#define ALLOC_SIZE_LARGE 1024 + +static struct env { + bool overall_leak_test; + bool mem_leak; + bool mem_unleak; +} env = { + .overall_leak_test = false, + .mem_leak = false, + .mem_unleak = false, +}; + +const char argp_program_doc[] ="mem_watcher test.\n"; + +static const struct argp_option opts[] = { + { NULL, 0, NULL, 0, "Memory Management Options:", 1 }, + { "overall-test", 'o', NULL, 0, "Perform overall memory test", 2 }, + { "detect-leak", 'l', NULL, 0, "Detect memory leaks", 3 }, + { "no-leak", 'n', NULL, 0, "No memory leaks expected", 3 }, + { NULL, 'h', NULL, OPTION_HIDDEN, "show the full help", 0 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +static error_t parse_arg(int key, char *arg, struct argp_state *state) +{ + (void)arg; + switch (key) { + case 'o': + env.overall_leak_test = true; + break; + case 'l': + env.mem_leak = true; + break; + case 'n': + env.mem_unleak = true; + break; + case 'h': + argp_state_help(state, stderr, ARGP_HELP_STD_HELP); + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +// 模拟一些处理,通过写入分配的内存 +static void process_data(void *ptr, int size) { + memset(ptr, 0, size); +} + +// 分配内存并处理数据 +static void * alloc_v3(int alloc_size) { + void *ptr = malloc(alloc_size); + if (ptr) { + process_data(ptr, alloc_size / 3); + } + return ptr; +} + +// 分配内存并处理数据 +static void * alloc_v2(int alloc_size) { + void *ptr = alloc_v3(alloc_size); + if (ptr) { + process_data(ptr, alloc_size / 4); + } + return ptr; +} + +// 分配内存并处理数据 +static void * alloc_v1(int alloc_size) { + void *ptr = alloc_v2(alloc_size); + if (ptr) { + process_data(ptr, alloc_size / 5); + } + return ptr; +} + +// 演示内存泄漏 +static void leak_memory() { + void *ptr = malloc(ALLOC_SIZE_LARGE); + // 故意不释放 ptr 以制造内存泄漏 + process_data(ptr, ALLOC_SIZE_LARGE); +} + +static void mem_leak_process() { + // 引入一些间歇性的内存泄漏 + void *ptr = NULL; + int i = 0; + for (i = 0; ; i++) { + if (i % 5 == 0) { + leak_memory(); + } + sleep(1); + } +} + +static void mem_unleak_process(){ + void *ptr = NULL; + int i = 0; + + for (i = 0; ; i++) { + int alloc_size = (i % 3 == 0) ? ALLOC_SIZE_SMALL : (i % 3 == 1) ? ALLOC_SIZE_MEDIUM : ALLOC_SIZE_LARGE; + + ptr = alloc_v1(alloc_size); + if (!ptr) { + perror("alloc_v1 失败"); + exit(EXIT_FAILURE); + } + + void *ptr2 = malloc(alloc_size); + if (!ptr2) { + perror("malloc 失败"); + free(ptr); + exit(EXIT_FAILURE); + } + + process_data(ptr2, alloc_size); + + sleep(1); + free(ptr); + + sleep(2); + free(ptr2); + } +} + +int main(int argc, char **argv){ + int err; + static const struct argp argp = { + .options = opts, + .parser = parse_arg, + .doc = argp_program_doc, + }; + + err = argp_parse(&argp, argc, argv, 0, NULL, NULL); + if (err) + return err; + + if (env.overall_leak_test) { + // 打印当前进程的进程号(PID) + pid_t pid = getpid(); + printf("当前进程的进程号(PID): %d\n", pid); + if (env.mem_leak) { + printf("正在进行内存泄漏检测...\n"); + mem_leak_process(); + } + if (env.mem_unleak) { + printf("正在进行无内存泄漏测试...\n"); + mem_unleak_process(); + } + } + + return 0; +} diff --git a/eBPF_Supermarket/Memory_Subsystem/old_project/mem_watcher/cma/Makefile b/eBPF_Supermarket/Memory_Subsystem/old_project/mem_watcher/cma/Makefile index c3a2cd4fc..4bee190f7 100644 --- a/eBPF_Supermarket/Memory_Subsystem/old_project/mem_watcher/cma/Makefile +++ b/eBPF_Supermarket/Memory_Subsystem/old_project/mem_watcher/cma/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) OUTPUT := .output CLANG ?= clang -LIBBPF_SRC := $(abspath ../libbpf-bootstrap/libbpf/src) -BPFTOOL_SRC := $(abspath ../libbpf-bootstrap/bpftool/src) +LIBBPF_SRC := $(abspath ../../../../lib/libbpf/src) +BPFTOOL_SRC := $(abspath ../../../../lib/bpftool/src) LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool diff --git a/eBPF_Supermarket/Memory_Subsystem/old_project/mem_watcher/ion/Makefile b/eBPF_Supermarket/Memory_Subsystem/old_project/mem_watcher/ion/Makefile index e9e8ef726..154ab723b 100644 --- a/eBPF_Supermarket/Memory_Subsystem/old_project/mem_watcher/ion/Makefile +++ b/eBPF_Supermarket/Memory_Subsystem/old_project/mem_watcher/ion/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) OUTPUT := .output CLANG ?= clang -LIBBPF_SRC := $(abspath ../libbpf-bootstrap/libbpf/src) -BPFTOOL_SRC := $(abspath ../libbpf-bootstrap/bpftool/src) +LIBBPF_SRC := $(abspath ../../../../lib/libbpf/src) +BPFTOOL_SRC := $(abspath ../../../../lib/bpftool/src) LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool diff --git a/eBPF_Supermarket/Memory_Subsystem/old_project/mem_watcher/page_fault/Makefile b/eBPF_Supermarket/Memory_Subsystem/old_project/mem_watcher/page_fault/Makefile index 041fcb3ba..9e45bb23a 100644 --- a/eBPF_Supermarket/Memory_Subsystem/old_project/mem_watcher/page_fault/Makefile +++ b/eBPF_Supermarket/Memory_Subsystem/old_project/mem_watcher/page_fault/Makefile @@ -2,8 +2,8 @@ OUTPUT := .output CLANG ?= clang LLVM_STRIP ?= llvm-strip -LIBBPF_SRC := $(abspath ../../libbpf/src) -BPFTOOL_SRC := $(abspath ../../bpftool/src) +LIBBPF_SRC := $(abspath ../../../../lib/libbpf/src) +BPFTOOL_SRC := $(abspath ../../../../lib/bpftool/src) LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool diff --git a/eBPF_Supermarket/Memory_Subsystem/old_project/paf/Makefile b/eBPF_Supermarket/Memory_Subsystem/old_project/paf/Makefile index 04f7a181a..75cfbb57c 100644 --- a/eBPF_Supermarket/Memory_Subsystem/old_project/paf/Makefile +++ b/eBPF_Supermarket/Memory_Subsystem/old_project/paf/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) OUTPUT := .output CLANG ?= clang -LIBBPF_SRC := $(abspath ../../libbpf/src) -BPFTOOL_SRC := $(abspath ../../bpftool/src) +LIBBPF_SRC := $(abspath ../../../lib/libbpf/src) +BPFTOOL_SRC := $(abspath ../../../lib/bpftool/src) LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool diff --git a/eBPF_Supermarket/Memory_Subsystem/old_project/time/Makefile b/eBPF_Supermarket/Memory_Subsystem/old_project/page_fault/Makefile similarity index 97% rename from eBPF_Supermarket/Memory_Subsystem/old_project/time/Makefile rename to eBPF_Supermarket/Memory_Subsystem/old_project/page_fault/Makefile index a018d9a27..6fc92d3a9 100644 --- a/eBPF_Supermarket/Memory_Subsystem/old_project/time/Makefile +++ b/eBPF_Supermarket/Memory_Subsystem/old_project/page_fault/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) OUTPUT := .output CLANG ?= clang -LIBBPF_SRC := $(abspath ../../libbpf/src) -BPFTOOL_SRC := $(abspath ../../bpftool/src) +LIBBPF_SRC := $(abspath ../../../lib/libbpf/src) +BPFTOOL_SRC := $(abspath ../../../lib/bpftool/src) LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/../bpftool) BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool diff --git a/eBPF_Supermarket/Memory_Subsystem/old_project/time/time.bpf.c b/eBPF_Supermarket/Memory_Subsystem/old_project/page_fault/page_fault.bpf.c similarity index 100% rename from eBPF_Supermarket/Memory_Subsystem/old_project/time/time.bpf.c rename to eBPF_Supermarket/Memory_Subsystem/old_project/page_fault/page_fault.bpf.c diff --git a/eBPF_Supermarket/Memory_Subsystem/old_project/time/time.c b/eBPF_Supermarket/Memory_Subsystem/old_project/page_fault/page_fault.c similarity index 100% rename from eBPF_Supermarket/Memory_Subsystem/old_project/time/time.c rename to eBPF_Supermarket/Memory_Subsystem/old_project/page_fault/page_fault.c diff --git a/eBPF_Supermarket/Memory_Subsystem/old_project/time/time.h b/eBPF_Supermarket/Memory_Subsystem/old_project/page_fault/page_fault.h similarity index 100% rename from eBPF_Supermarket/Memory_Subsystem/old_project/time/time.h rename to eBPF_Supermarket/Memory_Subsystem/old_project/page_fault/page_fault.h diff --git a/eBPF_Supermarket/Memory_Subsystem/old_project/pr/Makefile b/eBPF_Supermarket/Memory_Subsystem/old_project/pr/Makefile index 5b76fdb3e..fe15282f5 100644 --- a/eBPF_Supermarket/Memory_Subsystem/old_project/pr/Makefile +++ b/eBPF_Supermarket/Memory_Subsystem/old_project/pr/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) OUTPUT := .output CLANG ?= clang -LIBBPF_SRC := $(abspath ../../libbpf/src) -BPFTOOL_SRC := $(abspath ../../bpftool/src) +LIBBPF_SRC := $(abspath ../../../lib/libbpf/src) +BPFTOOL_SRC := $(abspath ../../../lib/bpftool/src) LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool diff --git a/eBPF_Supermarket/Memory_Subsystem/old_project/procstat/Makefile b/eBPF_Supermarket/Memory_Subsystem/old_project/procstat/Makefile index 28dcdc12c..a28526400 100644 --- a/eBPF_Supermarket/Memory_Subsystem/old_project/procstat/Makefile +++ b/eBPF_Supermarket/Memory_Subsystem/old_project/procstat/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) OUTPUT := .output CLANG ?= clang -LIBBPF_SRC := $(abspath ../../libbpf/src) -BPFTOOL_SRC := $(abspath ../../bpftool/src) +LIBBPF_SRC := $(abspath ../../../lib/libbpf/src) +BPFTOOL_SRC := $(abspath ../../../lib/bpftool/src) LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool diff --git a/eBPF_Supermarket/Memory_Subsystem/old_project/sysstat/Makefile b/eBPF_Supermarket/Memory_Subsystem/old_project/sysstat/Makefile index 422ff2fc3..5f33e0a2a 100644 --- a/eBPF_Supermarket/Memory_Subsystem/old_project/sysstat/Makefile +++ b/eBPF_Supermarket/Memory_Subsystem/old_project/sysstat/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) OUTPUT := .output CLANG ?= clang -LIBBPF_SRC := $(abspath ../../libbpf/src) -BPFTOOL_SRC := $(abspath ../../bpftool/src) +LIBBPF_SRC := $(abspath ../../../lib/libbpf/src) +BPFTOOL_SRC := $(abspath ../../../lib/bpftool/src) LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h index 90ad50757..89a5b9d91 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h @@ -158,6 +158,11 @@ struct { __uint(max_entries, 256 * 1024); } mysql_rb SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} redis_rb SEC(".maps"); + struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); @@ -242,6 +247,14 @@ struct { __type(value, __u64); } mysql_time SEC(".maps"); +//redis 耗时 +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 256*1024); + __type(key, __u32); + __type(value, struct redis_query); +} redis_time SEC(".maps"); + //sql请求数 struct { __uint(type, BPF_MAP_TYPE_HASH); @@ -269,7 +282,8 @@ const volatile int filter_dport = 0; const volatile int filter_sport = 0; const volatile int all_conn = 0, err_packet = 0, extra_conn_info = 0, layer_time = 0, http_info = 0, retrans_info = 0, udp_info =0,net_filter = 0, - drop_reason = 0,icmp_info = 0 ,tcp_info = 0 ,dns_info = 0 ,stack_info = 0,mysql_info = 0; + drop_reason = 0,icmp_info = 0 ,tcp_info = 0 ,dns_info = 0 ,stack_info = 0, + mysql_info = 0, redis_info = 0; /* help macro */ diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/data/connects.log b/eBPF_Supermarket/Network_Subsystem/net_watcher/data/connects.log index 733723688..e69de29bb 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/data/connects.log +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/data/connects.log @@ -1 +0,0 @@ -connection{pid="214827",sock="0xffff944e0c3dda00",src="192.168.239.132:35422",dst="20.189.173.1:443",is_server="0",backlog="-",maxbacklog="-",cwnd="-",ssthresh="-",sndbuf="-",wmem_queued="-",rx_bytes="-",tx_bytes="-",srtt="-",duration="-",total_retrans="-",fast_retrans="-",timeout_retrans="-"} diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c index 5c67c4090..4ae7d22f6 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c @@ -30,6 +30,8 @@ #include "mysql.bpf.h" +#include "redis.bpf.h" + #include "drop.bpf.h" // accecpt an TCP connection @@ -330,4 +332,13 @@ int BPF_KPROBE(query__start) { SEC("uretprobe/_Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command") int BPF_KPROBE(query__end){ return __handle_mysql_end(ctx); +} + +SEC("uprobe/call") +int BPF_KPROBE(query__start_redis) { + return __handle_redis_start(ctx); +} +SEC("uretprobe/call") +int BPF_KPROBE(query__end_redis){ + return __handle_redis_end(ctx); } \ No newline at end of file diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c index c2ba5490e..190c2689e 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c @@ -44,7 +44,7 @@ static int all_conn = 0, err_packet = 0, extra_conn_info = 0, layer_time = 0, http_info = 0, retrans_info = 0, udp_info = 0, net_filter = 0, drop_reason = 0, addr_to_func = 0, icmp_info = 0, tcp_info = 0, time_load = 0, dns_info = 0, stack_info = 0, mysql_info = 0, - count_info = 0; // flag + redis_info = 0 ,count_info = 0;// flag static const char *tcp_states[] = { [1] = "ESTABLISHED", [2] = "SYN_SENT", [3] = "SYN_RECV", @@ -78,8 +78,8 @@ static const struct argp_option opts[] = { {"stack", 'A', 0, 0, "set to trace of stack "}, {"mysql", 'M', 0, 0, "set to trace mysql information info include Pid 进程id、Comm " - "进程名、Size sql语句字节大小、Sql 语句、Duration Sql耗时、Request " - "Sql请求数"}, + "进程名、Size sql语句字节大小、Sql 语句"}, + {"redis", 'R', 0, 0}, {"count", 'C', "NUMBER", 0, "specify the time to count the number of requests"}, {}}; @@ -141,6 +141,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) { case 'M': mysql_info = 1; break; + case 'R': + redis_info = 1; + break; case 'C': count_info = strtoul(arg, &end, 10); break; @@ -169,6 +172,7 @@ enum MonitorMode { MODE_TCP, MODE_DNS, MODE_MYSQL, + MODE_REDIS, MODE_DEFAULT }; @@ -187,7 +191,10 @@ enum MonitorMode get_monitor_mode() { return MODE_DNS; } else if (mysql_info) { return MODE_MYSQL; - } else { + } else if (redis_info) { + return MODE_REDIS; + } + else { return MODE_DEFAULT; } } @@ -227,7 +234,7 @@ void print_logo() { pclose(lolcat_pipe); } -static const char binary_path[] = "/usr/sbin/mysqld"; +static char binary_path[64]=""; #define __ATTACH_UPROBE(skel, sym_name, prog_name, is_retprobe) \ do { \ LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts, .func_name = #sym_name, \ @@ -419,6 +426,7 @@ static void set_rodata_flags(struct netwatcher_bpf *skel) { skel->rodata->dns_info = dns_info; skel->rodata->stack_info = stack_info; skel->rodata->mysql_info = mysql_info; + skel->rodata->redis_info = redis_info; } static void set_disable_load(struct netwatcher_bpf *skel) { @@ -556,6 +564,10 @@ static void set_disable_load(struct netwatcher_bpf *skel) { mysql_info ? true : false); bpf_program__set_autoload(skel->progs.query__end, mysql_info ? true : false); + bpf_program__set_autoload(skel->progs.query__start_redis, + redis_info ? true : false); + bpf_program__set_autoload(skel->progs.query__end_redis, + redis_info ? true : false); } static void print_header(enum MonitorMode mode) { @@ -617,6 +629,14 @@ static void print_header(enum MonitorMode mode) { printf("%-20s %-20s %-20s %-20s %-40s %-20s %-20s \n", "Pid", "Tid", "Comm", "Size", "Sql", "Duration/μs", "Request"); break; + case MODE_REDIS: + printf("===============================================================" + "====================REDIS " + "INFORMATION====================================================" + "============================\n"); + printf("%-20s %-20s %-20s %-20s %-20s \n", "Pid", "Comm", "Size", "Redis", + "duration/μs"); + break; case MODE_DEFAULT: printf("===============================================================" "=INFORMATION===================================================" @@ -765,7 +785,7 @@ static int print_conns(struct netwatcher_bpf *skel) { static int print_packet(void *ctx, void *packet_info, size_t size) { if (udp_info || net_filter || drop_reason || icmp_info || tcp_info || - dns_info || mysql_info) + dns_info || mysql_info||redis_info) return 0; const struct pack_t *pack_info = packet_info; if (pack_info->mac_time > MAXTIME || pack_info->ip_time > MAXTIME || @@ -1117,6 +1137,20 @@ static int print_mysql(void *ctx, void *packet_info, size_t size) { } return 0; } +static int print_redis(void *ctx, void *packet_info, size_t size) { + const struct redis_query *pack_info = packet_info; + int i=0; + char redis[64]; + for(i=0;iargc;i++) + { + strcat(redis, pack_info->redis[i]); + strcat(redis, " "); + } + printf("%-20d %-20s %-20d %-20s %-21llu\n", pack_info->pid, + pack_info->comm,pack_info->argc, redis,pack_info->duratime); + strcpy(redis,""); + return 0; +} static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) { return vfprintf(stderr, format, args); @@ -1155,7 +1189,8 @@ static int print_trace(void *_ctx, void *data, size_t size) { return 0; } -int attach_uprobe(struct netwatcher_bpf *skel) { +int attach_uprobe_mysql(struct netwatcher_bpf *skel) { + ATTACH_UPROBE_CHECKED( skel, _Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command, query__start); @@ -1164,7 +1199,15 @@ int attach_uprobe(struct netwatcher_bpf *skel) { query__end); return 0; } - +int attach_uprobe_redis(struct netwatcher_bpf *skel) { + ATTACH_UPROBE_CHECKED( + skel, call, + query__start_redis); + ATTACH_UPROBE_CHECKED( + skel, call, + query__end_redis); + return 0; +} int main(int argc, char **argv) { char *last_slash = strrchr(argv[0], '/'); if (last_slash) { @@ -1187,6 +1230,7 @@ int main(int argc, char **argv) { struct ring_buffer *dns_rb = NULL; struct ring_buffer *trace_rb = NULL; struct ring_buffer *mysql_rb = NULL; + struct ring_buffer *redis_rb = NULL; struct netwatcher_bpf *skel; int err; /* Parse command line arguments */ @@ -1222,13 +1266,25 @@ int main(int argc, char **argv) { /* Attach tracepoint handler */ if (mysql_info) { - err = attach_uprobe(skel); + strcpy(binary_path, "/usr/sbin/mysqld"); + err = attach_uprobe_mysql(skel); if (err) { fprintf(stderr, "failed to attach uprobes\n"); goto cleanup; } - } else { + } + else if(redis_info) + { + strcpy(binary_path, "/usr/bin/redis-server"); + err = attach_uprobe_redis(skel); + if (err) { + fprintf(stderr, "failed to attach uprobes\n"); + + goto cleanup; + } + } + else { err = netwatcher_bpf__attach(skel); if (err) { fprintf(stderr, "Failed to attach BPF skeleton\n"); @@ -1237,7 +1293,7 @@ int main(int argc, char **argv) { } enum MonitorMode mode = get_monitor_mode(); - print_logo(); + //print_logo(); print_header(mode); @@ -1297,6 +1353,13 @@ int main(int argc, char **argv) { fprintf(stderr, "Failed to create ring buffer(trace)\n"); goto cleanup; } + redis_rb = ring_buffer__new(bpf_map__fd(skel->maps.redis_rb), print_redis, + NULL, NULL); + if (!redis_rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(trace)\n"); + goto cleanup; + } /* Set up ring buffer polling */ rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), print_packet, NULL, NULL); if (!rb) { @@ -1318,6 +1381,7 @@ int main(int argc, char **argv) { err = ring_buffer__poll(dns_rb, 100 /* timeout, ms */); err = ring_buffer__poll(trace_rb, 100 /* timeout, ms */); err = ring_buffer__poll(mysql_rb, 100 /* timeout, ms */); + err = ring_buffer__poll(redis_rb, 100 /* timeout, ms */); print_conns(skel); sleep(1); /* Ctrl-C will cause -EINTR */ diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h index de8aa5e7a..8687f3e13 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h @@ -180,4 +180,15 @@ typedef struct mysql_query { int count; } mysql_query; +struct redis_query { + int pid; + int tid; + char comm[20]; + u32 size; + char redis[4][8]; + u64 duratime; + int count; + u64 begin_time; + int argc; +}; #endif /* __NETWATCHER_H */ \ No newline at end of file diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/redis.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/redis.bpf.h new file mode 100644 index 000000000..ae4cf559a --- /dev/null +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/redis.bpf.h @@ -0,0 +1,70 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// redis + +#include "common.bpf.h" +#include "redis_helper.bpf.h" +#define MAXEPOLL 4 +static __always_inline int __handle_redis_start(struct pt_regs *ctx) { + struct client *cli = (struct client *)PT_REGS_PARM1(ctx); + struct redis_query start={}; + void *ptr; + char name[100]=""; + int argv_len; + bpf_probe_read(&start.argc, sizeof(start.argc), &cli->argc); + robj **arg0; + robj *arg1; + bpf_probe_read(&arg0, sizeof(arg0), &cli->argv); + bpf_probe_read(&arg1, sizeof(arg1), &arg0[0]); + for(int i=0;iptr); + bpf_probe_read_str(&start.redis[i], sizeof(start.redis[i]), ptr); + //bpf_printk("%s",start.redis[i]); + } + pid_t pid = bpf_get_current_pid_tgid() >> 32; + u64 start_time = bpf_ktime_get_ns() / 1000; + start.begin_time=start_time; + bpf_map_update_elem(&redis_time, &pid, &start, BPF_ANY); + return 0; +} + +static __always_inline int __handle_redis_end(struct pt_regs *ctx) { + pid_t pid = bpf_get_current_pid_tgid() >> 32; + struct redis_query *start; + u64 end_time = bpf_ktime_get_ns() / 1000; + start = bpf_map_lookup_elem(&redis_time, &pid); + if (!start) { + return 0; + } + struct redis_query *message = bpf_ringbuf_reserve(&redis_rb, sizeof(*message), 0); + if (!message) { + return 0; + } + message->pid = pid; + message->argc = start->argc; + bpf_get_current_comm(&message->comm, sizeof(message->comm)); + for(int i=0;iargc&&iredis[i], sizeof(message->redis[i]), start->redis[i]); + } + bpf_probe_read_str(&message->redis, sizeof(start->redis), start->redis); + message->duratime = end_time - start->begin_time; + bpf_printk("%llu - %llu = %llu",end_time,start->begin_time,message->duratime); + bpf_ringbuf_submit(message, 0); + return 0; +} \ No newline at end of file diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/redis_helper.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/redis_helper.bpf.h new file mode 100644 index 000000000..21f2031f7 --- /dev/null +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/redis_helper.bpf.h @@ -0,0 +1,55 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// +// netwatcher libbpf 内核<->用户 传递信息相关结构体 + +#ifndef __REDIS_HELPER_BPF_H +#define __REDIS_HELPER_BPF_H + +#include "netwatcher.h" +#include "vmlinux.h" +#include +#include +#include +#include +#include +#include + +#define LRU_BITS 24 +typedef struct redisObject { + unsigned type:4; + unsigned encoding:4; + unsigned lru:24; + int refcount; + void *ptr; +} robj; + +struct client { + u64 id; /* Client incremental unique ID. */ + u64 conn; + int resp; /* RESP protocol version. Can be 2 or 3. */ + u64 db; /* Pointer to currently SELECTed DB. */ + robj *name; /* As set by CLIENT SETNAME. */ + char* querybuf; /* Buffer we use to accumulate client queries. */ + unsigned long qb_pos; /* The position we have read in querybuf. */ + char* pending_querybuf; + unsigned long querybuf_peak; /* Recent (100ms or more) peak of querybuf size. */ + int argc; /* Num of arguments of current command. */ + robj **argv; /* Arguments of current command. */ + unsigned long argv_len_sum; /* Size of argv array (may be more than argc) */ +}; + +#endif diff --git a/eBPF_Supermarket/Stack_Analyser/Makefile b/eBPF_Supermarket/Stack_Analyser/Makefile index 83731b94e..4c357c824 100644 --- a/eBPF_Supermarket/Stack_Analyser/Makefile +++ b/eBPF_Supermarket/Stack_Analyser/Makefile @@ -45,6 +45,10 @@ ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS) BIN = $(patsubst src/%.cpp, %, ${wildcard src/*.cpp}) BPF = $(patsubst bpf/%.bpf.c, %, ${wildcard bpf/*.bpf.c}) +BPF_OBJ = $(patsubst %,$(OUTPUT)/%.bpf.o,$(BPF)) +BPF_SKEL_H = $(patsubst %,$(BPF_SKEL)/%.skel.h,$(BPF)) +BPF_WAPPER = $(patsubst %,$(OUTPUT)/%.o,$(BPF)) +BIN_OBJ = $(patsubst %,$(OUTPUT)/%.o,$(BIN)) TARGETS = stack_analyzer @@ -117,7 +121,7 @@ $(BPFTOOL): $(BPFTOOL_SRC) | $(BPFTOOL_OUTPUT) $(Q)$(MAKE) ARCH= CROSS_COMPILE= OUTPUT=$(BPFTOOL_OUTPUT)/ -C $(BPFTOOL_SRC) bootstrap # Build BPF code -$(OUTPUT)/%.bpf.o: bpf/%.bpf.c include/sa_ebpf.h $(LIBBPF_OBJ) $(VMLINUX) | $(OUTPUT) $(BPFTOOL) +$(BPF_OBJ): $(OUTPUT)/%.bpf.o: bpf/%.bpf.c include/ebpf.h $(LIBBPF_OBJ) $(VMLINUX) | $(OUTPUT) $(BPFTOOL) $(call msg,BPF,$@) $(Q)$(CLANG) -g -O2 -target bpf -D__TARGET_ARCH_$(ARCH) \ $(INCLUDES) $(CLANG_BPF_SYS_INCLUDES) \ @@ -125,16 +129,16 @@ $(OUTPUT)/%.bpf.o: bpf/%.bpf.c include/sa_ebpf.h $(LIBBPF_OBJ) $(VMLINUX) | $(OU $(Q)$(BPFTOOL) gen object $@ $(patsubst %.bpf.o,%.tmp.bpf.o,$@) # Generate BPF skeletons -$(BPF_SKEL)/%.skel.h: $(OUTPUT)/%.bpf.o | $(OUTPUT) $(BPFTOOL) $(BPF_SKEL) +$(BPF_SKEL_H): $(BPF_SKEL)/%.skel.h: $(OUTPUT)/%.bpf.o | $(OUTPUT) $(BPFTOOL) $(BPF_SKEL) $(call msg,GEN-SKEL,$@) $(Q)$(BPFTOOL) gen skeleton $< > $@ -$(patsubst %,$(OUTPUT)/%.o,$(BPF)): $(OUTPUT)/%.o: src/bpf_wapper/%.cpp include/bpf_wapper/%.h $(BPF_SKEL)/%.skel.h $(OUTPUT)/eBPFStackCollector.o +$(BPF_WAPPER): $(OUTPUT)/%.o: src/bpf_wapper/%.cpp include/bpf_wapper/%.h $(BPF_SKEL)/%.skel.h $(OUTPUT)/eBPFStackCollector.o $(call msg,CXX,$@) $(Q)$(CXX) $(CFLAGS) $(INCLUDES) -c $< -o $@ # Build depending library -$(patsubst %,$(OUTPUT)/%.o,$(BIN)): $(OUTPUT)/%.o: src/%.cpp $(patsubst %,$(BPF_SKEL)/%.skel.h,$(BPF)) +$(BIN_OBJ): $(OUTPUT)/%.o: src/%.cpp $(BPF_SKEL_H) $(call msg,CXX,$@) $(Q)$(CXX) $(CFLAGS) $(INCLUDES) -c $< -o $@ @@ -143,7 +147,7 @@ $(OUTPUT)/eBPFStackCollector.o: src/bpf_wapper/eBPFStackCollector.cpp include/bp $(Q)$(CXX) $(CFLAGS) $(INCLUDES) -c $< -o $@ # Build application binary -$(TARGETS): $(OUTPUT)/eBPFStackCollector.o $(patsubst %,$(OUTPUT)/%.o,$(BIN)) $(patsubst %,$(OUTPUT)/%.o,$(BPF)) $(LIBBPF_OBJ) +$(TARGETS): $(OUTPUT)/eBPFStackCollector.o $(BIN_OBJ) $(BPF_WAPPER) $(LIBBPF_OBJ) $(call msg,BINARY,$@) $(Q)$(CXX) $^ $(ALL_LDFLAGS) -lstdc++ -lelf -lz -o $@ diff --git a/eBPF_Supermarket/Stack_Analyser/bpf/io.bpf.c b/eBPF_Supermarket/Stack_Analyser/bpf/io.bpf.c index 0406c510e..2469004fe 100644 --- a/eBPF_Supermarket/Stack_Analyser/bpf/io.bpf.c +++ b/eBPF_Supermarket/Stack_Analyser/bpf/io.bpf.c @@ -21,7 +21,7 @@ #include #include -#include "sa_ebpf.h" +#include "ebpf.h" #include "bpf_wapper/io.h" #include "task.h" diff --git a/eBPF_Supermarket/Stack_Analyser/bpf/llc_stat.bpf.c b/eBPF_Supermarket/Stack_Analyser/bpf/llc_stat.bpf.c index eefa368db..b48d433d0 100644 --- a/eBPF_Supermarket/Stack_Analyser/bpf/llc_stat.bpf.c +++ b/eBPF_Supermarket/Stack_Analyser/bpf/llc_stat.bpf.c @@ -21,7 +21,7 @@ #include #include -#include "sa_ebpf.h" +#include "ebpf.h" #include "bpf_wapper/llc_stat.h" #include "task.h" diff --git a/eBPF_Supermarket/Stack_Analyser/bpf/memleak.bpf.c b/eBPF_Supermarket/Stack_Analyser/bpf/memleak.bpf.c index 24f2a14e7..d94b29d97 100644 --- a/eBPF_Supermarket/Stack_Analyser/bpf/memleak.bpf.c +++ b/eBPF_Supermarket/Stack_Analyser/bpf/memleak.bpf.c @@ -21,7 +21,7 @@ #include #include -#include "sa_ebpf.h" +#include "ebpf.h" #include "task.h" #include "bpf_wapper/memleak.h" @@ -31,9 +31,9 @@ const volatile bool wa_missing_free = false; const volatile size_t page_size = 4096; const volatile bool trace_all = false; -BPF_HASH(pid_size_map, u32, u64); // 记录了对应进程使用malloc,calloc等函数申请内存的大小 -BPF_HASH(piddr_meminfo_map, piddr, mem_info); // 记录了每次申请的内存空间的起始地址等信息 -BPF_HASH(memptrs_map, u32, u64); +BPF_HASH(pid_size_map, u32, u64, MAX_ENTRIES); // 记录了对应进程使用malloc,calloc等函数申请内存的大小 +BPF_HASH(piddr_meminfo_map, piddr, mem_info, MAX_ENTRIES); // 记录了每次申请的内存空间的起始地址等信息 +BPF_HASH(memptrs_map, u32, u64, MAX_ENTRIES); const char LICENSE[] SEC("license") = "GPL"; diff --git a/eBPF_Supermarket/Stack_Analyser/bpf/off_cpu.bpf.c b/eBPF_Supermarket/Stack_Analyser/bpf/off_cpu.bpf.c index 5f64815e9..80877b067 100644 --- a/eBPF_Supermarket/Stack_Analyser/bpf/off_cpu.bpf.c +++ b/eBPF_Supermarket/Stack_Analyser/bpf/off_cpu.bpf.c @@ -21,13 +21,13 @@ #include #include -#include "sa_ebpf.h" +#include "ebpf.h" #include "task.h" COMMON_MAPS(u32); COMMON_VALS; // 记录进程运行的起始时间 -BPF_HASH(pid_offTs_map, u32, u64); +BPF_HASH(pid_offTs_map, u32, u64, MAX_ENTRIES/10); const char LICENSE[] SEC("license") = "GPL"; diff --git a/eBPF_Supermarket/Stack_Analyser/bpf/on_cpu.bpf.c b/eBPF_Supermarket/Stack_Analyser/bpf/on_cpu.bpf.c index d70b7c23b..c1b103f19 100644 --- a/eBPF_Supermarket/Stack_Analyser/bpf/on_cpu.bpf.c +++ b/eBPF_Supermarket/Stack_Analyser/bpf/on_cpu.bpf.c @@ -21,7 +21,7 @@ #include #include -#include "sa_ebpf.h" +#include "ebpf.h" #include "task.h" const char LICENSE[] SEC("license") = "GPL"; diff --git a/eBPF_Supermarket/Stack_Analyser/bpf/probe.bpf.c b/eBPF_Supermarket/Stack_Analyser/bpf/probe.bpf.c index 99f91032c..623bb5ae0 100644 --- a/eBPF_Supermarket/Stack_Analyser/bpf/probe.bpf.c +++ b/eBPF_Supermarket/Stack_Analyser/bpf/probe.bpf.c @@ -22,13 +22,13 @@ #include #include -#include "sa_ebpf.h" +#include "ebpf.h" #include "bpf_wapper/probe.h" #include "task.h" COMMON_MAPS(time_tuple); COMMON_VALS; -BPF_HASH(starts, u32, u64); +BPF_HASH(starts, u32, u64, MAX_ENTRIES/10); static int entry(void *ctx) { diff --git a/eBPF_Supermarket/Stack_Analyser/bpf/readahead.bpf.c b/eBPF_Supermarket/Stack_Analyser/bpf/readahead.bpf.c index 41e984ba4..69925f805 100644 --- a/eBPF_Supermarket/Stack_Analyser/bpf/readahead.bpf.c +++ b/eBPF_Supermarket/Stack_Analyser/bpf/readahead.bpf.c @@ -21,7 +21,7 @@ #include #include -#include "sa_ebpf.h" +#include "ebpf.h" #include "task.h" #include "bpf_wapper/readahead.h" @@ -31,8 +31,8 @@ COMMON_MAPS(ra_tuple); COMMON_VALS; -BPF_HASH(in_ra_map, u32, psid); -BPF_HASH(page_psid_map, struct page *, psid); +BPF_HASH(in_ra_map, u32, psid, MAX_ENTRIES/10); +BPF_HASH(page_psid_map, struct page *, psid, MAX_ENTRIES); SEC("fentry/page_cache_ra_unbounded") // fentry在内核函数page_cache_ra_unbounded进入时触发的挂载点 int BPF_PROG(page_cache_ra_unbounded) diff --git a/eBPF_Supermarket/Stack_Analyser/bpf/template.bpf.c b/eBPF_Supermarket/Stack_Analyser/bpf/template.bpf.c index 8f741746f..108412609 100644 --- a/eBPF_Supermarket/Stack_Analyser/bpf/template.bpf.c +++ b/eBPF_Supermarket/Stack_Analyser/bpf/template.bpf.c @@ -21,7 +21,7 @@ #include #include -#include "sa_ebpf.h" +#include "ebpf.h" #include "bpf_wapper/template.h" #include "task.h" diff --git a/eBPF_Supermarket/Stack_Analyser/include/bpf_wapper/eBPFStackCollector.h b/eBPF_Supermarket/Stack_Analyser/include/bpf_wapper/eBPFStackCollector.h index 292225da1..ff07187c6 100644 --- a/eBPF_Supermarket/Stack_Analyser/include/bpf_wapper/eBPFStackCollector.h +++ b/eBPF_Supermarket/Stack_Analyser/include/bpf_wapper/eBPFStackCollector.h @@ -23,7 +23,7 @@ #include #include #include -#include "sa_user.h" +#include "user.h" struct Scale { @@ -62,7 +62,7 @@ class StackCollector uint32_t freq = 49; uint64_t cgroup = 0; uint32_t tgid = 0; - int err = 0; // 用于保存错误代码 + int err = 0; // 用于保存错误代码 bool ustack = false; // 是否跟踪用户栈 bool kstack = false; // 是否跟踪内核栈 @@ -94,25 +94,25 @@ class StackCollector /// @brief 加载、初始化参数并打开指定类型的ebpf程序 /// @param ... 一些ebpf程序全局变量初始化语句 /// @note 失败会使上层函数返回-1 -#define EBPF_LOAD_OPEN_INIT(...) \ - { \ - skel = skel->open(NULL); \ +#define EBPF_LOAD_OPEN_INIT(...) \ + { \ + skel = skel->open(NULL); \ CHECK_ERR_RN1(!skel, "Fail to open BPF skeleton"); \ - __VA_ARGS__; \ - skel->rodata->trace_user = ustack; \ - skel->rodata->trace_kernel = kstack; \ - skel->rodata->self_tgid = self_tgid; \ - skel->rodata->target_tgid = tgid; \ - skel->rodata->target_cgroupid = cgroup; \ - skel->rodata->freq = freq; \ - err = skel->load(skel); \ + __VA_ARGS__; \ + skel->rodata->trace_user = ustack; \ + skel->rodata->trace_kernel = kstack; \ + skel->rodata->self_tgid = self_tgid; \ + skel->rodata->target_tgid = tgid; \ + skel->rodata->target_cgroupid = cgroup; \ + skel->rodata->freq = freq; \ + err = skel->load(skel); \ CHECK_ERR_RN1(err, "Fail to load BPF skeleton"); \ - obj = skel->obj; \ + obj = skel->obj; \ } -#define ATTACH_PROTO \ - { \ - err = skel->attach(skel); \ +#define ATTACH_PROTO \ + { \ + err = skel->attach(skel); \ CHECK_ERR_RN1(err, "Failed to attach BPF skeleton"); \ } diff --git a/eBPF_Supermarket/Stack_Analyser/include/cgroup.h b/eBPF_Supermarket/Stack_Analyser/include/cgroup.h new file mode 100644 index 000000000..a9157a603 --- /dev/null +++ b/eBPF_Supermarket/Stack_Analyser/include/cgroup.h @@ -0,0 +1,9 @@ +#include +struct cgid_file_handle +{ + // struct file_handle handle; + unsigned int handle_bytes; + int handle_type; + uint64_t cgid; +}; +uint64_t get_cgroupid(const char *pathname); \ No newline at end of file diff --git a/eBPF_Supermarket/Stack_Analyser/include/sa_common.h b/eBPF_Supermarket/Stack_Analyser/include/common.h similarity index 83% rename from eBPF_Supermarket/Stack_Analyser/include/sa_common.h rename to eBPF_Supermarket/Stack_Analyser/include/common.h index 449f2f6c3..ad77f45e3 100644 --- a/eBPF_Supermarket/Stack_Analyser/include/sa_common.h +++ b/eBPF_Supermarket/Stack_Analyser/include/common.h @@ -27,22 +27,17 @@ #define CONTAINER_ID_LEN (128) /// @brief 栈计数的键,可以唯一标识一个用户内核栈 -typedef struct { +typedef struct +{ __u32 pid; __s32 ksid, usid; } psid; -typedef struct { +typedef struct +{ __u32 pid; __u32 tgid; char comm[COMM_LEN]; } task_info; -#define _COL_PREFIX "\033[" -#define _BLUE _COL_PREFIX "1;34m" -#define _GREEN _COL_PREFIX "1;32m" -#define _RED _COL_PREFIX "1;35m" -#define _ERED _COL_PREFIX "1;31m" -#define _RE _COL_PREFIX "0m" - #endif diff --git a/eBPF_Supermarket/Stack_Analyser/include/dt_elf.h b/eBPF_Supermarket/Stack_Analyser/include/dt_elf.h deleted file mode 100644 index a6174a376..000000000 --- a/eBPF_Supermarket/Stack_Analyser/include/dt_elf.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Linux内核诊断工具--elf相关函数头文件 - * - * Copyright (C) 2020 Alibaba Ltd. - * - * License terms: GNU General Public License (GPL) version 3 - * - */ - -#ifndef _PERF_ELF_H__ -#define _PERF_ELF_H__ - -#include -#include - -#include "dt_symbol.h" - -#define BUILD_ID_SIZE 40 -bool save_symbol_cache(std::set &ss, const char *path); -bool load_symbol_cache(std::set &ss, const char *path, const char *filename); - -bool get_symbol_from_elf(std::set &ss, const char *path); -bool search_symbol(const std::set &ss, symbol &sym); -int filename__read_build_id(int pid, const char *mnt_ns_name, const char *filename, char *bf, size_t size); -#endif diff --git a/eBPF_Supermarket/Stack_Analyser/include/dt_symbol.h b/eBPF_Supermarket/Stack_Analyser/include/dt_symbol.h deleted file mode 100644 index 3f2c3ffe9..000000000 --- a/eBPF_Supermarket/Stack_Analyser/include/dt_symbol.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Linux内核诊断工具--用户态符号表解析 - * - * Copyright (C) 2020 Alibaba Ltd. - * - * License terms: GNU General Public License (GPL) version 3 - * - */ - -#ifndef __PERF_SYMBOL_H__ -#define __PERF_SYMBOL_H__ - -#include -#include -#include - -//#include - -#define INVALID_ADDR ((size_t)(-1)) -enum { - NATIVE_TYPE = 0, - JIT_TYPE = 1, - UNKNOWN = 2, -}; - -struct elf_file { - unsigned char elf_read_error; - size_t eh_frame_hdr_offset; - size_t fde_count; - size_t table_data; - std::string filename; - int type; - - // TODO get builid from elf header or build hash for elf - elf_file(const std::string &name) : filename(name), type(NATIVE_TYPE) { - elf_read_error = 0; - eh_frame_hdr_offset = 0; - fde_count = 0; - table_data = 0; - } - - elf_file() :type(NATIVE_TYPE) {} - - // TODO get builid from elf header or build hash for elf - void reset(const std::string &name) { - filename = name; - elf_read_error = 0; - eh_frame_hdr_offset = 0; - fde_count = 0; - table_data = 0; - } - - bool operator< (const elf_file &rhs) const { - return filename < rhs.filename; - } -}; - -struct symbol { - size_t start; - size_t end; - size_t ip; - std::string name; - - symbol() :start(0), end(0), ip(0) {} - symbol(size_t pc) :start(0), end(0), ip(pc) {} - - void reset(size_t va) { start = end = 0; ip = va; } - bool operator< (const symbol &sym) const { - return sym.ip < start; - } - - bool operator> (const symbol &sym) const { - return sym.ip > end; - } -}; - -struct vma { - size_t start; - size_t end; - size_t offset; - size_t pc; - int type; - std::string name; - struct { - unsigned char elf_read_error; - size_t eh_frame_hdr_offset; - size_t fde_count; - size_t table_data; - }; - - size_t map(size_t pc) { - return pc - start + offset; - } - - void set_type(int t) { type = t; } - - vma(size_t s, size_t e, size_t o, const std::string &n) - :start(s), end(e), offset(o), pc(0), type(NATIVE_TYPE), name(n) {} - - vma() : start(0), end(0), offset(0), pc(0), type(NATIVE_TYPE) {} - - vma(size_t addr) : start(0), end(0), offset(0), pc(addr), type(NATIVE_TYPE) {} - - bool operator<(const vma &vm) { - return vm.start < vm.pc; - } - - vma &operator=(const vma &vm) { - if (this == &vm) { - return *this; - } - start = vm.start; - end = vm.end; - offset = vm.offset; - name = vm.name; - return *this; - } -}; - -static inline bool operator==(const vma &lhs, const vma &rhs) { - return lhs.start == rhs.start && lhs.end == rhs.end && lhs.name == rhs.name; -} - -class symbol_parser { -private: - typedef std::map proc_vma; - - std::map > file_symbols; - std::map > java_symbols; - std::set kernel_symbols; - std::map machine_vma; - std::set java_procs; - std::map > symbols_cache; -public: - bool load_kernel(); - std::set& get_java_procs() { return java_procs; } - - bool find_kernel_symbol(symbol &sym); - bool complete_kernel_symbol(symbol &sym); - - /// @brief 从elf file中查找sym中地址对应的符号名存入sym - /// @param sym 符号对象 - /// @param file 进程对应的elf file - /// @param pid 进程 - /// @param pid_ns 进程的命名空间? - /// @return 查找成功返回true,否则返回false - bool find_elf_symbol(symbol &sym, const elf_file &file, int pid, int pid_ns); - bool find_java_symbol(symbol &sym, int pid, int pid_ns); - - bool get_symbol_info(int pid, symbol &sym, elf_file &file); - - bool find_vma(pid_t pid, vma &vm); - vma* find_vma(pid_t pid, size_t pc); - void clear_symbol_info(int); - bool add_pid_maps(int pid, size_t start, size_t end, size_t offset, const char *name); - - bool find_symbol_in_cache(int tgid, unsigned long addr, std::string &symbol); - bool putin_symbol_cache(int tgid, unsigned long addr, std::string &symbol); - - void dump(void); -private: - bool load_pid_maps(int pid); - /// @brief 对elf_file对应的符号表进行缓存 -/// @param pid 未使用 -/// @param file elf file -/// @return 缓存成功返回true,否则返回false - bool load_elf(pid_t pid, const elf_file& file); - bool load_perf_map(int pid, int pid_ns); -public: - int java_only; - int user_symbol; -}; - -extern symbol_parser g_symbol_parser; - -std::string demangleCppSym(std::string symbol); -void clearSpace(std::string &sym); - -#endif diff --git a/eBPF_Supermarket/Stack_Analyser/include/sa_ebpf.h b/eBPF_Supermarket/Stack_Analyser/include/ebpf.h similarity index 91% rename from eBPF_Supermarket/Stack_Analyser/include/sa_ebpf.h rename to eBPF_Supermarket/Stack_Analyser/include/ebpf.h index 56ea5549d..84ee017f6 100644 --- a/eBPF_Supermarket/Stack_Analyser/include/sa_ebpf.h +++ b/eBPF_Supermarket/Stack_Analyser/include/ebpf.h @@ -19,7 +19,7 @@ #ifndef STACK_ANALYZER_EBPF #define STACK_ANALYZER_EBPF -#include "sa_common.h" +#include "common.h" #include #define PF_KTHREAD 0x00200000 @@ -39,13 +39,13 @@ /// @param name 新散列表的名字 /// @param type1 键的类型 /// @param type2 值的类型 -#define BPF_HASH(name, type1, type2) \ - struct \ - { \ - __uint(type, BPF_MAP_TYPE_HASH); \ - __uint(key_size, sizeof(type1)); \ - __uint(value_size, sizeof(type2)); \ - __uint(max_entries, MAX_ENTRIES); \ +#define BPF_HASH(name, _kt, _vt, _cap) \ + struct \ + { \ + __uint(type, BPF_MAP_TYPE_HASH); \ + __type(key, _kt); \ + __type(value, _vt); \ + __uint(max_entries, _cap); \ } name SEC(".maps") /** @@ -56,12 +56,12 @@ * pid_comm 存储 键值对,记录pid以及对应的命令名 * type:指定count值的类型 */ -#define COMMON_MAPS(count_type) \ - BPF_HASH(psid_count_map, psid, count_type); \ - BPF_STACK_TRACE(sid_trace_map); \ - BPF_HASH(tgid_cgroup_map, __u32, \ - char[CONTAINER_ID_LEN]); \ - BPF_HASH(pid_info_map, u32, task_info); +#define COMMON_MAPS(count_type) \ + BPF_HASH(psid_count_map, psid, count_type, MAX_ENTRIES); \ + BPF_STACK_TRACE(sid_trace_map); \ + BPF_HASH(tgid_cgroup_map, __u32, \ + char[CONTAINER_ID_LEN], MAX_ENTRIES / 100); \ + BPF_HASH(pid_info_map, u32, task_info, MAX_ENTRIES / 10); #define COMMON_VALS \ const volatile bool trace_user = false; \ @@ -123,7 +123,7 @@ (struct task_struct *)bpf_get_current_task() // 如果没有设置目标进程,则检查被采集进程是否为内核线程,是则退出采集 -#define CHECK_KTHREAD(_task) \ +#define CHECK_KTHREAD(_task) \ if (!target_tgid && BPF_CORE_READ(_task, flags) & PF_KTHREAD) \ return 0; diff --git a/eBPF_Supermarket/Stack_Analyser/include/trace_helpers.h b/eBPF_Supermarket/Stack_Analyser/include/trace.h similarity index 83% rename from eBPF_Supermarket/Stack_Analyser/include/trace_helpers.h rename to eBPF_Supermarket/Stack_Analyser/include/trace.h index 171bc4ee2..777248f94 100644 --- a/eBPF_Supermarket/Stack_Analyser/include/trace_helpers.h +++ b/eBPF_Supermarket/Stack_Analyser/include/trace.h @@ -4,9 +4,10 @@ #include -#define NSEC_PER_SEC 1000000000ULL +#define NSEC_PER_SEC 1000000000ULL -struct ksym { +struct ksym +{ const char *name; unsigned long addr; }; @@ -16,11 +17,12 @@ struct ksyms; struct ksyms *ksyms__load(void); void ksyms__free(struct ksyms *ksyms); const struct ksym *ksyms__map_addr(const struct ksyms *ksyms, - unsigned long addr); + unsigned long addr); const struct ksym *ksyms__get_symbol(const struct ksyms *ksyms, - const char *name); + const char *name); -struct sym { +struct sym +{ const char *name; unsigned long start; unsigned long size; @@ -30,11 +32,11 @@ struct sym { struct syms; struct syms *syms__load_pid(int tgid); -struct syms *syms__load_file(const char *fname); +struct syms *syms__load_file(const char *fname, int tgid); void syms__free(struct syms *syms); -const struct sym *syms__map_addr(const struct syms *syms, unsigned long addr); +struct sym *syms__map_addr(const struct syms *syms, unsigned long addr); const struct sym *syms__map_addr_dso(const struct syms *syms, unsigned long addr, - char **dso_name, unsigned long *dso_offset); + char **dso_name, unsigned long *dso_offset); struct syms_cache; @@ -42,7 +44,8 @@ struct syms_cache *syms_cache__new(int nr); struct syms *syms_cache__get_syms(struct syms_cache *syms_cache, int tgid); void syms_cache__free(struct syms_cache *syms_cache); -struct partition { +struct partition +{ char *name; unsigned int dev; }; @@ -58,7 +61,7 @@ partitions__get_by_name(const struct partitions *partitions, const char *name); void print_log2_hist(unsigned int *vals, int vals_size, const char *val_type); void print_linear_hist(unsigned int *vals, int vals_size, unsigned int base, - unsigned int step, const char *val_type); + unsigned int step, const char *val_type); unsigned long long get_ktime_ns(void); @@ -100,5 +103,11 @@ bool module_btf_exists(const char *mod); bool probe_tp_btf(const char *name); bool probe_ringbuf(); +const struct ksym *ksyms__find_symbol(const struct ksyms *ksyms, + const char *name); + +extern struct ksyms *ksyms; +extern struct syms_cache *syms_cache; +extern struct syms *syms; #endif /* __TRACE_HELPERS_H */ diff --git a/eBPF_Supermarket/Stack_Analyser/include/uprobe_helpers.h b/eBPF_Supermarket/Stack_Analyser/include/uprobe.h similarity index 100% rename from eBPF_Supermarket/Stack_Analyser/include/uprobe_helpers.h rename to eBPF_Supermarket/Stack_Analyser/include/uprobe.h diff --git a/eBPF_Supermarket/Stack_Analyser/include/sa_user.h b/eBPF_Supermarket/Stack_Analyser/include/user.h similarity index 97% rename from eBPF_Supermarket/Stack_Analyser/include/sa_user.h rename to eBPF_Supermarket/Stack_Analyser/include/user.h index b54352a6c..b46c53a76 100644 --- a/eBPF_Supermarket/Stack_Analyser/include/sa_user.h +++ b/eBPF_Supermarket/Stack_Analyser/include/user.h @@ -26,7 +26,14 @@ #include #include -#include "sa_common.h" +#include "common.h" + +#define _COL_PREFIX "\033[" +#define _BLUE _COL_PREFIX "1;34m" +#define _GREEN _COL_PREFIX "1;32m" +#define _RED _COL_PREFIX "1;35m" +#define _ERED _COL_PREFIX "1;31m" +#define _RE _COL_PREFIX "0m" #define PUT_ERR_REASON \ fprintf(stderr, _ERED " [%s]\n" _RE, strerror(errno)); @@ -49,7 +56,7 @@ /// @param info 要打印的错误信息 #define CHECK_ERR(action, cond, ...) \ if (cond) \ - DEAL_ERR(action, __VA_ARGS__) + DEAL_ERR(action, __VA_ARGS__) /// @brief 检查错误,若错误成立则打印带原因的错误信息并使上层函数返回-1 /// @param cond 被检查的条件表达式 @@ -67,4 +74,17 @@ #define COLLECTOR_INFO(_name) _BLUE "\b\b\b\bCollector for " _name " trace" _RE +inline void clearSpace(char *sym) +{ + for (char *p = sym; *p; p++) + { + if (*p != ' ') + { + *sym = *p; + sym++; + } + } + *sym = '\0'; +} + #endif diff --git a/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/eBPFStackCollector.cpp b/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/eBPFStackCollector.cpp index d3aa81547..2f99dcc35 100644 --- a/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/eBPFStackCollector.cpp +++ b/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/eBPFStackCollector.cpp @@ -17,14 +17,15 @@ // 包装用于采集调用栈数据的eBPF程序,规定一些抽象接口和通用变量 #include "bpf_wapper/eBPFStackCollector.h" -#include "sa_user.h" -#include "dt_symbol.h" +#include "user.h" +#include "trace.h" #include #include #include #include #include +#include std::string getLocalDateTime(void) { @@ -142,39 +143,36 @@ StackCollector::operator std::string() auto trace_fd = bpf_object__find_map_fd_by_name(obj, "sid_trace_map"); if (id.usid > 0 && traces.find(id.usid) == traces.end()) { - bpf_map_lookup_elem(trace_fd, &id.usid, trace); - for (p = trace + MAX_STACKS - 1; !*p; p--) - ; - std::vector sym_trace(p - trace + 1); - for (int i = 0; p >= trace; p--) + syms = syms_cache__get_syms(syms_cache, id.pid); + if (!syms) + fprintf(stderr, "failed to get syms\n"); + else { - uint64_t &addr = *p; - symbol sym; - sym.reset(addr); - elf_file file; - if (g_symbol_parser.find_symbol_in_cache(id.pid, addr, sym.name)) + bpf_map_lookup_elem(trace_fd, &id.usid, trace); + for (p = trace + MAX_STACKS - 1; !*p; p--) ; - else if (g_symbol_parser.get_symbol_info(id.pid, sym, file) && g_symbol_parser.find_elf_symbol(sym, file, id.pid, id.pid)) - { - if (sym.name[0] == '_' && sym.name[1] == 'Z') - // 代表是C++符号,则调用demangle解析 - sym.name = demangleCppSym(sym.name); - std::stringstream ss(""); - ss << "+0x" << std::hex << (sym.ip - sym.start); - sym.name += ss.str(); - clearSpace(sym.name); - g_symbol_parser.putin_symbol_cache(id.pid, addr, sym.name); - } - else + std::vector sym_trace(p - trace + 1); + for (int i = 0; p >= trace; p--) { - std::stringstream ss(""); - ss << "0x" << std::hex << sym.ip; - sym.name = ss.str(); - g_symbol_parser.putin_symbol_cache(id.pid, addr, sym.name); + struct sym *sym = syms__map_addr(syms, *p); + if (sym) + { + if (sym->name[0] == '_' && sym->name[1] == 'Z') + { + char *demangled = abi::__cxa_demangle(sym->name, NULL, NULL, NULL); + if (demangled) + { + clearSpace(demangled); + sym->name = demangled; + } + } + sym_trace[i++] = std::string(sym->name) + "+" + std::to_string(sym->offset); + } + else + sym_trace[i++] = "[unknown]"; } - sym_trace[i++] = sym.name; + traces[id.usid] = sym_trace; } - traces[id.usid] = sym_trace; } if (id.ksid > 0 && traces.find(id.ksid) == traces.end()) { @@ -184,22 +182,9 @@ StackCollector::operator std::string() std::vector sym_trace(p - trace + 1); for (int i = 0; p >= trace; p--) { - uint64_t &addr = *p; - symbol sym; - sym.reset(addr); - std::stringstream ss(""); - if (g_symbol_parser.find_kernel_symbol(sym)) - { - ss << "+0x" << std::hex << (sym.ip - sym.start); - sym.name += ss.str(); - clearSpace(sym.name); - } - else - { - ss << "0x" << std::hex << addr; - sym.name = ss.str(); - } - sym_trace[i++] = sym.name; + const struct ksym *ksym = ksyms__map_addr(ksyms, *p); + sym_trace[i++] = ksym ? std::string(ksym->name) + "+" + std::to_string(*p - ksym->addr) + : "[unknown]"; } traces[id.ksid] = sym_trace; } diff --git a/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/memleak.cpp b/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/memleak.cpp index 9a9c5ae1f..d8224de6d 100644 --- a/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/memleak.cpp +++ b/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/memleak.cpp @@ -17,7 +17,7 @@ // mem ebpf程序的包装类,实现接口和一些自定义方法 #include "bpf_wapper/memleak.h" -#include "trace_helpers.h" +#include "trace.h" #include uint64_t *MemleakStackCollector::count_values(void *d) diff --git a/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/off_cpu.cpp b/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/off_cpu.cpp index 1d9411b3d..d1cd1d9ba 100644 --- a/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/off_cpu.cpp +++ b/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/off_cpu.cpp @@ -17,7 +17,7 @@ // off cpu ebpf程序的包装类,实现接口和一些自定义方法 #include "bpf_wapper/off_cpu.h" -#include "dt_symbol.h" +#include "trace.h" OffCPUStackCollector::OffCPUStackCollector() { @@ -37,13 +37,11 @@ uint64_t *OffCPUStackCollector::count_values(void *data) int OffCPUStackCollector::ready(void) { EBPF_LOAD_OPEN_INIT(); - symbol sym; - sym.name = "finish_task_switch"; - if (!g_symbol_parser.complete_kernel_symbol(sym)) - { + const char *name = "finish_task_switch"; + const struct ksym *ksym = ksyms__find_symbol(ksyms, name); + if (!ksym) return -1; - } - skel->links.do_stack = bpf_program__attach_kprobe(skel->progs.do_stack, false, sym.name.c_str()); + skel->links.do_stack = bpf_program__attach_kprobe(skel->progs.do_stack, false, ksym->name); return 0; } diff --git a/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/probe.cpp b/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/probe.cpp index 2fa9e0b67..6b720c6b8 100644 --- a/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/probe.cpp +++ b/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/probe.cpp @@ -17,8 +17,8 @@ // ebpf程序包装类的模板,实现接口和一些自定义方法 #include "bpf_wapper/probe.h" -#include "trace_helpers.h" -#include "uprobe_helpers.h" +#include "trace.h" +#include "uprobe.h" void splitStr(const std::string &symbol, const char split, std::vector &res) { diff --git a/eBPF_Supermarket/Stack_Analyser/src/cgroup.cpp b/eBPF_Supermarket/Stack_Analyser/src/cgroup.cpp new file mode 100644 index 000000000..fb6b4ad79 --- /dev/null +++ b/eBPF_Supermarket/Stack_Analyser/src/cgroup.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include +#include +#include "cgroup.h" + +uint64_t get_cgroupid(const char *pathname) +{ + struct statfs fs; + int err; + struct cgid_file_handle *h; + int mount_id; + uint64_t ret; + + err = statfs(pathname, &fs); + if (err != 0) + { + fprintf(stderr, "statfs on %s failed: %s\n", pathname, strerror(errno)); + exit(1); + } + + if ((fs.f_type != (typeof(fs.f_type))CGROUP2_SUPER_MAGIC)) + { + fprintf(stderr, "File %s is not on a cgroup2 mount.\n", pathname); + exit(1); + } + + h = (cgid_file_handle *)malloc(sizeof(struct cgid_file_handle)); + if (!h) + { + fprintf(stderr, "Cannot allocate memory.\n"); + exit(1); + } + + h->handle_bytes = 8; + err = name_to_handle_at(AT_FDCWD, pathname, (struct file_handle *)h, &mount_id, 0); + if (err != 0) + { + fprintf(stderr, "name_to_handle_at failed: %s\n", strerror(errno)); + exit(1); + } + + if (h->handle_bytes != 8) + { + fprintf(stderr, "Unexpected handle size: %d. \n", h->handle_bytes); + exit(1); + } + + ret = h->cgid; + free(h); + + return ret; +} \ No newline at end of file diff --git a/eBPF_Supermarket/Stack_Analyser/src/dt_elf.cpp b/eBPF_Supermarket/Stack_Analyser/src/dt_elf.cpp deleted file mode 100644 index d040e8936..000000000 --- a/eBPF_Supermarket/Stack_Analyser/src/dt_elf.cpp +++ /dev/null @@ -1,621 +0,0 @@ -/* - * Linux内核诊断工具--elf相关公共函数 - * - * Copyright (C) 2020 Alibaba Ltd. - * - * License terms: GNU General Public License (GPL) version 3 - * - */ -#include "dt_elf.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NOTE_ALIGN(n) (((n) + 3) & -4U) - -struct sym_section_ctx -{ - Elf_Data *syms; - Elf_Data *symstrs; - Elf_Data *rel_data; - int is_reloc; - int is_plt; - int sym_count; - int plt_rel_type; - unsigned long plt_offset; - unsigned long plt_entsize; -}; - -struct symbol_sections_ctx -{ - sym_section_ctx symtab; - sym_section_ctx symtab_in_dynsym; - sym_section_ctx dynsymtab; -}; - -struct section_info -{ - Elf_Scn *sec; - GElf_Shdr *hdr; -}; - -struct plt_ctx -{ - section_info dynsym; - section_info plt_rel; - section_info plt; -}; - -__attribute__((unused)) static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, - GElf_Shdr *shp, const char *name, - size_t *idx) -{ - Elf_Scn *sec = NULL; - size_t cnt = 1; - - /* Elf is corrupted/truncated, avoid calling elf_strptr. */ - if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) - return NULL; - - while ((sec = elf_nextscn(elf, sec)) != NULL) - { - char *str; - - gelf_getshdr(sec, shp); - str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); - - if (!strcmp(name, str)) - { - if (idx) - *idx = cnt; - - break; - } - - ++cnt; - } - - return sec; -} - -__attribute__((unused)) static int elf_read_build_id(Elf *elf, char *bf, size_t size) -{ - int err = -1; - GElf_Ehdr ehdr; - GElf_Shdr shdr; - Elf_Data *data; - Elf_Scn *sec; - Elf_Kind ek; - char *ptr; - - if (size < BUILD_ID_SIZE) - goto out; - - ek = elf_kind(elf); - - if (ek != ELF_K_ELF) - goto out; - - if (gelf_getehdr(elf, &ehdr) == NULL) - { - fprintf(stderr, "%s: cannot get elf header.\n", __func__); - goto out; - } - - /* - * Check following sections for notes: - * '.note.gnu.build-id' - * '.notes' - * '.note' (VDSO specific) - */ - do - { - sec = elf_section_by_name(elf, &ehdr, &shdr, - ".note.gnu.build-id", NULL); - - if (sec) - break; - - sec = elf_section_by_name(elf, &ehdr, &shdr, - ".notes", NULL); - - if (sec) - break; - - sec = elf_section_by_name(elf, &ehdr, &shdr, - ".note", NULL); - - if (sec) - break; - - return err; - - } while (0); - - data = elf_getdata(sec, NULL); - - if (data == NULL) - goto out; - - ptr = (char *)data->d_buf; - - while ((intptr_t)ptr < (intptr_t)((char *)data->d_buf + data->d_size)) - { - GElf_Nhdr *nhdr = (GElf_Nhdr *)ptr; - size_t namesz = NOTE_ALIGN(nhdr->n_namesz), - descsz = NOTE_ALIGN(nhdr->n_descsz); - const char *name; - - ptr += sizeof(*nhdr); - name = (const char *)ptr; - ptr += namesz; - - if (nhdr->n_type == NT_GNU_BUILD_ID && - nhdr->n_namesz == sizeof("GNU")) - { - if (memcmp(name, "GNU", sizeof("GNU")) == 0) - { - size_t sz = size < descsz ? size : descsz; - memcpy(bf, ptr, sz); - memset(bf + sz, 0, size - sz); - err = descsz; - break; - } - } - - ptr += descsz; - } - -out: - return err; -} - -extern int calc_sha1_1M(const char *filename, unsigned char *buf); - -int filename__read_build_id(int pid, const char *mnt_ns_name, const char *filename, char *bf, size_t size) -{ - int fd, err = -1; - struct stat sb; - - if (size < BUILD_ID_SIZE) - goto out; - - fd = open(filename, O_RDONLY); - - if (fd < 0) - goto out; - - if (fstat(fd, &sb) == 0) - { - snprintf(bf, size, "%s[%lu]", filename, sb.st_size); - err = 0; - } - - close(fd); -out: - return err; -} - -static int is_function(const GElf_Sym *sym) -{ - return GELF_ST_TYPE(sym->st_info) == STT_FUNC && - sym->st_name != 0 && - sym->st_shndx != SHN_UNDEF; -} - -static int get_symbols_in_section(sym_section_ctx *sym, Elf *elf, Elf_Scn *sec, GElf_Shdr *shdr, int is_reloc) -{ - sym->syms = elf_getdata(sec, NULL); - if (!sym->syms) - { - return -1; - } - - Elf_Scn *symstrs_sec = elf_getscn(elf, shdr->sh_link); - if (!sec) - { - return -1; - } - - sym->symstrs = elf_getdata(symstrs_sec, NULL); - if (!sym->symstrs) - { - return -1; - } - - sym->sym_count = shdr->sh_size / shdr->sh_entsize; - sym->is_plt = 0; - sym->is_reloc = is_reloc; - - return 0; -} - -static int get_plt_symbols_in_section(sym_section_ctx *sym, Elf *elf, plt_ctx *plt) -{ - sym->syms = elf_getdata(plt->dynsym.sec, NULL); - if (!sym->syms) - { - return -1; - } - - sym->rel_data = elf_getdata(plt->plt_rel.sec, NULL); - if (!sym->rel_data) - { - return -1; - } - - Elf_Scn *symstrs_sec = elf_getscn(elf, plt->dynsym.hdr->sh_link); - if (!symstrs_sec) - { - return -1; - } - - sym->symstrs = elf_getdata(symstrs_sec, NULL); - if (!sym->symstrs) - { - return -1; - } - - sym->is_plt = 1; - sym->plt_entsize = plt->plt.hdr->sh_type; - sym->plt_offset = plt->plt.hdr->sh_offset; - sym->sym_count = plt->plt_rel.hdr->sh_size / plt->plt_rel.hdr->sh_entsize; - sym->plt_rel_type = plt->plt_rel.hdr->sh_type; - - return 0; -} - -static void __get_plt_symbol(std::set &ss, symbol_sections_ctx *si, Elf *elf) -{ - symbol s; - GElf_Sym sym; - int symidx; - int index = 0; - const char *sym_name = NULL; - - s.end = 0; - s.start = 0; - - if (!si->dynsymtab.syms) - { - return; - } - - while (index < si->dynsymtab.sym_count) - { - if (si->dynsymtab.plt_rel_type == SHT_RELA) - { - GElf_Rela pos_mem, *pos; - pos = gelf_getrela(si->dynsymtab.rel_data, index, &pos_mem); - symidx = GELF_R_SYM(pos->r_info); - } - else if (si->dynsymtab.plt_rel_type == SHT_REL) - { - GElf_Rel pos_mem, *pos; - pos = gelf_getrel(si->dynsymtab.rel_data, index, &pos_mem); - symidx = GELF_R_SYM(pos->r_info); - } - else - { - return; - } - index++; - si->dynsymtab.plt_offset += si->dynsymtab.plt_entsize; - gelf_getsym(si->dynsymtab.syms, symidx, &sym); - - sym_name = (const char *)si->dynsymtab.symstrs->d_buf + sym.st_name; - s.start = si->dynsymtab.plt_offset; - s.end = s.start + si->dynsymtab.plt_entsize; - s.ip = s.start; - s.name = sym_name; - ss.insert(s); - } -} - -static void __get_symbol_without_plt(std::set &ss, sym_section_ctx *tab, Elf *elf) -{ - GElf_Sym sym; - int index = 0; - const char *sym_name; - symbol s; - s.end = 0; - s.start = 0; - - while (index < tab->sym_count) - { - gelf_getsym(tab->syms, index, &sym); - index++; - if (sym.st_shndx == SHN_ABS) - { - continue; - } - if (!is_function(&sym)) - { - continue; - } - sym_name = (const char *)tab->symstrs->d_buf + sym.st_name; - if (tab->is_reloc) - { - Elf_Scn *sec = elf_getscn(elf, sym.st_shndx); - if (!sec) - { - continue; - } - GElf_Shdr shdr; - gelf_getshdr(sec, &shdr); - sym.st_value -= shdr.sh_addr - shdr.sh_offset; - } - s.start = sym.st_value & 0xffffffff; - s.end = s.start + sym.st_size; - s.ip = s.start; - s.name = sym_name; - ss.insert(s); - } -} - -static void __get_symbol(std::set &ss, symbol_sections_ctx *si, Elf *elf) -{ - symbol s; - s.end = 0; - s.start = 0; - - if (!si->symtab.syms && !si->dynsymtab.syms) - { - return; - } - - sym_section_ctx *tab = &si->symtab; - __get_symbol_without_plt(ss, tab, elf); - tab = &si->symtab_in_dynsym; - __get_symbol_without_plt(ss, tab, elf); -} - -static void get_all_symbols(std::set &ss, symbol_sections_ctx *si, Elf *elf) -{ - __get_symbol(ss, si, elf); - __get_plt_symbol(ss, si, elf); -} - -bool search_symbol(const std::set &ss, symbol &sym) -{ - std::set::const_iterator it = ss.find(sym); - - if (it != ss.end()) - { - sym.end = it->end; - sym.start = it->start; - sym.name = it->name; - - return true; - } - - return false; -} - -bool get_symbol_from_elf(std::set &ss, const char *path) -{ - // static int first_init = 0; - - // if (!first_init) { - // first_init = true; - // init_global_env(); - // } - - int is_reloc = 0; - elf_version(EV_CURRENT); - int fd = open(path, O_RDONLY); - - Elf *elf = elf_begin(fd, ELF_C_READ, NULL); - if (elf == NULL) - { - close(fd); - return false; - } - - Elf_Kind ek = elf_kind(elf); - if (ek != ELF_K_ELF) - { - elf_end(elf); - close(fd); - return false; - } - GElf_Ehdr hdr; - if (gelf_getehdr(elf, &hdr) == NULL) - { - elf_end(elf); - close(fd); - return false; - } - - if (hdr.e_type == ET_EXEC) - { - is_reloc = 1; - } - - if (!elf_rawdata(elf_getscn(elf, hdr.e_shstrndx), NULL)) - { - elf_end(elf); - close(fd); - return false; - } - - GElf_Shdr shdr; - GElf_Shdr symtab_shdr; - GElf_Shdr dynsym_shdr; - GElf_Shdr plt_shdr; - GElf_Shdr plt_rel_shdr; - memset(&shdr, 0, sizeof(shdr)); - memset(&symtab_shdr, 0, sizeof(symtab_shdr)); - memset(&dynsym_shdr, 0, sizeof(dynsym_shdr)); - memset(&plt_shdr, 0, sizeof(plt_shdr)); - memset(&plt_rel_shdr, 0, sizeof(plt_rel_shdr)); - - Elf_Scn *sec = NULL; - Elf_Scn *dynsym_sec = NULL; - Elf_Scn *symtab_sec = NULL; - Elf_Scn *plt_sec = NULL; - Elf_Scn *plt_rel_sec = NULL; - - while ((sec = elf_nextscn(elf, sec)) != NULL) - { - char *str; - gelf_getshdr(sec, &shdr); - str = elf_strptr(elf, hdr.e_shstrndx, shdr.sh_name); - - if (str && strcmp(".symtab", str) == 0) - { - symtab_sec = sec; - memcpy(&symtab_shdr, &shdr, sizeof(dynsym_shdr)); - } - if (str && strcmp(".dynsym", str) == 0) - { - dynsym_sec = sec; - memcpy(&dynsym_shdr, &shdr, sizeof(dynsym_shdr)); - } - if (str && strcmp(".rela.plt", str) == 0) - { - plt_rel_sec = sec; - memcpy(&plt_rel_shdr, &shdr, sizeof(plt_rel_shdr)); - } - if (str && strcmp(".plt", str) == 0) - { - plt_sec = sec; - memcpy(&plt_shdr, &shdr, sizeof(plt_shdr)); - } - if (str && strcmp(".gnu.prelink_undo", str) == 0) - { - is_reloc = 1; - } - } - - plt_ctx plt; - plt.dynsym.hdr = &dynsym_shdr; - plt.dynsym.sec = dynsym_sec; - plt.plt.hdr = &plt_shdr; - plt.plt.sec = plt_sec; - plt.plt_rel.hdr = &plt_rel_shdr; - plt.plt_rel.sec = plt_rel_sec; - - symbol_sections_ctx si; - memset(&si, 0, sizeof(si)); - if (symtab_sec) - { - get_symbols_in_section(&si.symtab, elf, symtab_sec, &symtab_shdr, is_reloc); - } - if (dynsym_sec) - { - get_symbols_in_section(&si.symtab_in_dynsym, elf, dynsym_sec, &dynsym_shdr, is_reloc); - } - if (dynsym_sec && plt_sec) - { - get_plt_symbols_in_section(&si.dynsymtab, elf, &plt); - } - - get_all_symbols(ss, &si, elf); - elf_end(elf); - close(fd); - return true; -} - -struct symbol_cache_item -{ - int start; - int size; - char name[0]; -}; - -bool save_symbol_cache(std::set &ss, const char *path) -{ - char buf[2048]; - int len = 0; - bool status = true; - - int fd = open(path, O_RDONLY); - if (fd < 0) - { - status = false; - return status; - } - int ret; - ret = read(fd, &len, 4); - if (ret <= 0) - { - close(fd); - status = false; - return status; - } - ret = read(fd, buf, len); - if (ret <= 0) - { - close(fd); - status = false; - return status; - } - - while (1) - { - struct symbol_cache_item *sym; - symbol s; - ret = read(fd, &len, 4); - if (ret <= 0) - { - status = false; - break; - } - ret = read(fd, buf, len); - if (ret < len) - { - status = false; - break; - } - sym = (struct symbol_cache_item *)buf; - s.start = sym->start; - s.end = sym->start + sym->size; - s.ip = sym->start; - s.name = sym->name; - ss.insert(s); - } - close(fd); - return status; -} - -bool load_symbol_cache(std::set &ss, const char *path, const char *filename) -{ - int fd = open(path, O_RDWR | O_EXCL); - if (fd < 0) - { - return false; - } - int len = strlen(filename); - int ret = write(fd, &len, 4); - if (ret < 0) - { - close(fd); - return false; - } - ret = write(fd, filename, len); - if (ret < 0) - { - close(fd); - return false; - } - - std::set::iterator it; - int v; - for (it = ss.begin(); it != ss.end(); ++it) - { - v = it->start; - ret = write(fd, &v, 4); - v = it->end - it->start; - ret = write(fd, &v, 4); - ret = write(fd, it->name.c_str(), it->name.length()); - } - return true; -} diff --git a/eBPF_Supermarket/Stack_Analyser/src/dt_symbol.cpp b/eBPF_Supermarket/Stack_Analyser/src/dt_symbol.cpp deleted file mode 100644 index 07bb4fba6..000000000 --- a/eBPF_Supermarket/Stack_Analyser/src/dt_symbol.cpp +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Linux内核诊断工具--用户态符号表解析 - * - * Copyright (C) 2020 Alibaba Ltd. - * - * License terms: GNU General Public License (GPL) version 3 - * - */ - -#include -#include -#include -#include - -#include "dt_symbol.h" -#include "dt_elf.h" - -void restore_global_env(); -int attach_ns_env(int pid); - -symbol_parser g_symbol_parser; -const bool debug_mode = false; - -bool symbol_parser::add_pid_maps(int pid, size_t start, size_t end, size_t offset, const char *name) -{ - std::map::iterator it; - it = machine_vma.find(pid); - if (it == machine_vma.end()) { - proc_vma proc; - machine_vma.insert(make_pair(pid, proc)); - it = machine_vma.find(pid); - if (it == machine_vma.end()) { - return false; - } - } - - vma vm(start, end, offset, name); - it->second.insert(std::make_pair(vm.start, std::move(vm))); - - return true; -} - -bool symbol_parser::load_pid_maps(int pid) -{ - std::map::iterator it; - it = machine_vma.find(pid); - if (it != machine_vma.end()) { - return true; - } - - proc_vma proc; - char fn[23]; - sprintf(fn, "/proc/%d/maps", pid); - FILE *fp = fopen(fn, "r"); - if (!fp) { - return false; - } - - char buf[4096]; - char exename[4096]; - size_t start, end, offset; - while (fgets(buf, sizeof(buf), fp) != NULL) { - start = end = offset = 0; - exename[0] = '\0'; - sscanf(buf, "%lx-%lx %*s %lx %*x:%*x %*u %s %*s\n", &start, &end, &offset, exename); - if (exename[0] == '\0') { - strcpy(exename, "[anon]"); - } - vma vm(start, end, offset, exename); - proc.insert(std::make_pair(vm.start, std::move(vm))); - } - - fclose(fp); - - machine_vma.insert(std::make_pair(pid, std::move(proc))); - it = machine_vma.find(pid); - if (it == machine_vma.end()) { - return false; - } - - return true; -} - -bool symbol_parser::load_perf_map(int pid, int pid_ns) -{ -#if 0 - if (pid != pid_ns) { - if (attach_ns_env(pid) < 0) { - return false; - } - } -#endif - char perfmapfile[64]; - snprintf(perfmapfile, sizeof(perfmapfile), "/tmp/perf-%d.map", pid); - FILE *fp = fopen(perfmapfile, "r"); - if (fp == NULL) { - if (debug_mode) { - printf("cannot read perf map %d\n", pid); - } - return false; - } - char line[256]; - char *buf; - long start; - int size; - char name[256]; - std::set syms; - symbol sym; - while ((buf = fgets(line, sizeof(line), fp)) != NULL) { - sscanf(buf, "%lx %x %s\n", &start, &size, name); - sym.start = start; - sym.end = sym.start + size; - sym.ip = sym.start; - sym.name = name; - syms.insert(sym); - } - java_symbols.insert(make_pair(pid, std::move(syms))); -#if 0 - if (pid != pid_ns) { - restore_global_env(); - } -#endif - return true; -} - -bool symbol_parser::find_java_symbol(symbol &sym, int pid, int pid_ns) -{ - std::set ss; - std::map >::iterator it; - //bool load_now = false; - it = java_symbols.find(pid); - if (it == java_symbols.end()) { - if (!load_perf_map(pid, pid_ns)) { - return false; - } - //load_now = true; - it = java_symbols.find(pid); - return search_symbol(it->second, sym); - } else { - return search_symbol(it->second, sym); - } - return true; - - //bool ret = search_symbol(syms, sym); -#if 0 - if (!ret && !load_now) { - java_symbols.erase(pid); - if (!load_perf_map(pid)) { - return false; - } - syms = java_symbols.find(pid)->second; - return search_symbol(syms, sym); - } -#endif - //return ret; -} - -static bool load_kernel_symbol_list(std::vector &sym_list) -{ - FILE *fp = fopen("/proc/kallsyms", "r"); - if (!fp) { - return -1; - } - - char buf[256]; - char type; - int len; - while (fgets(buf, sizeof(buf), fp) != NULL) { - sscanf(buf, "%*p %c %*s\n", &type); - if ((type | 0x20) != 't') { - continue; - } - len = strlen(buf); - if (buf[len-1] == '\n') { - buf[len-1] = '\0'; - } - sym_list.push_back(buf); - } - fclose(fp); - - std::sort(sym_list.begin(), sym_list.end()); - return true; -} - -bool is_space(int ch) { - return std::isspace(ch); -} - -static inline void rtrim(std::string &s) -{ - s.erase(std::find_if(s.rbegin(), s.rend(), is_space).base(), s.end()); -} - -static bool get_next_kernel_symbol( - std::set &syms, - std::vector &sym_list, - std::vector::iterator cursor) -{ - if (cursor == sym_list.end()) { - return false; - } - symbol sym; - size_t start, end; - sscanf(cursor->c_str(), "%p %*c %*s\n", (void **)&start); - sym.name = cursor->c_str() + 19; - // rtrim(sym.name); -// #if 0 - // if (sym.name[sym.name.size()-1] == ' ') { - // // sym.name[sym.name.size()-1] = '\0'; - // sym.name.pop_back(); - // } -// #endif - cursor++; - if (cursor != sym_list.end()) { - sscanf(cursor->c_str(), "%p %*c %*s\n", (void **)&end); - } - else { - end = INVALID_ADDR; - } - sym.start = start; - sym.end = end; - sym.ip = start; - - syms.insert(sym); - return true; -} - -bool symbol_parser::load_kernel() -{ - if (kernel_symbols.size() != 0) { - return true; - } - - std::vector sym_list; - if (!load_kernel_symbol_list(sym_list)) { - exit(0); - return false; - } - - std::vector::iterator cursor = sym_list.begin(); - while (get_next_kernel_symbol(kernel_symbols, sym_list, cursor)) { - cursor++; - } - return true; -} - -bool symbol_parser::load_elf(pid_t pid, const elf_file &file) -{ - std::map >::iterator it; - it = file_symbols.find(file); - std::set tmp; - std::set &syms = tmp; - if (it != file_symbols.end()) { - return true; - } - if (get_symbol_from_elf(syms, file.filename.c_str())) { - file_symbols.insert(make_pair(file, std::move(syms))); - return true; - } - return false; -} - -bool symbol_parser::find_kernel_symbol(symbol &sym) -{ - load_kernel(); - sym.end = sym.start = 0; - std::set::iterator it = kernel_symbols.find(sym); - if (it != kernel_symbols.end()) { - sym.end = it->end; - sym.start = it->start; - sym.name = it->name; - return true; - } - return false; -} - -bool symbol_parser::complete_kernel_symbol(symbol &sym) -{ - load_kernel(); - sym.end = sym.start = 0; - for (auto it = kernel_symbols.begin(); it != kernel_symbols.end(); ++it) { - auto size = sym.name.size(), tsize = it->name.size(); - if(size > tsize || it->name.substr(tsize-5, 5) == ".cold") { - continue; - } - if(it->name.substr(0, size) == sym.name) { - sym.end = it->end; - sym.start = it->start; - sym.name = it->name; - return true; - } - } - return false; -} - -bool symbol_parser::find_symbol_in_cache(int tgid, unsigned long addr, std::string &symbol) -{ - std::map >::const_iterator it_pid = - symbols_cache.find(tgid); - - if (it_pid != symbols_cache.end()) { - std::map map = symbols_cache[tgid]; - std::map::const_iterator it_symbol = - map.find(addr); - - if (it_symbol != map.end()) { - symbol = map[addr]; - - return true; - } - } - - return false; -} - -bool symbol_parser::putin_symbol_cache(int tgid, unsigned long addr, std::string &symbol) -{ - std::map >::const_iterator it_pid = - symbols_cache.find(tgid); - - if (it_pid == symbols_cache.end()) { - std::map map; - symbols_cache.insert(std::make_pair(tgid, map)); - } - - std::map &map = symbols_cache[tgid]; - std::map::const_iterator it_symbol = - map.find(addr); - - if (it_symbol == map.end()) { - map[addr] = symbol; - return true; - } - - return false; -} - -/// @brief 找到指定进程中的虚拟地址对应的在可执行文件中相对于文件开始的偏移,赋给sym.ip -/// @param pid 指定进程的pid -/// @param sym 提供进程虚拟地址 -/// @param file 文件信息 -/// @return 成功找到返回true -bool symbol_parser::get_symbol_info(int pid, symbol &sym, elf_file &file) -{ - std::map::iterator proc_vma_info; - - if (java_only) { - file.type = UNKNOWN; - return true; - } - - proc_vma_info = machine_vma.find(pid); - if (proc_vma_info == machine_vma.end()) { - if (!load_pid_maps(pid)) { - if (debug_mode) { - printf("load pid maps failed\n"); - } - return false; - } - } - - vma area(sym.ip); - if (!find_vma(pid, area)) { - if (debug_mode) { - printf("find vma failed\n"); - } - return false; - } - if (area.name == "[anon]") { - file.type = JIT_TYPE; - } - - file.reset(area.name); - if (file.type != JIT_TYPE) { - sym.reset(area.map(sym.ip)); - } - - return true; -} - -bool symbol_parser::find_elf_symbol(symbol &sym, const elf_file &file, int pid, int pid_ns) -{ - if (java_only) { - return find_java_symbol(sym, pid, pid_ns); - } - - if (file.type == JIT_TYPE) { - return find_java_symbol(sym, pid, pid_ns); - } - - std::map >::iterator it; - it = file_symbols.find(file); - std::set ss; - if (it == file_symbols.end()) { - if (!load_elf(pid, file)) { - return false; - } - it = file_symbols.find(file); - } - return search_symbol(it->second, sym); -} - -vma* symbol_parser::find_vma(pid_t pid, size_t pc) -{ - std::map::iterator it; - - it = machine_vma.find(pid); - if (it == machine_vma.end()) { - return NULL; - } - - proc_vma::iterator vma_iter = it->second.upper_bound(pc); - if (vma_iter == it->second.end() || vma_iter->second.end < pc) { - return NULL; - } - - if (vma_iter != it->second.begin()) { - --vma_iter; - } - - return &vma_iter->second; -} - -bool symbol_parser::find_vma(pid_t pid, vma &vm) -{ - std::map::iterator proc_vma_map; - - proc_vma_map = machine_vma.find(pid); - if (proc_vma_map == machine_vma.end()) { - return false; - } - - proc_vma::const_iterator vma_iter = proc_vma_map->second.upper_bound(vm.pc); - if (vma_iter == proc_vma_map->second.end()) { - return false; - } - if (vma_iter->second.end < vm.pc) { - return false; - } - - if (vma_iter != proc_vma_map->second.begin()) { - --vma_iter; - } - - vm.start = vma_iter->second.start; - vm.end = vma_iter->second.end; - vm.name = "/proc/" + std::to_string(pid) + "/root/" + vma_iter->second.name; - vm.offset = vma_iter->second.offset; - - return true; -} - -class pid_cmdline { - private: - std::map cmdlines; - public: - void clear(void); - std::string & get_pid_cmdline(int pid); -}; - -void pid_cmdline::clear(void) -{ - cmdlines.clear(); -} - -void clear_symbol_info(class pid_cmdline &pid_cmdline, std::set &procs, int dist) -{ - pid_cmdline.clear(); - procs.clear(); - g_symbol_parser.clear_symbol_info(dist); -} - -void symbol_parser::clear_symbol_info(int dist) -{ - machine_vma.clear(); - java_symbols.clear(); - if (dist) { - kernel_symbols.clear(); - file_symbols.clear(); - } -} - -void symbol_parser::dump(void) -{ - int count1, count2, count3; - - if (!debug_mode) - return; - - { - count1 = 0; - count2 = 0; - count3 = 0; - std::map >::iterator iter = file_symbols.begin(); - for(; iter != file_symbols.end(); ++iter) { - std::set& map = iter->second; - const elf_file& file = iter->first; - - count1++; - printf("xby-debug, file_symbols: %s, %lu\n", - file.filename.c_str(), - map.size()); - - count2 += map.size(); - std::set::iterator it = map.begin(); - for(; it != map.end(); ++it) { - count3 += it->name.length(); - } - } - printf("xby-debug, file_symbols: %d, %d, %d\n", count1, count2, count3); - printf("xby-debug, sizeof(symbol): %ld\n", sizeof(symbol)); - } - - { - count1 = 0; - count2 = 0; - std::map >::iterator iter = java_symbols.begin(); - for(; iter != java_symbols.end(); ++iter) { - count1++; - std::set& map = iter->second; - count2 += map.size(); - } - printf("xby-debug, java_symbols: %d, %d\n", count1, count2); - } - - { - printf("xby-debug, kernel_symbols: %lu\n", kernel_symbols.size()); - } - - { - count1 = 0; - count2 = 0; - std::map::iterator iter = machine_vma.begin(); - for(; iter != machine_vma.end(); ++iter) { - count1++; - proc_vma map = iter->second; - count2 += map.size(); - } - printf("xby-debug, machine_vma: %d, %d\n", count1, count2); - } - - { - count1 = 0; - count2 = 0; - std::map >::iterator iter = symbols_cache.begin(); - for(; iter != symbols_cache.end(); ++iter) { - count1++; - std::map& map = iter->second; - count2 += map.size(); - } - printf("xby-debug, symbols_cache: %d, %d\n", count1, count2); - } -} - -std::string demangleCppSym(std::string symbol) -{ - size_t size = 0; - int status = 0; - char *demangled = abi::__cxa_demangle(symbol.c_str(), NULL, &size, &status); - - if (status == 0 && demangled != NULL) - { - std::string FuncName(demangled); - free(demangled); - return FuncName; - } - else - { - // 解码失败,返回原始符号 - return symbol; - } -} - -void clearSpace(std::string &sym) -{ - for (auto i = sym.begin(); i != sym.end();) - { - if (isblank(*i)) - { - sym.erase(i); - } - else - { - i++; - } - } -} \ No newline at end of file diff --git a/eBPF_Supermarket/Stack_Analyser/src/main.cpp b/eBPF_Supermarket/Stack_Analyser/src/main.cpp index 2c15e5af6..435d380b9 100644 --- a/eBPF_Supermarket/Stack_Analyser/src/main.cpp +++ b/eBPF_Supermarket/Stack_Analyser/src/main.cpp @@ -29,15 +29,14 @@ #include "bpf_wapper/io.h" #include "bpf_wapper/readahead.h" #include "bpf_wapper/probe.h" -#include "sa_user.h" +#include "user.h" #include "clipp.h" +#include "cgroup.h" +#include "trace.h" -uint64_t stop_time = -1; bool timeout = false; -uint64_t IntTmp; -std::string StrTmp; -clipp::man_page *man_page; std::vector StackCollectorList; +void end_handle(void); namespace MainConfig { @@ -54,89 +53,14 @@ namespace MainConfig bool trace_kernel = false; } -namespace helper -{ -#include -#include - struct cgid_file_handle - { - // struct file_handle handle; - unsigned int handle_bytes; - int handle_type; - uint64_t cgid; - }; - uint64_t get_cgroupid(const char *pathname) - { - struct statfs fs; - int err; - struct cgid_file_handle *h; - int mount_id; - uint64_t ret; - - err = statfs(pathname, &fs); - if (err != 0) - { - fprintf(stderr, "statfs on %s failed: %s\n", pathname, strerror(errno)); - exit(1); - } - - if ((fs.f_type != (typeof(fs.f_type))CGROUP2_SUPER_MAGIC)) - { - fprintf(stderr, "File %s is not on a cgroup2 mount.\n", pathname); - exit(1); - } - - h = (cgid_file_handle *)malloc(sizeof(struct cgid_file_handle)); - if (!h) - { - fprintf(stderr, "Cannot allocate memory.\n"); - exit(1); - } - - h->handle_bytes = 8; - err = name_to_handle_at(AT_FDCWD, pathname, (struct file_handle *)h, &mount_id, 0); - if (err != 0) - { - fprintf(stderr, "name_to_handle_at failed: %s\n", strerror(errno)); - exit(1); - } - - if (h->handle_bytes != 8) - { - fprintf(stderr, "Unexpected handle size: %d. \n", h->handle_bytes); - exit(1); - } - - ret = h->cgid; - free(h); - - return ret; - } -} - -void end_handle(void) -{ - signal(SIGINT, SIG_IGN); - for (auto Item : StackCollectorList) - { - Item->activate(false); - if (!timeout) - { - std::cout << std::string(*Item) << std::endl; - } - Item->finish(); - } - if (MainConfig::command.length()) - { - kill(MainConfig::target_tgid, SIGTERM); - } -} - int main(int argc, char *argv[]) { - man_page = new clipp::man_page(); + uint64_t stop_time = -1; + clipp::man_page man_page; clipp::group cli; { + uint64_t IntTmp; + std::string StrTmp; auto OnCpuOption = (clipp::option("on_cpu") .call([] { StackCollectorList.push_back(new OnCPUStackCollector()); }) % @@ -172,31 +96,31 @@ int main(int argc, char *argv[]) COLLECTOR_INFO("llc_stat") & ((clipp::option("-P") & clipp::value("period", IntTmp) - .call([] + .call([IntTmp] { static_cast(StackCollectorList.back()) ->setScale(IntTmp); })) % "Set sampling period; default is 100"); auto ProbeOption = clipp::option("probe") - .call([] - { StackCollectorList.push_back(new ProbeStackCollector()); }) % - COLLECTOR_INFO("probe") & - (clipp::value("probe", StrTmp) - .call([] - { static_cast(StackCollectorList.back()) - ->setScale(StrTmp); }) % - "Set the probe string; specific use is:\n" - " | p:: -- probe a kernel function;\n" - ": | p:: -- probe a user-space function in the library 'lib';\n" - "t:: -- probe a kernel tracepoint;\n" - "u:: -- probe a USDT tracepoint"); + .call([] + { StackCollectorList.push_back(new ProbeStackCollector()); }) % + COLLECTOR_INFO("probe") & + (clipp::value("probe", StrTmp) + .call([&StrTmp] + { static_cast(StackCollectorList.back()) + ->setScale(StrTmp); }) % + "Set the probe string; specific use is:\n" + " | p:: -- probe a kernel function;\n" + ": | p:: -- probe a user-space function in the library 'lib';\n" + "t:: -- probe a kernel tracepoint;\n" + "u:: -- probe a USDT tracepoint"); auto MainOption = _GREEN "Some overall options" _RE % (( ((clipp::option("-g") & clipp::value("cgroup path", StrTmp) - .call([] - { MainConfig::target_cgroup = helper::get_cgroupid(StrTmp.c_str()); printf("Trace cgroup %ld\n", MainConfig::target_cgroup); })) % + .call([&StrTmp] + { MainConfig::target_cgroup = get_cgroupid(StrTmp.c_str()); printf("Trace cgroup %ld\n", MainConfig::target_cgroup); })) % "Set the cgroup of the process to be tracked; default is -1, which keeps track of all cgroups") | ((clipp::option("-p") & clipp::value("pid", MainConfig::target_tgid)) % @@ -215,7 +139,7 @@ int main(int argc, char *argv[]) "Set the output delay time (seconds); default is 5", (clipp::option("-d") & clipp::value("duration", MainConfig::run_time) - .call([] + .call([&stop_time] { stop_time = time(NULL) + MainConfig::run_time; })) % "Set the total sampling time; default is __INT_MAX__", (clipp::option("-u") @@ -241,8 +165,8 @@ int main(int argc, char *argv[]) { std::cout << "verion 2.0\n\n"; }) % "Show version"), (clipp::option("-h", "--help") - .call([] - { std::cout << *man_page << std::endl; exit(0); }) % + .call([&man_page] + { std::cout << man_page << std::endl; exit(0); }) % "Show man page")); cli = (OnCpuOption, @@ -260,13 +184,13 @@ int main(int argc, char *argv[]) .first_column(3) .doc_column(25) .last_column(128); - *man_page = clipp::make_man_page(cli, argv[0], fmt) - .prepend_section("DESCRIPTION", _RED "Count the function call stack associated with some metric.\n" _RE BANNER) - .append_section("LICENSE", _RED "Apache Licence 2.0" _RE); + man_page = clipp::make_man_page(cli, argv[0], fmt) + .prepend_section("DESCRIPTION", _RED "Count the function call stack associated with some metric.\n" _RE BANNER) + .append_section("LICENSE", _RED "Apache Licence 2.0" _RE); } if (!clipp::parse(argc, argv, cli)) { - std::cerr << *man_page << std::endl; + std::cerr << man_page << std::endl; return -1; } if (StackCollectorList.size() == 0) @@ -306,6 +230,19 @@ int main(int argc, char *argv[]) } } + ksyms = ksyms__load(); + if (!ksyms) + { + fprintf(stderr, "failed to load kallsyms\n"); + exit(1); + } + syms_cache = syms_cache__new(0); + if (!syms_cache) + { + fprintf(stderr, "failed to create syms_cache\n"); + exit(1); + } + for (auto Item = StackCollectorList.begin(); Item != StackCollectorList.end();) { fprintf(stderr, _RED "Attach collecotor%d %s.\n" _RE, @@ -381,4 +318,22 @@ int main(int argc, char *argv[]) } timeout = true; return 0; -} \ No newline at end of file +}; + +void end_handle(void) +{ + signal(SIGINT, SIG_IGN); + for (auto Item : StackCollectorList) + { + Item->activate(false); + if (!timeout) + { + std::cout << std::string(*Item) << std::endl; + } + Item->finish(); + } + if (MainConfig::command.length()) + { + kill(MainConfig::target_tgid, SIGTERM); + } +}; \ No newline at end of file diff --git a/eBPF_Supermarket/Stack_Analyser/src/trace_helpers.cpp b/eBPF_Supermarket/Stack_Analyser/src/trace.cpp similarity index 82% rename from eBPF_Supermarket/Stack_Analyser/src/trace_helpers.cpp rename to eBPF_Supermarket/Stack_Analyser/src/trace.cpp index 6097ec6e7..a8dc45044 100644 --- a/eBPF_Supermarket/Stack_Analyser/src/trace_helpers.cpp +++ b/eBPF_Supermarket/Stack_Analyser/src/trace.cpp @@ -20,8 +20,8 @@ #include #include #include -#include "trace_helpers.h" -#include "uprobe_helpers.h" +#include "trace.h" +#include "uprobe.h" #define min(x, y) ({ \ typeof(x) _min1 = (x); \ @@ -29,14 +29,15 @@ (void) (&_min1 == &_min2); \ _min1 < _min2 ? _min1 : _min2; }) -#define DISK_NAME_LEN 32 +#define DISK_NAME_LEN 32 -#define MINORBITS 20 -#define MINORMASK ((1U << MINORBITS) - 1) +#define MINORBITS 20 +#define MINORMASK ((1U << MINORBITS) - 1) -#define MKDEV(ma, mi) (((ma) << MINORBITS) | (mi)) +#define MKDEV(ma, mi) (((ma) << MINORBITS) | (mi)) -struct ksyms { +struct ksyms +{ struct ksym *syms; int syms_sz; int syms_cap; @@ -51,7 +52,8 @@ static int ksyms__add_symbol(struct ksyms *ksyms, const char *name, unsigned lon struct ksym *ksym; void *tmp; - if (ksyms->strs_sz + name_len > ksyms->strs_cap) { + if (ksyms->strs_sz + name_len > ksyms->strs_cap) + { new_cap = ksyms->strs_cap * 4 / 3; if (new_cap < ksyms->strs_sz + name_len) new_cap = ksyms->strs_sz + name_len; @@ -63,7 +65,8 @@ static int ksyms__add_symbol(struct ksyms *ksyms, const char *name, unsigned lon ksyms->strs = (char *)tmp; ksyms->strs_cap = new_cap; } - if (ksyms->syms_sz + 1 > ksyms->syms_cap) { + if (ksyms->syms_sz + 1 > ksyms->syms_cap) + { new_cap = ksyms->syms_cap * 4 / 3; if (new_cap < 1024) new_cap = 1024; @@ -111,9 +114,10 @@ struct ksyms *ksyms__load(void) if (!ksyms) goto err_out; - while (true) { + while (true) + { ret = fscanf(f, "%lx %c %s%*[^\n]\n", - &sym_addr, &sym_type, sym_name); + &sym_addr, &sym_type, sym_name); if (ret == EOF && feof(f)) break; if (ret != 3) @@ -148,13 +152,14 @@ void ksyms__free(struct ksyms *ksyms) } const struct ksym *ksyms__map_addr(const struct ksyms *ksyms, - unsigned long addr) + unsigned long addr) { int start = 0, end = ksyms->syms_sz - 1, mid; unsigned long sym_addr; /* find largest sym_addr <= addr using binary search */ - while (start < end) { + while (start < end) + { mid = start + (end - start + 1) / 2; sym_addr = ksyms->syms[mid].addr; @@ -170,11 +175,12 @@ const struct ksym *ksyms__map_addr(const struct ksyms *ksyms, } const struct ksym *ksyms__get_symbol(const struct ksyms *ksyms, - const char *name) + const char *name) { int i; - for (i = 0; i < ksyms->syms_sz; i++) { + for (i = 0; i < ksyms->syms_sz; i++) + { if (strcmp(ksyms->syms[i].name, name) == 0) return &ksyms->syms[i]; } @@ -182,13 +188,15 @@ const struct ksym *ksyms__get_symbol(const struct ksyms *ksyms, return NULL; } -struct load_range { +struct load_range +{ uint64_t start; uint64_t end; uint64_t file_off; }; -enum elf_type { +enum elf_type +{ EXEC, DYN, PERF_MAP, @@ -196,7 +204,8 @@ enum elf_type { UNKNOWN, }; -struct dso { +struct dso +{ char *name; struct load_range *ranges; int range_sz; @@ -218,7 +227,8 @@ struct dso { struct btf *btf; }; -struct map { +struct map +{ uint64_t start_addr; uint64_t end_addr; uint64_t file_off; @@ -227,7 +237,8 @@ struct map { uint64_t inode; }; -struct syms { +struct syms +{ struct dso *dsos; int dso_sz; }; @@ -238,14 +249,15 @@ static bool is_file_backed(const char *mapname) (!strncmp(mapname, prefix, sizeof(prefix) - 1)) return mapname[0] && !( - STARTS_WITH(mapname, "//anon") || - STARTS_WITH(mapname, "/dev/zero") || - STARTS_WITH(mapname, "/anon_hugepage") || - STARTS_WITH(mapname, "[stack") || - STARTS_WITH(mapname, "/SYSV") || - STARTS_WITH(mapname, "[heap]") || - STARTS_WITH(mapname, "[uprobes]") || - STARTS_WITH(mapname, "[vsyscall]")); + STARTS_WITH(mapname, "//anon") || + STARTS_WITH(mapname, "/dev/zero") || + STARTS_WITH(mapname, "/anon_hugepage") || + STARTS_WITH(mapname, "[stack") || + STARTS_WITH(mapname, "/SYSV") || + STARTS_WITH(mapname, "[heap]") || + STARTS_WITH(mapname, "[uprobes]") || + STARTS_WITH(mapname, "[vsyscall]") || + STARTS_WITH(mapname, "[vdso]")); } static bool is_perf_map(const char *path) @@ -285,7 +297,7 @@ static int get_elf_type(const char *path) } static int get_elf_text_scn_info(const char *path, uint64_t *addr, - uint64_t *offset) + uint64_t *offset) { Elf_Scn *section = NULL; int fd = -1, err = -1; @@ -302,12 +314,14 @@ static int get_elf_text_scn_info(const char *path, uint64_t *addr, goto err_out; err = -1; - while ((section = elf_nextscn(e, section)) != 0) { + while ((section = elf_nextscn(e, section)) != 0) + { if (!gelf_getshdr(section, &header)) continue; name = elf_strptr(e, stridx, header.sh_name); - if (name && !strcmp(name, ".text")) { + if (name && !strcmp(name, ".text")) + { *addr = (uint64_t)header.sh_addr; *offset = (uint64_t)header.sh_offset; err = 0; @@ -326,16 +340,19 @@ static int syms__add_dso(struct syms *syms, struct map *map, const char *name) int i, type; void *tmp; - for (i = 0; i < syms->dso_sz; i++) { - if (!strcmp(syms->dsos[i].name, name)) { + for (i = 0; i < syms->dso_sz; i++) + { + if (!strcmp(syms->dsos[i].name, name)) + { dso = &syms->dsos[i]; break; } } - if (!dso) { + if (!dso) + { tmp = realloc(syms->dsos, (syms->dso_sz + 1) * - sizeof(*syms->dsos)); + sizeof(*syms->dsos)); if (!tmp) return -1; syms->dsos = (struct dso *)tmp; @@ -354,41 +371,55 @@ static int syms__add_dso(struct syms *syms, struct map *map, const char *name) dso->ranges[dso->range_sz].file_off = map->file_off; dso->range_sz++; type = get_elf_type(name); - if (type == ET_EXEC) { + if (type == ET_EXEC) + { dso->type = EXEC; - } else if (type == ET_DYN) { + } + else if (type == ET_DYN) + { dso->type = DYN; if (get_elf_text_scn_info(name, &dso->sh_addr, &dso->sh_offset) < 0) return -1; - } else if (is_perf_map(name)) { + } + else if (is_perf_map(name)) + { dso->type = PERF_MAP; - } else if (is_vdso(name)) { + } + else if (is_vdso(name)) + { dso->type = VDSO; - } else { + } + else + { dso->type = UNKNOWN; } return 0; } static struct dso *syms__find_dso(const struct syms *syms, unsigned long addr, - uint64_t *offset) + uint64_t *offset) { struct load_range *range; struct dso *dso; int i, j; - for (i = 0; i < syms->dso_sz; i++) { + for (i = 0; i < syms->dso_sz; i++) + { dso = &syms->dsos[i]; - for (j = 0; j < dso->range_sz; j++) { + for (j = 0; j < dso->range_sz; j++) + { range = &dso->ranges[j]; if (addr <= range->start || addr >= range->end) continue; - if (dso->type == DYN || dso->type == VDSO) { + if (dso->type == DYN || dso->type == VDSO) + { /* Offset within the mmap */ *offset = addr - range->start + range->file_off; /* Offset within the ELF for dyn symbol lookup */ *offset += dso->sh_addr - dso->sh_offset; - } else { + } + else + { *offset = addr; } @@ -405,7 +436,7 @@ static int dso__load_sym_table_from_perf_map(struct dso *dso) } static int dso__add_sym(struct dso *dso, const char *name, uint64_t start, - uint64_t size) + uint64_t size) { struct sym *sym; size_t new_cap; @@ -416,7 +447,8 @@ static int dso__add_sym(struct dso *dso, const char *name, uint64_t start, if (off < 0) return off; - if (dso->syms_sz + 1 > dso->syms_cap) { + if (dso->syms_sz + 1 > dso->syms_cap) + { new_cap = dso->syms_cap * 4 / 3; if (new_cap < 1024) new_cap = 1024; @@ -447,17 +479,19 @@ static int sym_cmp(const void *p1, const void *p2) } static int dso__add_syms(struct dso *dso, Elf *e, Elf_Scn *section, - size_t stridx, size_t symsize) + size_t stridx, size_t symsize) { Elf_Data *data = NULL; - while ((data = elf_getdata(section, data)) != 0) { + while ((data = elf_getdata(section, data)) != 0) + { size_t i, symcount = data->d_size / symsize; if (data->d_size % symsize) return -1; - for (i = 0; i < symcount; ++i) { + for (i = 0; i < symcount; ++i) + { const char *name; GElf_Sym sym; @@ -503,18 +537,19 @@ static int dso__load_sym_table_from_elf(struct dso *dso, int fd) if (!e) return -1; - while ((section = elf_nextscn(e, section)) != 0) { + while ((section = elf_nextscn(e, section)) != 0) + { GElf_Shdr header; if (!gelf_getshdr(section, &header)) continue; if (header.sh_type != SHT_SYMTAB && - header.sh_type != SHT_DYNSYM) + header.sh_type != SHT_DYNSYM) continue; if (dso__add_syms(dso, e, section, header.sh_link, - header.sh_entsize)) + header.sh_entsize)) goto err_out; } @@ -522,7 +557,7 @@ static int dso__load_sym_table_from_elf(struct dso *dso, int fd) for (i = 0; i < dso->syms_sz; i++) dso->syms[i].name = btf__name_by_offset(dso->btf, - (unsigned long)dso->syms[i].name); + (unsigned long)dso->syms[i].name); qsort(dso->syms, dso->syms_sz, sizeof(*dso->syms), sym_cmp); @@ -552,10 +587,11 @@ static int create_tmp_vdso_image(struct dso *dso) if (!f) return -1; - while (true) { + while (true) + { ret = fscanf(f, "%llx-%llx %*s %*x %*x:%*x %*u%[^\n]", - (long long*)&start_addr, (long long*)&end_addr, - buf); + (long long *)&start_addr, (long long *)&end_addr, + buf); if (ret == EOF && feof(f)) break; if (ret != 3) @@ -577,20 +613,22 @@ static int create_tmp_vdso_image(struct dso *dso) memcpy(image, (void *)start_addr, sz); snprintf(tmpfile, sizeof(tmpfile), - "/tmp/libbpf_%ld_vdso_image_XXXXXX", pid); + "/tmp/libbpf_%ld_vdso_image_XXXXXX", pid); fd = mkostemp(tmpfile, O_CLOEXEC); - if (fd < 0) { + if (fd < 0) + { fprintf(stderr, "failed to create temp file: %s\n", - strerror(errno)); + strerror(errno)); goto err_out; } /* Unlink the file to avoid leaking */ if (unlink(tmpfile) == -1) fprintf(stderr, "failed to unlink %s: %s\n", tmpfile, - strerror(errno)); - if (write(fd, image, sz) == -1) { + strerror(errno)); + if (write(fd, image, sz) == -1) + { fprintf(stderr, "failed to write to vDSO image: %s\n", - strerror(errno)); + strerror(errno)); close(fd); fd = -1; goto err_out; @@ -636,7 +674,8 @@ static struct sym *dso__find_sym(struct dso *dso, uint64_t offset) end = dso->syms_sz - 1; /* find largest sym_addr <= addr using binary search */ - while (start < end) { + while (start < end) + { mid = start + (end - start + 1) / 2; sym_addr = dso->syms[mid].start; @@ -647,16 +686,17 @@ static struct sym *dso__find_sym(struct dso *dso, uint64_t offset) } if (start == end && dso->syms[start].start <= offset && - offset < dso->syms[start].start + dso->syms[start].size) { + offset < dso->syms[start].start + dso->syms[start].size) + { (dso->syms[start]).offset = offset - dso->syms[start].start; return &dso->syms[start]; } return NULL; } -struct syms *syms__load_file(const char *fname) +struct syms *syms__load_file(const char *fname, pid_t tgid) { - char buf[PATH_MAX], perm[5]; + char buf[PATH_MAX], perm[5], path[PATH_MAX]; struct syms *syms; struct map map; char *name; @@ -671,17 +711,18 @@ struct syms *syms__load_file(const char *fname) if (!syms) goto err_out; - while (true) { + while (true) + { ret = fscanf(f, "%llx-%llx %4s %llx %llx:%llx %llu%[^\n]", - (long long*)&map.start_addr, - (long long*)&map.end_addr, perm, - (long long*)&map.file_off, - (long long*)&map.dev_major, - (long long*)&map.dev_minor, - (long long*)&map.inode, buf); + (long long *)&map.start_addr, + (long long *)&map.end_addr, perm, + (long long *)&map.file_off, + (long long *)&map.dev_major, + (long long *)&map.dev_minor, + (long long *)&map.inode, buf); if (ret == EOF && feof(f)) break; - if (ret != 8) /* perf-.map */ + if (ret != 8) /* perf-.map */ goto err_out; if (perm[2] != 'x') @@ -693,7 +734,8 @@ struct syms *syms__load_file(const char *fname) if (!is_file_backed(name)) continue; - if (syms__add_dso(syms, &map, name)) + sprintf(path, "/proc/%d/root/%s", tgid, name); + if (syms__add_dso(syms, &map, path)) goto err_out; } @@ -711,7 +753,7 @@ struct syms *syms__load_pid(pid_t tgid) char fname[128]; snprintf(fname, sizeof(fname), "/proc/%ld/maps", (long)tgid); - return syms__load_file(fname); + return syms__load_file(fname, tgid); } void syms__free(struct syms *syms) @@ -727,7 +769,7 @@ void syms__free(struct syms *syms) free(syms); } -const struct sym *syms__map_addr(const struct syms *syms, unsigned long addr) +struct sym *syms__map_addr(const struct syms *syms, unsigned long addr) { struct dso *dso; uint64_t offset; @@ -739,7 +781,7 @@ const struct sym *syms__map_addr(const struct syms *syms, unsigned long addr) } const struct sym *syms__map_addr_dso(const struct syms *syms, unsigned long addr, - char **dso_name, unsigned long *dso_offset) + char **dso_name, unsigned long *dso_offset) { struct dso *dso; uint64_t offset; @@ -754,8 +796,10 @@ const struct sym *syms__map_addr_dso(const struct syms *syms, unsigned long addr return dso__find_sym(dso, offset); } -struct syms_cache { - struct { +struct syms_cache +{ + struct + { struct syms *syms; int tgid; } *data; @@ -792,13 +836,14 @@ struct syms *syms_cache__get_syms(struct syms_cache *syms_cache, int tgid) void *tmp; int i; - for (i = 0; i < syms_cache->nr; i++) { + for (i = 0; i < syms_cache->nr; i++) + { if (syms_cache->data[i].tgid == tgid) return syms_cache->data[i].syms; } tmp = realloc(syms_cache->data, (syms_cache->nr + 1) * - sizeof(*syms_cache->data)); + sizeof(*syms_cache->data)); if (!tmp) return NULL; syms_cache->data = (typeof(syms_cache->data))tmp; @@ -807,19 +852,20 @@ struct syms *syms_cache__get_syms(struct syms_cache *syms_cache, int tgid) return syms_cache->data[syms_cache->nr++].syms; } -struct partitions { +struct partitions +{ struct partition *items; int sz; }; static int partitions__add_partition(struct partitions *partitions, - const char *name, unsigned int dev) + const char *name, unsigned int dev) { struct partition *partition; void *tmp; tmp = realloc(partitions->items, (partitions->sz + 1) * - sizeof(*partitions->items)); + sizeof(*partitions->items)); if (!tmp) return -1; partitions->items = (struct partition *)tmp; @@ -848,15 +894,16 @@ struct partitions *partitions__load(void) if (!partitions) goto err_out; - while (fgets(buf, sizeof(buf), f) != NULL) { + while (fgets(buf, sizeof(buf), f) != NULL) + { /* skip heading */ if (buf[0] != ' ' || buf[0] == '\n') continue; if (sscanf(buf, "%u %u %llu %s", &devmaj, &devmin, &nop, - part_name) != 4) + part_name) != 4) goto err_out; if (partitions__add_partition(partitions, part_name, - MKDEV(devmaj, devmin))) + MKDEV(devmaj, devmin))) goto err_out; } @@ -887,7 +934,8 @@ partitions__get_by_dev(const struct partitions *partitions, unsigned int dev) { int i; - for (i = 0; i < partitions->sz; i++) { + for (i = 0; i < partitions->sz; i++) + { if (partitions->items[i].dev == dev) return &partitions->items[i]; } @@ -900,7 +948,8 @@ partitions__get_by_name(const struct partitions *partitions, const char *name) { int i; - for (i = 0; i < partitions->sz; i++) { + for (i = 0; i < partitions->sz; i++) + { if (strcmp(partitions->items[i].name, name) == 0) return &partitions->items[i]; } @@ -932,7 +981,8 @@ void print_log2_hist(unsigned int *vals, int vals_size, const char *val_type) unsigned long long low, high; int stars, width, i; - for (i = 0; i < vals_size; i++) { + for (i = 0; i < vals_size; i++) + { val = vals[i]; if (val > 0) idx_max = i; @@ -944,14 +994,15 @@ void print_log2_hist(unsigned int *vals, int vals_size, const char *val_type) return; printf("%*s%-*s : count distribution\n", idx_max <= 32 ? 5 : 15, "", - idx_max <= 32 ? 19 : 29, val_type); + idx_max <= 32 ? 19 : 29, val_type); if (idx_max <= 32) stars = stars_max; else stars = stars_max / 2; - for (i = 0; i <= idx_max; i++) { + for (i = 0; i <= idx_max; i++) + { low = (1ULL << (i + 1)) >> 1; high = (1ULL << (i + 1)) - 1; if (low == high) @@ -965,14 +1016,16 @@ void print_log2_hist(unsigned int *vals, int vals_size, const char *val_type) } void print_linear_hist(unsigned int *vals, int vals_size, unsigned int base, - unsigned int step, const char *val_type) + unsigned int step, const char *val_type) { int i, stars_max = 40, idx_min = -1, idx_max = -1; unsigned int val, val_max = 0; - for (i = 0; i < vals_size; i++) { + for (i = 0; i < vals_size; i++) + { val = vals[i]; - if (val > 0) { + if (val > 0) + { idx_max = i; if (idx_min < 0) idx_min = i; @@ -985,7 +1038,8 @@ void print_linear_hist(unsigned int *vals, int vals_size, unsigned int base, return; printf(" %-13s : count distribution\n", val_type); - for (i = idx_min; i <= idx_max; i++) { + for (i = idx_min; i <= idx_max; i++) + { val = vals[i]; if (!val) continue; @@ -1013,10 +1067,12 @@ bool is_kernel_module(const char *name) if (!f) return false; - while (fgets(buf, sizeof(buf), f) != NULL) { + while (fgets(buf, sizeof(buf), f) != NULL) + { if (sscanf(buf, "%s %*s\n", buf) != 1) break; - if (!strcmp(buf, name)) { + if (!strcmp(buf, name)) + { found = true; break; } @@ -1031,18 +1087,17 @@ static bool fentry_try_attach(int id) int prog_fd, attach_fd; char error[4096]; struct bpf_insn insns[] = { - { .code = BPF_ALU64 | BPF_MOV | BPF_K, .dst_reg = BPF_REG_0, .imm = 0 }, - { .code = BPF_JMP | BPF_EXIT }, + {.code = BPF_ALU64 | BPF_MOV | BPF_K, .dst_reg = BPF_REG_0, .imm = 0}, + {.code = BPF_JMP | BPF_EXIT}, }; LIBBPF_OPTS(bpf_prog_load_opts, opts, - .expected_attach_type = BPF_TRACE_FENTRY, - .attach_btf_id = (__u32)id, - .log_size = sizeof(error), - .log_buf = error, - ); + .expected_attach_type = BPF_TRACE_FENTRY, + .attach_btf_id = (__u32)id, + .log_size = sizeof(error), + .log_buf = error, ); prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACING, "test", "GPL", insns, - sizeof(insns) / sizeof(struct bpf_insn), &opts); + sizeof(insns) / sizeof(struct bpf_insn), &opts); if (prog_fd < 0) return false; @@ -1066,7 +1121,8 @@ bool fentry_can_attach(const char *name, const char *mod) btf = vmlinux_btf; - if (mod) { + if (mod) + { module_btf = btf__load_module_btf(mod, vmlinux_btf); err = libbpf_get_error(module_btf); if (!err) @@ -1100,8 +1156,7 @@ static const char *tracefs_path(void) static const char *tracefs_available_filter_functions(void) { - return use_debugfs() ? DEBUGFS"/available_filter_functions" : - TRACEFS"/available_filter_functions"; + return use_debugfs() ? DEBUGFS "/available_filter_functions" : TRACEFS "/available_filter_functions"; } bool kprobe_exists(const char *name) @@ -1115,15 +1170,18 @@ bool kprobe_exists(const char *name) if (!f) goto avail_filter; - while (true) { + while (true) + { ret = fscanf(f, "%s %s%*[^\n]\n", addr_range, sym_name); if (ret == EOF && feof(f)) break; - if (ret != 2) { + if (ret != 2) + { fprintf(stderr, "failed to read symbol from kprobe blacklist\n"); break; } - if (!strcmp(name, sym_name)) { + if (!strcmp(name, sym_name)) + { fclose(f); return false; } @@ -1135,15 +1193,18 @@ bool kprobe_exists(const char *name) if (!f) goto slow_path; - while (true) { + while (true) + { ret = fscanf(f, "%s%*[^\n]\n", sym_name); if (ret == EOF && feof(f)) break; - if (ret != 1) { + if (ret != 1) + { fprintf(stderr, "failed to read symbol from available_filter_functions\n"); break; } - if (!strcmp(name, sym_name)) { + if (!strcmp(name, sym_name)) + { fclose(f); return true; } @@ -1157,15 +1218,18 @@ bool kprobe_exists(const char *name) if (!f) return false; - while (true) { + while (true) + { ret = fscanf(f, "%*x %*c %s%*[^\n]\n", sym_name); if (ret == EOF && feof(f)) break; - if (ret != 1) { + if (ret != 1) + { fprintf(stderr, "failed to read symbol from kallsyms\n"); break; } - if (!strcmp(name, sym_name)) { + if (!strcmp(name, sym_name)) + { fclose(f); return true; } @@ -1203,7 +1267,8 @@ bool module_btf_exists(const char *mod) { char sysfs_mod[80]; - if (mod) { + if (mod) + { snprintf(sysfs_mod, sizeof(sysfs_mod), "/sys/kernel/btf/%s", mod); if (!access(sysfs_mod, R_OK)) return true; @@ -1215,8 +1280,8 @@ bool probe_tp_btf(const char *name) { LIBBPF_OPTS(bpf_prog_load_opts, opts, .expected_attach_type = BPF_TRACE_RAW_TP); struct bpf_insn insns[] = { - { .code = BPF_ALU64 | BPF_MOV | BPF_K, .dst_reg = BPF_REG_0, .imm = 0 }, - { .code = BPF_JMP | BPF_EXIT }, + {.code = BPF_ALU64 | BPF_MOV | BPF_K, .dst_reg = BPF_REG_0, .imm = 0}, + {.code = BPF_JMP | BPF_EXIT}, }; int fd, insn_cnt = sizeof(insns) / sizeof(struct bpf_insn); @@ -1238,3 +1303,21 @@ bool probe_ringbuf() close(map_fd); return true; } + +const struct ksym *ksyms__find_symbol(const struct ksyms *ksyms, + const char *name) +{ + for (int i = 0; i < ksyms->syms_sz; i++) + { + int j; + for (j = 0; name[j] && name[j] == ksyms->syms[i].name[j]; j++) + ; + if (!name[j]) + return &ksyms->syms[i]; + } + return NULL; +} + +struct ksyms *ksyms; +struct syms_cache *syms_cache; +struct syms *syms; \ No newline at end of file diff --git a/eBPF_Supermarket/Stack_Analyser/src/uprobe_helpers.cpp b/eBPF_Supermarket/Stack_Analyser/src/uprobe.cpp similarity index 100% rename from eBPF_Supermarket/Stack_Analyser/src/uprobe_helpers.cpp rename to eBPF_Supermarket/Stack_Analyser/src/uprobe.cpp