From cda8dcf43a0867342bd68715521c03d84f162f49 Mon Sep 17 00:00:00 2001 From: xnought Date: Fri, 9 Feb 2024 12:08:19 -0800 Subject: [PATCH] feat: instead of fork jsut cp entire venome --- .gitmodules | 3 - frontend/venome-molstar | 1 - frontend/venome-molstar/.eslintrc.json | 118 + frontend/venome-molstar/.gitattributes | 1 + .../venome-molstar/.github/workflows/node.yml | 19 + frontend/venome-molstar/.gitignore | 10 + frontend/venome-molstar/.npmignore | 3 + frontend/venome-molstar/CHANGELOG.md | 50 + frontend/venome-molstar/LICENSE | 201 + frontend/venome-molstar/README.md | 26 + frontend/venome-molstar/component-demo.html | 232 + frontend/venome-molstar/example/.gitignore | 24 + .../example/.vscode/extensions.json | 3 + frontend/venome-molstar/example/README.md | 47 + frontend/venome-molstar/example/index.html | 13 + frontend/venome-molstar/example/package.json | 21 + .../venome-molstar/example/public/vite.svg | 1 + .../venome-molstar/example/src/App.svelte | 69 + frontend/venome-molstar/example/src/app.css | 0 .../example/src/assets/svelte.svg | 1 + frontend/venome-molstar/example/src/main.ts | 8 + .../venome-molstar/example/src/vite-env.d.ts | 2 + .../venome-molstar/example/svelte.config.js | 7 + frontend/venome-molstar/example/tsconfig.json | 20 + .../venome-molstar/example/tsconfig.node.json | 9 + .../venome-molstar/example/vite.config.ts | 7 + frontend/venome-molstar/example/yarn.lock | 865 ++ frontend/venome-molstar/favicon.ico | Bin 0 -> 16958 bytes frontend/venome-molstar/index.html | 259 + .../lib/alphafold-transparency.d.ts | 6 + .../lib/alphafold-transparency.js | 98 + .../venome-molstar/lib/custom-events.d.ts | 4 + frontend/venome-molstar/lib/custom-events.js | 68 + .../lib/domain-annotations/behavior.d.ts | 5 + .../lib/domain-annotations/behavior.js | 39 + .../lib/domain-annotations/color.d.ts | 10 + .../lib/domain-annotations/color.js | 81 + .../lib/domain-annotations/prop.d.ts | 35 + .../lib/domain-annotations/prop.js | 142 + frontend/venome-molstar/lib/helpers.d.ts | 106 + frontend/venome-molstar/lib/helpers.js | 389 + frontend/venome-molstar/lib/index.d.ts | 98 + frontend/venome-molstar/lib/index.js | 928 ++ frontend/venome-molstar/lib/labels.d.ts | 2 + frontend/venome-molstar/lib/labels.js | 46 + frontend/venome-molstar/lib/loci-details.d.ts | 27 + frontend/venome-molstar/lib/loci-details.js | 141 + frontend/venome-molstar/lib/overlay.d.ts | 16 + frontend/venome-molstar/lib/overlay.js | 50 + frontend/venome-molstar/lib/overlay.scss | 46 + .../lib/plugin-custom-state.d.ts | 84 + .../venome-molstar/lib/plugin-custom-state.js | 5 + .../venome-molstar/lib/sifts-mapping.d.ts | 16 + frontend/venome-molstar/lib/sifts-mapping.js | 83 + .../lib/sifts-mappings-behaviour.d.ts | 5 + .../lib/sifts-mappings-behaviour.js | 54 + .../venome-molstar/lib/spec-from-html.d.ts | 3 + frontend/venome-molstar/lib/spec-from-html.js | 109 + frontend/venome-molstar/lib/spec.d.ts | 122 + frontend/venome-molstar/lib/spec.js | 124 + .../venome-molstar/lib/subscribe-events.d.ts | 1 + .../venome-molstar/lib/subscribe-events.js | 190 + .../lib/superposition-export.d.ts | 4 + .../lib/superposition-export.js | 130 + .../superposition-focus-representation.d.ts | 16 + .../lib/superposition-focus-representation.js | 148 + .../lib/superposition-sifts-mapping.d.ts | 22 + .../lib/superposition-sifts-mapping.js | 155 + .../venome-molstar/lib/superposition.d.ts | 7 + frontend/venome-molstar/lib/superposition.js | 727 + .../lib/ui/alphafold-superposition.d.ts | 56 + .../lib/ui/alphafold-superposition.js | 149 + .../lib/ui/alphafold-tranparency.d.ts | 21 + .../lib/ui/alphafold-tranparency.js | 45 + .../lib/ui/annotation-controls.d.ts | 27 + .../lib/ui/annotation-controls.js | 151 + .../lib/ui/annotation-row-controls.d.ts | 26 + .../lib/ui/annotation-row-controls.js | 36 + .../lib/ui/export-superposition.d.ts | 6 + .../lib/ui/export-superposition.js | 49 + .../lib/ui/pdbe-left-panel.d.ts | 18 + .../venome-molstar/lib/ui/pdbe-left-panel.js | 129 + .../lib/ui/pdbe-screenshot-controls.d.ts | 20 + .../lib/ui/pdbe-screenshot-controls.js | 65 + .../lib/ui/pdbe-structure-controls.d.ts | 18 + .../lib/ui/pdbe-structure-controls.js | 48 + .../lib/ui/pdbe-viewport-controls.d.ts | 5 + .../lib/ui/pdbe-viewport-controls.js | 26 + .../venome-molstar/lib/ui/segment-tree.d.ts | 18 + .../venome-molstar/lib/ui/segment-tree.js | 652 + .../lib/ui/superposition-components.d.ts | 9 + .../lib/ui/superposition-components.js | 364 + .../lib/ui/superposition-viewport.d.ts | 4 + .../lib/ui/superposition-viewport.js | 12 + .../lib/ui/symmetry-annotation-controls.d.ts | 46 + .../lib/ui/symmetry-annotation-controls.js | 213 + frontend/venome-molstar/package-lock.json | 11725 ++++++++++++++++ frontend/venome-molstar/package.json | 82 + frontend/venome-molstar/portfolio.html | 415 + frontend/venome-molstar/scripts.js | 91 + .../src/app/alphafold-transparency.ts | 191 + .../venome-molstar/src/app/custom-events.ts | 99 + .../src/app/domain-annotations/behavior.ts | 68 + .../src/app/domain-annotations/color.ts | 122 + .../src/app/domain-annotations/prop.ts | 198 + frontend/venome-molstar/src/app/helpers.ts | 588 + frontend/venome-molstar/src/app/index.ts | 1255 ++ frontend/venome-molstar/src/app/labels.ts | 58 + .../venome-molstar/src/app/loci-details.ts | 227 + frontend/venome-molstar/src/app/overlay.ts | 59 + .../src/app/plugin-custom-state.ts | 74 + .../venome-molstar/src/app/sifts-mapping.ts | 116 + .../src/app/sifts-mappings-behaviour.ts | 84 + .../venome-molstar/src/app/spec-from-html.ts | 125 + frontend/venome-molstar/src/app/spec.ts | 267 + .../src/app/subscribe-events.ts | 209 + .../src/app/superposition-export.ts | 157 + .../app/superposition-focus-representation.ts | 213 + .../src/app/superposition-sifts-mapping.ts | 250 + .../venome-molstar/src/app/superposition.ts | 1006 ++ .../src/app/ui/alphafold-superposition.tsx | 236 + .../src/app/ui/alphafold-tranparency.tsx | 52 + .../src/app/ui/annotation-controls.tsx | 199 + .../src/app/ui/annotation-row-controls.tsx | 74 + .../src/app/ui/export-superposition.tsx | 63 + .../src/app/ui/pdbe-left-panel.tsx | 205 + .../src/app/ui/pdbe-screenshot-controls.tsx | 109 + .../src/app/ui/pdbe-structure-controls.tsx | 77 + .../src/app/ui/pdbe-viewport-controls.tsx | 40 + .../src/app/ui/segment-tree.tsx | 785 ++ .../src/app/ui/superposition-components.tsx | 498 + .../src/app/ui/superposition-viewport.tsx | 25 + .../app/ui/symmetry-annotation-controls.tsx | 250 + frontend/venome-molstar/src/overlay.scss | 46 + .../venome-molstar/src/web-component/index.js | 19 + frontend/venome-molstar/tsconfig.json | 27 + .../webpack.config.development.js | 21 + .../webpack.config.production.js | 140 + 138 files changed, 29116 insertions(+), 4 deletions(-) delete mode 100644 .gitmodules delete mode 160000 frontend/venome-molstar create mode 100644 frontend/venome-molstar/.eslintrc.json create mode 100644 frontend/venome-molstar/.gitattributes create mode 100644 frontend/venome-molstar/.github/workflows/node.yml create mode 100644 frontend/venome-molstar/.gitignore create mode 100644 frontend/venome-molstar/.npmignore create mode 100644 frontend/venome-molstar/CHANGELOG.md create mode 100644 frontend/venome-molstar/LICENSE create mode 100644 frontend/venome-molstar/README.md create mode 100644 frontend/venome-molstar/component-demo.html create mode 100644 frontend/venome-molstar/example/.gitignore create mode 100644 frontend/venome-molstar/example/.vscode/extensions.json create mode 100644 frontend/venome-molstar/example/README.md create mode 100644 frontend/venome-molstar/example/index.html create mode 100644 frontend/venome-molstar/example/package.json create mode 100644 frontend/venome-molstar/example/public/vite.svg create mode 100644 frontend/venome-molstar/example/src/App.svelte create mode 100644 frontend/venome-molstar/example/src/app.css create mode 100644 frontend/venome-molstar/example/src/assets/svelte.svg create mode 100644 frontend/venome-molstar/example/src/main.ts create mode 100644 frontend/venome-molstar/example/src/vite-env.d.ts create mode 100644 frontend/venome-molstar/example/svelte.config.js create mode 100644 frontend/venome-molstar/example/tsconfig.json create mode 100644 frontend/venome-molstar/example/tsconfig.node.json create mode 100644 frontend/venome-molstar/example/vite.config.ts create mode 100644 frontend/venome-molstar/example/yarn.lock create mode 100644 frontend/venome-molstar/favicon.ico create mode 100644 frontend/venome-molstar/index.html create mode 100644 frontend/venome-molstar/lib/alphafold-transparency.d.ts create mode 100644 frontend/venome-molstar/lib/alphafold-transparency.js create mode 100644 frontend/venome-molstar/lib/custom-events.d.ts create mode 100644 frontend/venome-molstar/lib/custom-events.js create mode 100644 frontend/venome-molstar/lib/domain-annotations/behavior.d.ts create mode 100644 frontend/venome-molstar/lib/domain-annotations/behavior.js create mode 100644 frontend/venome-molstar/lib/domain-annotations/color.d.ts create mode 100644 frontend/venome-molstar/lib/domain-annotations/color.js create mode 100644 frontend/venome-molstar/lib/domain-annotations/prop.d.ts create mode 100644 frontend/venome-molstar/lib/domain-annotations/prop.js create mode 100644 frontend/venome-molstar/lib/helpers.d.ts create mode 100644 frontend/venome-molstar/lib/helpers.js create mode 100644 frontend/venome-molstar/lib/index.d.ts create mode 100644 frontend/venome-molstar/lib/index.js create mode 100644 frontend/venome-molstar/lib/labels.d.ts create mode 100644 frontend/venome-molstar/lib/labels.js create mode 100644 frontend/venome-molstar/lib/loci-details.d.ts create mode 100644 frontend/venome-molstar/lib/loci-details.js create mode 100644 frontend/venome-molstar/lib/overlay.d.ts create mode 100644 frontend/venome-molstar/lib/overlay.js create mode 100644 frontend/venome-molstar/lib/overlay.scss create mode 100644 frontend/venome-molstar/lib/plugin-custom-state.d.ts create mode 100644 frontend/venome-molstar/lib/plugin-custom-state.js create mode 100644 frontend/venome-molstar/lib/sifts-mapping.d.ts create mode 100644 frontend/venome-molstar/lib/sifts-mapping.js create mode 100644 frontend/venome-molstar/lib/sifts-mappings-behaviour.d.ts create mode 100644 frontend/venome-molstar/lib/sifts-mappings-behaviour.js create mode 100644 frontend/venome-molstar/lib/spec-from-html.d.ts create mode 100644 frontend/venome-molstar/lib/spec-from-html.js create mode 100644 frontend/venome-molstar/lib/spec.d.ts create mode 100644 frontend/venome-molstar/lib/spec.js create mode 100644 frontend/venome-molstar/lib/subscribe-events.d.ts create mode 100644 frontend/venome-molstar/lib/subscribe-events.js create mode 100644 frontend/venome-molstar/lib/superposition-export.d.ts create mode 100644 frontend/venome-molstar/lib/superposition-export.js create mode 100644 frontend/venome-molstar/lib/superposition-focus-representation.d.ts create mode 100644 frontend/venome-molstar/lib/superposition-focus-representation.js create mode 100644 frontend/venome-molstar/lib/superposition-sifts-mapping.d.ts create mode 100644 frontend/venome-molstar/lib/superposition-sifts-mapping.js create mode 100644 frontend/venome-molstar/lib/superposition.d.ts create mode 100644 frontend/venome-molstar/lib/superposition.js create mode 100644 frontend/venome-molstar/lib/ui/alphafold-superposition.d.ts create mode 100644 frontend/venome-molstar/lib/ui/alphafold-superposition.js create mode 100644 frontend/venome-molstar/lib/ui/alphafold-tranparency.d.ts create mode 100644 frontend/venome-molstar/lib/ui/alphafold-tranparency.js create mode 100644 frontend/venome-molstar/lib/ui/annotation-controls.d.ts create mode 100644 frontend/venome-molstar/lib/ui/annotation-controls.js create mode 100644 frontend/venome-molstar/lib/ui/annotation-row-controls.d.ts create mode 100644 frontend/venome-molstar/lib/ui/annotation-row-controls.js create mode 100644 frontend/venome-molstar/lib/ui/export-superposition.d.ts create mode 100644 frontend/venome-molstar/lib/ui/export-superposition.js create mode 100644 frontend/venome-molstar/lib/ui/pdbe-left-panel.d.ts create mode 100644 frontend/venome-molstar/lib/ui/pdbe-left-panel.js create mode 100644 frontend/venome-molstar/lib/ui/pdbe-screenshot-controls.d.ts create mode 100644 frontend/venome-molstar/lib/ui/pdbe-screenshot-controls.js create mode 100644 frontend/venome-molstar/lib/ui/pdbe-structure-controls.d.ts create mode 100644 frontend/venome-molstar/lib/ui/pdbe-structure-controls.js create mode 100644 frontend/venome-molstar/lib/ui/pdbe-viewport-controls.d.ts create mode 100644 frontend/venome-molstar/lib/ui/pdbe-viewport-controls.js create mode 100644 frontend/venome-molstar/lib/ui/segment-tree.d.ts create mode 100644 frontend/venome-molstar/lib/ui/segment-tree.js create mode 100644 frontend/venome-molstar/lib/ui/superposition-components.d.ts create mode 100644 frontend/venome-molstar/lib/ui/superposition-components.js create mode 100644 frontend/venome-molstar/lib/ui/superposition-viewport.d.ts create mode 100644 frontend/venome-molstar/lib/ui/superposition-viewport.js create mode 100644 frontend/venome-molstar/lib/ui/symmetry-annotation-controls.d.ts create mode 100644 frontend/venome-molstar/lib/ui/symmetry-annotation-controls.js create mode 100644 frontend/venome-molstar/package-lock.json create mode 100644 frontend/venome-molstar/package.json create mode 100644 frontend/venome-molstar/portfolio.html create mode 100644 frontend/venome-molstar/scripts.js create mode 100644 frontend/venome-molstar/src/app/alphafold-transparency.ts create mode 100644 frontend/venome-molstar/src/app/custom-events.ts create mode 100644 frontend/venome-molstar/src/app/domain-annotations/behavior.ts create mode 100644 frontend/venome-molstar/src/app/domain-annotations/color.ts create mode 100644 frontend/venome-molstar/src/app/domain-annotations/prop.ts create mode 100644 frontend/venome-molstar/src/app/helpers.ts create mode 100644 frontend/venome-molstar/src/app/index.ts create mode 100644 frontend/venome-molstar/src/app/labels.ts create mode 100644 frontend/venome-molstar/src/app/loci-details.ts create mode 100644 frontend/venome-molstar/src/app/overlay.ts create mode 100644 frontend/venome-molstar/src/app/plugin-custom-state.ts create mode 100644 frontend/venome-molstar/src/app/sifts-mapping.ts create mode 100644 frontend/venome-molstar/src/app/sifts-mappings-behaviour.ts create mode 100644 frontend/venome-molstar/src/app/spec-from-html.ts create mode 100644 frontend/venome-molstar/src/app/spec.ts create mode 100644 frontend/venome-molstar/src/app/subscribe-events.ts create mode 100644 frontend/venome-molstar/src/app/superposition-export.ts create mode 100644 frontend/venome-molstar/src/app/superposition-focus-representation.ts create mode 100644 frontend/venome-molstar/src/app/superposition-sifts-mapping.ts create mode 100644 frontend/venome-molstar/src/app/superposition.ts create mode 100644 frontend/venome-molstar/src/app/ui/alphafold-superposition.tsx create mode 100644 frontend/venome-molstar/src/app/ui/alphafold-tranparency.tsx create mode 100644 frontend/venome-molstar/src/app/ui/annotation-controls.tsx create mode 100644 frontend/venome-molstar/src/app/ui/annotation-row-controls.tsx create mode 100644 frontend/venome-molstar/src/app/ui/export-superposition.tsx create mode 100644 frontend/venome-molstar/src/app/ui/pdbe-left-panel.tsx create mode 100644 frontend/venome-molstar/src/app/ui/pdbe-screenshot-controls.tsx create mode 100644 frontend/venome-molstar/src/app/ui/pdbe-structure-controls.tsx create mode 100644 frontend/venome-molstar/src/app/ui/pdbe-viewport-controls.tsx create mode 100644 frontend/venome-molstar/src/app/ui/segment-tree.tsx create mode 100644 frontend/venome-molstar/src/app/ui/superposition-components.tsx create mode 100644 frontend/venome-molstar/src/app/ui/superposition-viewport.tsx create mode 100644 frontend/venome-molstar/src/app/ui/symmetry-annotation-controls.tsx create mode 100644 frontend/venome-molstar/src/overlay.scss create mode 100644 frontend/venome-molstar/src/web-component/index.js create mode 100644 frontend/venome-molstar/tsconfig.json create mode 100644 frontend/venome-molstar/webpack.config.development.js create mode 100644 frontend/venome-molstar/webpack.config.production.js diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 83d64a11..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "frontend/venome-molstar"] - path = frontend/venome-molstar - url = git@github.com:xnought/venome-molstar.git diff --git a/frontend/venome-molstar b/frontend/venome-molstar deleted file mode 160000 index 885b180d..00000000 --- a/frontend/venome-molstar +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 885b180d35cb977a1bb442dfdb1dd5fe53b9ad9c diff --git a/frontend/venome-molstar/.eslintrc.json b/frontend/venome-molstar/.eslintrc.json new file mode 100644 index 00000000..e5c62c5e --- /dev/null +++ b/frontend/venome-molstar/.eslintrc.json @@ -0,0 +1,118 @@ +{ + "env": { + "browser": true, + "node": true + }, + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module", + "ecmaFeatures": { + "impliedStrict": true + } + }, + "rules": { + "indent": "off", + "arrow-parens": [ + "off", + "as-needed" + ], + "brace-style": "off", + "comma-spacing": "off", + "space-infix-ops": "off", + "comma-dangle": "off", + "eqeqeq": [ + "error", + "smart" + ], + "import/order": "off", + "no-eval": "warn", + "no-new-wrappers": "warn", + "no-trailing-spaces": "warn", + "no-unsafe-finally": "warn", + "no-var": "error", + "spaced-comment": "warn", + "semi": "warn", + "no-throw-literal": "error", + "key-spacing": "warn", + "object-curly-spacing": ["warn", "always"], + "array-bracket-spacing": "warn", + "space-in-parens": "warn", + "computed-property-spacing": "error", + "prefer-const": ["warn", { + "destructuring": "all", + "ignoreReadBeforeAssign": false + }], + "space-before-function-paren": "off", + "func-call-spacing": "off", + "no-multi-spaces": "warn", + "block-spacing": "warn", + "keyword-spacing": "off", + "space-before-blocks": "warn", + "semi-spacing": "warn" + }, + "overrides": [ + { + "files": ["**/*.ts", "**/*.tsx"], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": ["tsconfig.json", "tsconfig.commonjs.json"], + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "@typescript-eslint/ban-types": "off", + "@typescript-eslint/class-name-casing": "off", + "@typescript-eslint/indent": [ + "error", + 4, + { + "ignoredNodes": ["TypeExpression"], + "SwitchCase": 1 + } + ], + "@typescript-eslint/member-delimiter-style": [ + "off", + { + "multiline": { + "delimiter": "none", + "requireLast": true + }, + "singleline": { + "delimiter": "semi", + "requireLast": false + } + } + ], + "@typescript-eslint/prefer-namespace-keyword": "warn", + "@typescript-eslint/quotes": [ + "error", + "single", + { + "avoidEscape": true, + "allowTemplateLiterals": true + } + ], + "@typescript-eslint/semi": [ + "off", + null + ], + "@typescript-eslint/type-annotation-spacing": "error", + "@typescript-eslint/brace-style": [ + "error", + "1tbs", { "allowSingleLine": true } + ], + "@typescript-eslint/comma-spacing": "warn", + "@typescript-eslint/space-infix-ops": "warn", + "@typescript-eslint/space-before-function-paren": ["warn", { + "anonymous": "always", + "named": "never", + "asyncArrow": "always" + }], + "@typescript-eslint/func-call-spacing": ["warn"], + "@typescript-eslint/keyword-spacing": ["warn"] + } + } + ] +} \ No newline at end of file diff --git a/frontend/venome-molstar/.gitattributes b/frontend/venome-molstar/.gitattributes new file mode 100644 index 00000000..20eac601 --- /dev/null +++ b/frontend/venome-molstar/.gitattributes @@ -0,0 +1 @@ +package-lock.json binary \ No newline at end of file diff --git a/frontend/venome-molstar/.github/workflows/node.yml b/frontend/venome-molstar/.github/workflows/node.yml new file mode 100644 index 00000000..ecf223a2 --- /dev/null +++ b/frontend/venome-molstar/.github/workflows/node.yml @@ -0,0 +1,19 @@ +name: Build + +on: + push: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 16 + - run: npm ci + - name: Lint + run: npm run lint + - name: Build + run: npm run build diff --git a/frontend/venome-molstar/.gitignore b/frontend/venome-molstar/.gitignore new file mode 100644 index 00000000..f95a82de --- /dev/null +++ b/frontend/venome-molstar/.gitignore @@ -0,0 +1,10 @@ +build/ + +node_modules/ +debug.log +npm-debug.log +tsconfig.tsbuildinfo + +*.sublime-workspace +.idea +.DS_Store diff --git a/frontend/venome-molstar/.npmignore b/frontend/venome-molstar/.npmignore new file mode 100644 index 00000000..f6314701 --- /dev/null +++ b/frontend/venome-molstar/.npmignore @@ -0,0 +1,3 @@ +!build/ +src/ +lib/ \ No newline at end of file diff --git a/frontend/venome-molstar/CHANGELOG.md b/frontend/venome-molstar/CHANGELOG.md new file mode 100644 index 00000000..5f6ec55d --- /dev/null +++ b/frontend/venome-molstar/CHANGELOG.md @@ -0,0 +1,50 @@ +# Change Log +All notable changes to this project will be documented in this file, following the suggestions of [Keep a CHANGELOG](http://keepachangelog.com/). This project adheres to [Semantic Versioning](http://semver.org/) for its most widely used - and defacto - public interfaces. + +## [Unreleased] + +- Mol* core dependency updated to 3.44.0 +- Removed Assembly Symmetry hack (now will hide assembly symmetry section for non-biological assemblies) +- Manual testing via `portfolio.html` +- Fixed hideStructure.nonStandard option +- hideStructure.het option also hides ions +- Removed loadCartoonsOnly option +- Setting highlight and selection color (by `.visual.setColor()`) includes the outline color +- Web-component attributes renamed to `ligand-auth-asym-id` and `ligand-struct-asym-id` (lowercase i) + +## [v3.1.3] +- Added ``Assembly Symmetry`` to structure controls, requires setting ``symmetryAnnotation`` in initialization parameters +- Keep sequence panel in settings even when initially hidden +- Changed `tsconfig.json` to place `tsconfig.tsbuildinfo` correctly (for incremental build) +- Fixed coloring after annotation is switched off (revert to `chain-id`, not `polymer-id`) +- Loading overlay with animated PDBe logo (requires initParam `loadingOverlay`) +- Use linting to keep code nice +- Correctly handle numeric value 0 in selections +- Fetch structures from static files when possible, instead of using ModelServer + +## [v3.1.2] +- Added PDBe Sifts Mappings module to solve UniPort mappings issue +- Split Webpack config file into separate files for Production and Development + +## [v3.1.1] +- Controls menu visible for AlphaFold view +- ``Reactive`` parameter addition for better responsive layout support + +## [v3.1.0] +- Mol* core dependency updated to V3.15.0 +- Superposition view - added option to superpose AlphaFold model +- UniPort residue numbering param addition to higlight and selection helper methods +- New param to display Sequence panel [62](https://github.com/molstar/lib/pdbe-molstar/lib/issues/62) + +## [v1.2.1] - 2021-12-03 +- Selection helper method ``representationColor`` param issue fix + +## [v1.2.0] - 2021-09-20 +- Add parameters to support AlphaFold Protein Structure DB view +- Add parameters to customize mouse events, issues [#8](https://github.com/PDBeurope/pdbe-molstar/lib/issues/8) +- Add parameter to customize ``lighting`` setting +- Extend ``Selection / highlight`` helper methods to support ``label_atom_id`` list, issues [#32](https://github.com/PDBeurope/pdbe-molstar/lib/issues/32) +- Extend helper methods support for multiple structures +- Extend ``hideCanvasControls`` +- Fix Frame rate drop issue while rotating the canvas +- Fix RGB color issue for params starting with r:0 \ No newline at end of file diff --git a/frontend/venome-molstar/LICENSE b/frontend/venome-molstar/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/frontend/venome-molstar/LICENSE @@ -0,0 +1,201 @@ + 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 [yyyy] [name of copyright owner] + + 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/frontend/venome-molstar/README.md b/frontend/venome-molstar/README.md new file mode 100644 index 00000000..016f9a86 --- /dev/null +++ b/frontend/venome-molstar/README.md @@ -0,0 +1,26 @@ +# PDBe Molstar + +PDBe implementation of [Mol\* (/'mol-star/)](https://github.com/molstar/lib/molstar) + +**Refer [PDBe Molstar Wiki](https://github.com/PDBeurope/pdbe-molstar/lib/wiki) for detailed documentation and examples** + +## Building & Running locally + +```sh +npm install +npm run build +# npm run rebuild # for a clean build +npm run serve +``` + +## Build automatically on file save: + +```sh +npm run watch +``` + +## Manual testing + +- Run locally by `npm run serve` +- Go to and check the viewer with various different setting (some of these reflect the actual setting on PDBe pages) +- If you want to tweak the options, go to "Frame URL" and change the options in the URL diff --git a/frontend/venome-molstar/component-demo.html b/frontend/venome-molstar/component-demo.html new file mode 100644 index 00000000..799f1046 --- /dev/null +++ b/frontend/venome-molstar/component-demo.html @@ -0,0 +1,232 @@ + + + + + + + PDBe Molstar Component Demo + + + + + + + + + + + + + + + +

PDBe Molstar Component

+ +
+
+

Canvas/ layout methods

+
+

Set Background

+ + + +

Toggle controls menu

+ + + + +

Toggle Fullscreen

+ +
+ +

Visual Methods

+
+

Change representation visibility

+ + + +

Toggle Spin

+ + + + +

Focus

+ + +

Highlight

+ + + +

Selection

+ +
+ +
+ +
+ +
+ +
+ + +

Set highlight / selection colour

+ + +
+ + + +

Reset Visual

+ + + + +

Update data

+ + +
+
+ +
+

PDBe Mol* Web-component Demo

+ +
+ + +
+ +
+
+ + + + + + \ No newline at end of file diff --git a/frontend/venome-molstar/example/.gitignore b/frontend/venome-molstar/example/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/frontend/venome-molstar/example/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/frontend/venome-molstar/example/.vscode/extensions.json b/frontend/venome-molstar/example/.vscode/extensions.json new file mode 100644 index 00000000..bdef8201 --- /dev/null +++ b/frontend/venome-molstar/example/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["svelte.svelte-vscode"] +} diff --git a/frontend/venome-molstar/example/README.md b/frontend/venome-molstar/example/README.md new file mode 100644 index 00000000..e6cd94fc --- /dev/null +++ b/frontend/venome-molstar/example/README.md @@ -0,0 +1,47 @@ +# Svelte + TS + Vite + +This template should help get you started developing with Svelte and TypeScript in Vite. + +## Recommended IDE Setup + +[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). + +## Need an official Svelte framework? + +Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more. + +## Technical considerations + +**Why use this over SvelteKit?** + +- It brings its own routing solution which might not be preferable for some users. +- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. + +This template contains as little as possible to get started with Vite + TypeScript + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project. + +Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate. + +**Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** + +Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information. + +**Why include `.vscode/extensions.json`?** + +Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project. + +**Why enable `allowJs` in the TS template?** + +While `allowJs: false` would indeed prevent the use of `.js` files in the project, it does not prevent the use of JavaScript syntax in `.svelte` files. In addition, it would force `checkJs: false`, bringing the worst of both worlds: not being able to guarantee the entire codebase is TypeScript, and also having worse typechecking for the existing JavaScript. In addition, there are valid use cases in which a mixed codebase may be relevant. + +**Why is HMR not preserving my local component state?** + +HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr). + +If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR. + +```ts +// store.ts +// An extremely simple external store +import { writable } from 'svelte/store' +export default writable(0) +``` diff --git a/frontend/venome-molstar/example/index.html b/frontend/venome-molstar/example/index.html new file mode 100644 index 00000000..b6c5f0af --- /dev/null +++ b/frontend/venome-molstar/example/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + Svelte + TS + + +
+ + + diff --git a/frontend/venome-molstar/example/package.json b/frontend/venome-molstar/example/package.json new file mode 100644 index 00000000..97841b33 --- /dev/null +++ b/frontend/venome-molstar/example/package.json @@ -0,0 +1,21 @@ +{ + "name": "test", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-check --tsconfig ./tsconfig.json" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.1", + "@tsconfig/svelte": "^5.0.2", + "svelte": "^4.2.8", + "svelte-check": "^3.6.2", + "tslib": "^2.6.2", + "typescript": "^5.2.2", + "vite": "^5.0.8" + } +} diff --git a/frontend/venome-molstar/example/public/vite.svg b/frontend/venome-molstar/example/public/vite.svg new file mode 100644 index 00000000..e7b8dfb1 --- /dev/null +++ b/frontend/venome-molstar/example/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/venome-molstar/example/src/App.svelte b/frontend/venome-molstar/example/src/App.svelte new file mode 100644 index 00000000..df6f9844 --- /dev/null +++ b/frontend/venome-molstar/example/src/App.svelte @@ -0,0 +1,69 @@ + + +
+ + + + + + diff --git a/frontend/venome-molstar/example/src/app.css b/frontend/venome-molstar/example/src/app.css new file mode 100644 index 00000000..e69de29b diff --git a/frontend/venome-molstar/example/src/assets/svelte.svg b/frontend/venome-molstar/example/src/assets/svelte.svg new file mode 100644 index 00000000..c5e08481 --- /dev/null +++ b/frontend/venome-molstar/example/src/assets/svelte.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/venome-molstar/example/src/main.ts b/frontend/venome-molstar/example/src/main.ts new file mode 100644 index 00000000..8a909a15 --- /dev/null +++ b/frontend/venome-molstar/example/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' +import App from './App.svelte' + +const app = new App({ + target: document.getElementById('app'), +}) + +export default app diff --git a/frontend/venome-molstar/example/src/vite-env.d.ts b/frontend/venome-molstar/example/src/vite-env.d.ts new file mode 100644 index 00000000..4078e747 --- /dev/null +++ b/frontend/venome-molstar/example/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/frontend/venome-molstar/example/svelte.config.js b/frontend/venome-molstar/example/svelte.config.js new file mode 100644 index 00000000..b0683fd2 --- /dev/null +++ b/frontend/venome-molstar/example/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/frontend/venome-molstar/example/tsconfig.json b/frontend/venome-molstar/example/tsconfig.json new file mode 100644 index 00000000..5fb548f2 --- /dev/null +++ b/frontend/venome-molstar/example/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/frontend/venome-molstar/example/tsconfig.node.json b/frontend/venome-molstar/example/tsconfig.node.json new file mode 100644 index 00000000..494bfe08 --- /dev/null +++ b/frontend/venome-molstar/example/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/frontend/venome-molstar/example/vite.config.ts b/frontend/venome-molstar/example/vite.config.ts new file mode 100644 index 00000000..d7019694 --- /dev/null +++ b/frontend/venome-molstar/example/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte()], +}) diff --git a/frontend/venome-molstar/example/yarn.lock b/frontend/venome-molstar/example/yarn.lock new file mode 100644 index 00000000..cc3f075d --- /dev/null +++ b/frontend/venome-molstar/example/yarn.lock @@ -0,0 +1,865 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@esbuild/aix-ppc64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz#d1bc06aedb6936b3b6d313bf809a5a40387d2b7f" + integrity sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA== + +"@esbuild/android-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz#7ad65a36cfdb7e0d429c353e00f680d737c2aed4" + integrity sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA== + +"@esbuild/android-arm@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz#b0c26536f37776162ca8bde25e42040c203f2824" + integrity sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w== + +"@esbuild/android-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.12.tgz#cb13e2211282012194d89bf3bfe7721273473b3d" + integrity sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew== + +"@esbuild/darwin-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz#cbee41e988020d4b516e9d9e44dd29200996275e" + integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g== + +"@esbuild/darwin-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz#e37d9633246d52aecf491ee916ece709f9d5f4cd" + integrity sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A== + +"@esbuild/freebsd-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz#1ee4d8b682ed363b08af74d1ea2b2b4dbba76487" + integrity sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA== + +"@esbuild/freebsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz#37a693553d42ff77cd7126764b535fb6cc28a11c" + integrity sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg== + +"@esbuild/linux-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz#be9b145985ec6c57470e0e051d887b09dddb2d4b" + integrity sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA== + +"@esbuild/linux-arm@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz#207ecd982a8db95f7b5279207d0ff2331acf5eef" + integrity sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w== + +"@esbuild/linux-ia32@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz#d0d86b5ca1562523dc284a6723293a52d5860601" + integrity sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA== + +"@esbuild/linux-loong64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz#9a37f87fec4b8408e682b528391fa22afd952299" + integrity sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA== + +"@esbuild/linux-mips64el@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz#4ddebd4e6eeba20b509d8e74c8e30d8ace0b89ec" + integrity sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w== + +"@esbuild/linux-ppc64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz#adb67dadb73656849f63cd522f5ecb351dd8dee8" + integrity sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg== + +"@esbuild/linux-riscv64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz#11bc0698bf0a2abf8727f1c7ace2112612c15adf" + integrity sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg== + +"@esbuild/linux-s390x@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz#e86fb8ffba7c5c92ba91fc3b27ed5a70196c3cc8" + integrity sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg== + +"@esbuild/linux-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz#5f37cfdc705aea687dfe5dfbec086a05acfe9c78" + integrity sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg== + +"@esbuild/netbsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz#29da566a75324e0d0dd7e47519ba2f7ef168657b" + integrity sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA== + +"@esbuild/openbsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz#306c0acbdb5a99c95be98bdd1d47c916e7dc3ff0" + integrity sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw== + +"@esbuild/sunos-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz#0933eaab9af8b9b2c930236f62aae3fc593faf30" + integrity sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA== + +"@esbuild/win32-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz#773bdbaa1971b36db2f6560088639ccd1e6773ae" + integrity sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A== + +"@esbuild/win32-ia32@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz#000516cad06354cc84a73f0943a4aa690ef6fd67" + integrity sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ== + +"@esbuild/win32-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae" + integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA== + +"@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/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": + 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.18", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.22" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz#72a621e5de59f5f1ef792d0793a82ee20f645e4c" + integrity sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw== + 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": + 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" + +"@rollup/rollup-android-arm-eabi@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz#66b8d9cb2b3a474d115500f9ebaf43e2126fe496" + integrity sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg== + +"@rollup/rollup-android-arm64@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz#46327d5b86420d2307946bec1535fdf00356e47d" + integrity sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw== + +"@rollup/rollup-darwin-arm64@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz#166987224d2f8b1e2fd28ee90c447d52271d5e90" + integrity sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw== + +"@rollup/rollup-darwin-x64@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz#a2e6e096f74ccea6e2f174454c26aef6bcdd1274" + integrity sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog== + +"@rollup/rollup-linux-arm-gnueabihf@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz#09fcd4c55a2d6160c5865fec708a8e5287f30515" + integrity sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ== + +"@rollup/rollup-linux-arm64-gnu@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz#19a3c0b6315c747ca9acf86e9b710cc2440f83c9" + integrity sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ== + +"@rollup/rollup-linux-arm64-musl@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz#94aaf95fdaf2ad9335983a4552759f98e6b2e850" + integrity sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ== + +"@rollup/rollup-linux-riscv64-gnu@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz#160510e63f4b12618af4013bddf1761cf9fc9880" + integrity sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA== + +"@rollup/rollup-linux-x64-gnu@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz#5ac5d068ce0726bd0a96ca260d5bd93721c0cb98" + integrity sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw== + +"@rollup/rollup-linux-x64-musl@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz#bafa759ab43e8eab9edf242a8259ffb4f2a57a5d" + integrity sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ== + +"@rollup/rollup-win32-arm64-msvc@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz#1cc3416682e5a20d8f088f26657e6e47f8db468e" + integrity sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA== + +"@rollup/rollup-win32-ia32-msvc@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz#7d2251e1aa5e8a1e47c86891fe4547a939503461" + integrity sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ== + +"@rollup/rollup-win32-x64-msvc@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz#2c1fb69e02a3f1506f52698cfdc3a8b6386df9a6" + integrity sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ== + +"@sveltejs/vite-plugin-svelte-inspector@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.0.0.tgz#365afaa0dd63517838ce4686a3dc3982be348a9b" + integrity sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg== + dependencies: + debug "^4.3.4" + +"@sveltejs/vite-plugin-svelte@^3.0.1": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.0.2.tgz#5c33534d07130283cff92304f627010387c11af0" + integrity sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q== + dependencies: + "@sveltejs/vite-plugin-svelte-inspector" "^2.0.0" + debug "^4.3.4" + deepmerge "^4.3.1" + kleur "^4.1.5" + magic-string "^0.30.5" + svelte-hmr "^0.15.3" + vitefu "^0.2.5" + +"@tsconfig/svelte@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@tsconfig/svelte/-/svelte-5.0.2.tgz#c9ed3575c5445afb14965bb76e8446fbf7e4a0e6" + integrity sha512-BRbo1fOtyVbhfLyuCWw6wAWp+U8UQle+ZXu84MYYWzYSEB28dyfnRBIE99eoG+qdAC0po6L2ScIEivcT07UaMA== + +"@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.0", "@types/estree@^1.0.1": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + +"@types/pug@^2.0.6": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@types/pug/-/pug-2.0.10.tgz#52f8dbd6113517aef901db20b4f3fca543b88c1f" + integrity sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA== + +acorn@^8.10.0, acorn@^8.9.0: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + +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" + +aria-query@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" + integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== + dependencies: + dequal "^2.0.3" + +axobject-query@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.0.0.tgz#04a4c90dce33cc5d606c76d6216e3b250ff70dab" + integrity sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw== + dependencies: + dequal "^2.0.3" + +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== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2, 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" + +buffer-crc32@^0.2.5: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + +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== + +chokidar@^3.4.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + 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" + +code-red@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/code-red/-/code-red-1.0.4.tgz#59ba5c9d1d320a4ef795bc10a28bd42bfebe3e35" + integrity sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + "@types/estree" "^1.0.1" + acorn "^8.10.0" + estree-walker "^3.0.3" + periscopic "^3.1.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +css-tree@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20" + integrity sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw== + dependencies: + mdn-data "2.0.30" + source-map-js "^1.0.1" + +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" + +deepmerge@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +dequal@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + +detect-indent@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" + integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== + +es6-promise@^3.1.2: + version "3.3.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" + integrity sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg== + +esbuild@^0.19.3: + version "0.19.12" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04" + integrity sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.19.12" + "@esbuild/android-arm" "0.19.12" + "@esbuild/android-arm64" "0.19.12" + "@esbuild/android-x64" "0.19.12" + "@esbuild/darwin-arm64" "0.19.12" + "@esbuild/darwin-x64" "0.19.12" + "@esbuild/freebsd-arm64" "0.19.12" + "@esbuild/freebsd-x64" "0.19.12" + "@esbuild/linux-arm" "0.19.12" + "@esbuild/linux-arm64" "0.19.12" + "@esbuild/linux-ia32" "0.19.12" + "@esbuild/linux-loong64" "0.19.12" + "@esbuild/linux-mips64el" "0.19.12" + "@esbuild/linux-ppc64" "0.19.12" + "@esbuild/linux-riscv64" "0.19.12" + "@esbuild/linux-s390x" "0.19.12" + "@esbuild/linux-x64" "0.19.12" + "@esbuild/netbsd-x64" "0.19.12" + "@esbuild/openbsd-x64" "0.19.12" + "@esbuild/sunos-x64" "0.19.12" + "@esbuild/win32-arm64" "0.19.12" + "@esbuild/win32-ia32" "0.19.12" + "@esbuild/win32-x64" "0.19.12" + +estree-walker@^3.0.0, estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + +fast-glob@^3.2.7: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + 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" + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.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" + +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, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +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@^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" + +graceful-fs@^4.1.3: + 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== + +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" + +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: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +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-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-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-reference@^3.0.0, is-reference@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.2.tgz#154747a01f45cd962404ee89d43837af2cba247c" + integrity sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg== + dependencies: + "@types/estree" "*" + +kleur@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" + integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== + +locate-character@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-3.0.0.tgz#0305c5b8744f61028ef5d01f444009e00779f974" + integrity sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA== + +magic-string@^0.30.4, magic-string@^0.30.5: + version "0.30.7" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.7.tgz#0cecd0527d473298679da95a2d7aeb8c64048505" + integrity sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + +mdn-data@2.0.30: + version "2.0.30" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" + integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +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" + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +minimatch@^3.1.1: + 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" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp@^0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mri@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" + integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +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== + +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" + +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" + +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== + +periscopic@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/periscopic/-/periscopic-3.1.0.tgz#7e9037bf51c5855bd33b48928828db4afa79d97a" + integrity sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^3.0.0" + is-reference "^3.0.0" + +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== + +postcss@^8.4.32: + version "8.4.34" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.34.tgz#563276e86b4ff20dfa5eed0d394d4c53853b2051" + integrity sha512-4eLTO36woPSocqZ1zIrFD2K1v6wH7pY1uBh0JIM2KKfrVtGvPFiAku6aNOP0W1Wr9qwnaCsF0Z+CrVnryB2A8Q== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +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== + +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" + +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== + +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@^2.5.2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rollup@^4.2.0: + version "4.9.6" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.9.6.tgz#4515facb0318ecca254a2ee1315e22e09efc50a0" + integrity sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg== + dependencies: + "@types/estree" "1.0.5" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.9.6" + "@rollup/rollup-android-arm64" "4.9.6" + "@rollup/rollup-darwin-arm64" "4.9.6" + "@rollup/rollup-darwin-x64" "4.9.6" + "@rollup/rollup-linux-arm-gnueabihf" "4.9.6" + "@rollup/rollup-linux-arm64-gnu" "4.9.6" + "@rollup/rollup-linux-arm64-musl" "4.9.6" + "@rollup/rollup-linux-riscv64-gnu" "4.9.6" + "@rollup/rollup-linux-x64-gnu" "4.9.6" + "@rollup/rollup-linux-x64-musl" "4.9.6" + "@rollup/rollup-win32-arm64-msvc" "4.9.6" + "@rollup/rollup-win32-ia32-msvc" "4.9.6" + "@rollup/rollup-win32-x64-msvc" "4.9.6" + fsevents "~2.3.2" + +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" + +sade@^1.7.4: + version "1.8.1" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" + integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== + dependencies: + mri "^1.1.0" + +sander@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/sander/-/sander-0.5.1.tgz#741e245e231f07cafb6fdf0f133adfa216a502ad" + integrity sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA== + dependencies: + es6-promise "^3.1.2" + graceful-fs "^4.1.3" + mkdirp "^0.5.1" + rimraf "^2.5.2" + +sorcery@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/sorcery/-/sorcery-0.11.0.tgz#310c80ee993433854bb55bb9aa4003acd147fca8" + integrity sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.14" + buffer-crc32 "^0.2.5" + minimist "^1.2.0" + sander "^0.5.0" + +source-map-js@^1.0.1, source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +svelte-check@^3.6.2: + version "3.6.3" + resolved "https://registry.yarnpkg.com/svelte-check/-/svelte-check-3.6.3.tgz#416c9a83deb7c2030046824ebee10ab93bbcd394" + integrity sha512-Q2nGnoysxUnB9KjnjpQLZwdjK62DHyW6nuH/gm2qteFnDk0lCehe/6z8TsIvYeKjC6luKaWxiNGyOcWiLLPSwA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.17" + chokidar "^3.4.1" + fast-glob "^3.2.7" + import-fresh "^3.2.1" + picocolors "^1.0.0" + sade "^1.7.4" + svelte-preprocess "^5.1.0" + typescript "^5.0.3" + +svelte-hmr@^0.15.3: + version "0.15.3" + resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.15.3.tgz#df54ccde9be3f091bf5f18fc4ef7b8eb6405fbe6" + integrity sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ== + +svelte-preprocess@^5.1.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/svelte-preprocess/-/svelte-preprocess-5.1.3.tgz#7682239fe53f724c845b53026816fdfe15d028f9" + integrity sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw== + dependencies: + "@types/pug" "^2.0.6" + detect-indent "^6.1.0" + magic-string "^0.30.5" + sorcery "^0.11.0" + strip-indent "^3.0.0" + +svelte@^4.2.8: + version "4.2.10" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-4.2.10.tgz#3bef8d79ca75eb53cc4d03f9fac1546e60393f77" + integrity sha512-Ep06yCaCdgG1Mafb/Rx8sJ1QS3RW2I2BxGp2Ui9LBHSZ2/tO/aGLc5WqPjgiAP6KAnLJGaIr/zzwQlOo1b8MxA== + dependencies: + "@ampproject/remapping" "^2.2.1" + "@jridgewell/sourcemap-codec" "^1.4.15" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/estree" "^1.0.1" + acorn "^8.9.0" + aria-query "^5.3.0" + axobject-query "^4.0.0" + code-red "^1.0.3" + css-tree "^2.3.1" + estree-walker "^3.0.3" + is-reference "^3.0.1" + locate-character "^3.0.0" + magic-string "^0.30.4" + periscopic "^3.1.0" + +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" + +tslib@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + +typescript@^5.0.3, typescript@^5.2.2: + version "5.3.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" + integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== + +vite@^5.0.8: + version "5.0.12" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.12.tgz#8a2ffd4da36c132aec4adafe05d7adde38333c47" + integrity sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w== + dependencies: + esbuild "^0.19.3" + postcss "^8.4.32" + rollup "^4.2.0" + optionalDependencies: + fsevents "~2.3.3" + +vitefu@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/vitefu/-/vitefu-0.2.5.tgz#c1b93c377fbdd3e5ddd69840ea3aa70b40d90969" + integrity sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q== + +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== diff --git a/frontend/venome-molstar/favicon.ico b/frontend/venome-molstar/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..1991a6035fe20f3b1c3f4c0417049625c5a96d90 GIT binary patch literal 16958 zcmeHPYiu0V6&|w`1FC9@fT{?T{%IA_UscqK)a(NyN|CAnMe9&gyt_$cR8Rz-S*H<5 z^-`%SZ6$CMAe6Rg1VtehO5)wMF(i#Qg78oXkOV~P2(j2Ep{N*#M{tVm>34SbEW_-K z@0r=zg+`s|`s~cy^Z3r4IrrShMAKUEFBa4A_gmWHD>Ur_P16>m;F6X>q3i!Yg7ZLX zc+L6AyuLD#O+S*%r3;CiaU_}3KThV1DU^fBZ2Ae%jfuRzJUN;<)30XYg`8`X`SgRJ zBhYgQ^nH|%P{vS3Q65g^jYN0OIM1&h5ud5G0Ba|3KLed}D5kJ{fO=b2=8VfkdQd5u z?+p_V@O~)NLAJ~$v&NoOPG6zHR;eyYy+lr5hW6d>!4@~)JeJy_U+kuH)sV3WJ|3u7 z51z|?scagNpuVH~#qO`9vc{k4wa3PP0{*!X@`rfEx7)e%RNyW z3waMqeGngrhY)vm3grfAV?$-pbC4O$oX&0RMiE2TpK92vc+ii!;il_}!QS?2U3vf3 z&~^*j9_q{7e1K=BbF zeZNzF0GU7aBr9*cmKZW36ff-lj1Oeapqvcy-t#2W`I$S0{O<;mS*s@=qJADaC>Qkb z9Hu+%vcSJfC}R%&)!l1`*R(3(F28}D3$18=8dqq0X4ymku zvsd|CzY-7J+OK+@#;(i*yG8`Iopg#pEJH=Ray>r~=qTBj+F@LxlIM1x;xY6H`h|3X zWuX0OTwV2z^KbMUbsQ8gAy*P(KA@OUhbm3dj|1}&)&aYe{S>_;T;DH+o&(Ol{ml1d zyI=XtN4bbf56#zbebhasu5WDN`hF>NJg?UC*>mYzPu}>OT8}Zs@=^CiLH#kV@0UVH zbMVs~oZ@|^cb;+JnHyBq$Nl*mhu3_KdHm33;HN$i*gjR_!5k%Hkme1EywS}(erPlB zSMqK}EJwVtj0F?9-XAIbReqk1uO41|kss{D(`fuF2iIN*9W)26#7}e6jDz}h@QCs= zyeq?g`=>_YujJW766~lmZ6Ckj8qGy1{Z^^7w`)lM4*O3^!P}7d2f2$SeZB?XX1mQ@ zgZlSyUp9U!`{_g?Yy1ka<5KCEAV~b(xy;$Ay#7PH?{`7&j0Kyj4d*e(^?f^jIxny1 zh@Szgo>}To%Hup5>$w$!)qky)AB#=I+_1V_p9zO2?uteymo8ay^lT@Y_G@UbaKTxMgSLCm z#$rclijCkn3&yW6Ob;E}b|F_&%~>biz&7hBVFeH9y-Z{N#&L&VsQybVy>! zlyzSWp5yC<*r(dt$1k+{-plVs;wL+3ZU#DJef3b!kJ)zMe@KRZGQm84Xru9yO*BU* zd@PA703G?`&&A?A{w9q4&$EdEaMxzt23h*EBgW1Z{4E&@IdX)JI?Ga?# zfcU?&jjVFo zs{L`lu64Os?A@<+ZvM^FD!XXy!ag_4c1o#auP)8ku{^~8Q33uF@wi#D*N0`OXgK_K zdwl(dQ5Al=j~Kp0CC}}CWiDSbP8(qv!2hrSKXRW*-+PLYC;$4ozDH>cse1mgHe=ku zwt1yV?9q_upm&6216M+Ze`3r}AK2dh)^{O)=F00|ep6x_>R|su@3+}LDfP7f1$+5f zE^_(vVBf6F2jllLpM=I@=IM~Tk7Z-*{D#N}*rP=`twaacp}kom*|ZM>d%l>DDD2zA zHY(^m=1A^|#oknY*HM{Ic+x5_{>S^I`|R+Zq=#rt&uXXBZ~9II>p#B(_BkQ`U3NKm z2Rf{F3Vy$i`GSa3Or-HJV#;dBIBu77#qvY6*FqAXI8IE_ny%9t6Ycfs%IlXyp0~Z~ z*z0M>Pv@}p1-re1bDA&Oi?RX!*bI6IWx;o8#RL7L!ggXGnA9(V=K$!YdiKB4I-wKx zGXC)hY^O19Lrd(cv3G$*HcpfD7ar=+9&b1NWgk#GHWok0U#@5Od3^@zu8+O_3t^{w zm3Y0Y89wM(zaDdjf_xx=I(Tn(I_=eV@(23(b1^17+-M(!BjX!^e|r;r@H&0d}zYF6J2JC|mA#ask7uKC`sl@oe{6PC4 zCExtmZLyzY?7s|s+x|NJFi+!*aJcwQyL>)JyD!G~r8@#>{}<@n43--VHCuqc6MlFG zbk2h>CBZqE`1%X-y%jlh4LDFg8eaH!1vE?M*fdqH~E-v zG0jY$X-;d=S*^`93tHQ>7BWpuYb|2IV;=vFKt|L0X0_50ohj2r(`AafrK7D_rme*m zaP(zb3n54_3!y@*nQ1YLp+Xx@%;`{Oky>XIlJH$N~Q}$pwYn5Ya-Y2qmqi*2;FU zU2JcK0%Pf@Qohdhn2+TYwX$5+Q`K9s!!Hi-LDWnO`voUuKUMt3eq=k?E~acR + + + + + + PDBe Molstar + + + + + + + + + +

PDBe Molstar

+ +
+
+

Canvas/ layout methods

+
+

Set Background

+ + + +

Toggle controls menu

+ + + + +

Toggle Fullscreen

+ +
+ +

Visual Methods

+
+

Change representation visibility

+ + + +

Toggle Spin

+ + + + +

Focus

+ + +

Highlight

+ + + +

Selection

+ +
+ +
+ +
+ +
+ +
+ + +

Set highlight / selection colour

+ + +
+ + + +

Reset Visual

+ + + + +

Update data

+ + +
+ +
+

Options

+
+

+                
+
+
+ +
+

PDBe Mol* JS Plugin Demo

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/frontend/venome-molstar/lib/alphafold-transparency.d.ts b/frontend/venome-molstar/lib/alphafold-transparency.d.ts new file mode 100644 index 00000000..5196db37 --- /dev/null +++ b/frontend/venome-molstar/lib/alphafold-transparency.d.ts @@ -0,0 +1,6 @@ +import { StructureElement } from "molstar/lib/mol-model/structure"; +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import { StructureComponentRef, StructureRef } from "molstar/lib/mol-plugin-state/manager/structure/hierarchy-state"; +export declare function applyAFTransparency(plugin: PluginContext, structure: Readonly, transparency: number, pLDDT?: number): Promise; +export declare function setStructureTransparency(plugin: PluginContext, components: StructureComponentRef[], value: number, loci: StructureElement.Loci, types?: string[]): Promise; +export declare function clearStructureTransparency(plugin: PluginContext, components: StructureComponentRef[], types?: string[]): Promise; diff --git a/frontend/venome-molstar/lib/alphafold-transparency.js b/frontend/venome-molstar/lib/alphafold-transparency.js new file mode 100644 index 00000000..46710f0d --- /dev/null +++ b/frontend/venome-molstar/lib/alphafold-transparency.js @@ -0,0 +1,98 @@ +import { StructureElement } from "molstar/lib/mol-model/structure"; +import { StateTransforms } from "molstar/lib/mol-plugin-state/transforms"; +import { StateSelection, } from "molstar/lib/mol-state"; +import { isEmptyLoci, Loci } from "molstar/lib/mol-model/loci"; +import { Transparency } from "molstar/lib/mol-theme/transparency"; +import { MolScriptBuilder as MS } from "molstar/lib/mol-script/language/builder"; +import { QualityAssessment } from "molstar/lib/extensions/model-archive/quality-assessment/prop"; +import { compile } from "molstar/lib/mol-script/runtime/query/compiler"; +import { StructureSelection, QueryContext, } from "molstar/lib/mol-model/structure"; +const TransparencyManagerTag = "transparency-controls"; +function getLociByPLDDT(score, contextData) { + const queryExp = MS.struct.modifier.union([ + MS.struct.modifier.wholeResidues([ + MS.struct.modifier.union([ + MS.struct.generator.atomGroups({ + "chain-test": MS.core.rel.eq([ + MS.ammp("objectPrimitive"), + "atomistic", + ]), + "residue-test": MS.core.rel.lte([ + QualityAssessment.symbols.pLDDT.symbol(), + score, + ]), + }), + ]), + ]), + ]); + const query = compile(queryExp); + const sel = query(new QueryContext(contextData)); + return StructureSelection.toLociWithSourceUnits(sel); +} +export async function applyAFTransparency(plugin, structure, transparency, pLDDT = 70) { + return plugin.dataTransaction(async (ctx) => { + const loci = getLociByPLDDT(pLDDT, structure.cell.obj.data); + await setStructureTransparency(plugin, structure.components, transparency, loci); + }, { canUndo: "Apply Transparency" }); +} +export async function setStructureTransparency(plugin, components, value, loci, types) { + await eachRepr(plugin, components, async (update, repr, transparencyCell) => { + if (types && + types.length > 0 && + !types.includes(repr.params.values.type.name)) + return; + const structure = repr.obj.data.sourceData; + if (Loci.isEmpty(loci) || isEmptyLoci(loci)) + return; + const layer = { + bundle: StructureElement.Bundle.fromLoci(loci), + value, + }; + if (transparencyCell) { + const bundleLayers = [ + ...transparencyCell.params.values.layers, + layer, + ]; + const filtered = getFilteredBundle(bundleLayers, structure); + update + .to(transparencyCell) + .update(Transparency.toBundle(filtered)); + } + else { + const filtered = getFilteredBundle([layer], structure); + update + .to(repr.transform.ref) + .apply(StateTransforms.Representation + .TransparencyStructureRepresentation3DFromBundle, Transparency.toBundle(filtered), { tags: TransparencyManagerTag }); + } + }); +} +export async function clearStructureTransparency(plugin, components, types) { + await eachRepr(plugin, components, async (update, repr, transparencyCell) => { + if (types && + types.length > 0 && + !types.includes(repr.params.values.type.name)) + return; + if (transparencyCell) { + update.delete(transparencyCell.transform.ref); + } + }); +} +async function eachRepr(plugin, components, callback) { + const state = plugin.state.data; + const update = state.build(); + for (const c of components) { + for (const r of c.representations) { + const transparency = state.select(StateSelection.Generators.ofTransformer(StateTransforms.Representation + .TransparencyStructureRepresentation3DFromBundle, r.cell.transform.ref).withTag(TransparencyManagerTag)); + await callback(update, r.cell, transparency[0]); + } + } + return update.commit({ doNotUpdateCurrent: true }); +} +/** filter transparency layers for given structure */ +function getFilteredBundle(layers, structure) { + const transparency = Transparency.ofBundle(layers, structure.root); + const merged = Transparency.merge(transparency); + return Transparency.filter(merged, structure); +} diff --git a/frontend/venome-molstar/lib/custom-events.d.ts b/frontend/venome-molstar/lib/custom-events.d.ts new file mode 100644 index 00000000..9366968d --- /dev/null +++ b/frontend/venome-molstar/lib/custom-events.d.ts @@ -0,0 +1,4 @@ +import { PluginContext } from "molstar/lib/mol-plugin/context"; +export declare namespace CustomEvents { + function add(plugin: PluginContext, targetElement: HTMLElement): void; +} diff --git a/frontend/venome-molstar/lib/custom-events.js b/frontend/venome-molstar/lib/custom-events.js new file mode 100644 index 00000000..3af52bc3 --- /dev/null +++ b/frontend/venome-molstar/lib/custom-events.js @@ -0,0 +1,68 @@ +import { lociDetails } from "./loci-details"; +import { debounceTime } from "rxjs/operators"; +export var CustomEvents; +(function (CustomEvents) { + function create(eventTypeArr) { + const eventObj = {}; + for (let ei = 0, el = eventTypeArr.length; ei < el; ei++) { + const eventType = eventTypeArr[ei]; + let event; + if (typeof MouseEvent == "function") { + // current standard + event = new MouseEvent(eventType, { + view: window, + bubbles: true, + cancelable: true, + }); + } + else if (typeof document.createEvent == "function") { + // older standard + event = document.createEvent("MouseEvents"); + event.initEvent(eventType, true /* bubbles */, true /* cancelable */); + } + eventObj[eventType] = event; + } + return eventObj; + } + function dispatchCustomEvent(event, eventData, targetElement) { + if (typeof eventData !== "undefined") { + eventData["residueNumber"] = eventData.seq_id; + event["eventData"] = eventData; + event.eventData.residueNumber = eventData.seq_id; + targetElement.dispatchEvent(event); + } + } + function add(plugin, targetElement) { + const pdbevents = create([ + "PDB.molstar.click", + "PDB.molstar.mouseover", + "PDB.molstar.mouseout", + ]); + plugin.behaviors.interaction.click.subscribe((e) => { + if (e.button === 1 && + e.current && + e.current.loci.kind !== "empty-loci") { + const evData = lociDetails(e.current.loci); + if (evData) + dispatchCustomEvent(pdbevents["PDB.molstar.click"], evData, targetElement); + } + }); + plugin.behaviors.interaction.hover + .pipe(debounceTime(100)) + .subscribe((e) => { + if (e.current && + e.current.loci && + e.current.loci.kind !== "empty-loci") { + const evData = lociDetails(e.current.loci); + if (evData) + dispatchCustomEvent(pdbevents["PDB.molstar.mouseover"], evData, targetElement); + } + if (e.current && + e.current.loci && + e.current.loci.kind === "empty-loci") { + dispatchCustomEvent(pdbevents["PDB.molstar.mouseout"], {}, targetElement); + } + }); + } + CustomEvents.add = add; +})(CustomEvents || (CustomEvents = {})); diff --git a/frontend/venome-molstar/lib/domain-annotations/behavior.d.ts b/frontend/venome-molstar/lib/domain-annotations/behavior.d.ts new file mode 100644 index 00000000..3eb05ed7 --- /dev/null +++ b/frontend/venome-molstar/lib/domain-annotations/behavior.d.ts @@ -0,0 +1,5 @@ +import { PluginBehavior } from "molstar/lib/mol-plugin/behavior"; +export declare const PDBeDomainAnnotations: import("molstar/lib/mol-state/transformer").StateTransformer; diff --git a/frontend/venome-molstar/lib/domain-annotations/behavior.js b/frontend/venome-molstar/lib/domain-annotations/behavior.js new file mode 100644 index 00000000..74dc9920 --- /dev/null +++ b/frontend/venome-molstar/lib/domain-annotations/behavior.js @@ -0,0 +1,39 @@ +import { DomainAnnotationsProvider } from "./prop"; +import { DomainAnnotationsColorThemeProvider } from "./color"; +import { ParamDefinition as PD } from "molstar/lib/mol-util/param-definition"; +import { PluginBehavior } from "molstar/lib/mol-plugin/behavior"; +export const PDBeDomainAnnotations = PluginBehavior.create({ + name: "pdbe-domain-annotations-prop", + category: "custom-props", + display: { + name: "Domain annotations", + description: "Data for domain annotations, obtained via PDBe.", + }, + ctor: class extends PluginBehavior.Handler { + provider = DomainAnnotationsProvider; + labelDomainAnnotations = { + label: (loci) => void 0, + }; + register() { + this.ctx.customModelProperties.register(this.provider, this.params.autoAttach); + this.ctx.managers.lociLabels.addProvider(this.labelDomainAnnotations); + this.ctx.representation.structure.themes.colorThemeRegistry.add(DomainAnnotationsColorThemeProvider); + } + update(p) { + const updated = this.params.autoAttach !== p.autoAttach; + this.params.autoAttach = p.autoAttach; + this.params.showTooltip = p.showTooltip; + this.ctx.customModelProperties.setDefaultAutoAttach(this.provider.descriptor.name, this.params.autoAttach); + return updated; + } + unregister() { + this.ctx.customModelProperties.unregister(DomainAnnotationsProvider.descriptor.name); + this.ctx.managers.lociLabels.removeProvider(this.labelDomainAnnotations); + this.ctx.representation.structure.themes.colorThemeRegistry.remove(DomainAnnotationsColorThemeProvider); + } + }, + params: () => ({ + autoAttach: PD.Boolean(false), + showTooltip: PD.Boolean(true), + }), +}); diff --git a/frontend/venome-molstar/lib/domain-annotations/color.d.ts b/frontend/venome-molstar/lib/domain-annotations/color.d.ts new file mode 100644 index 00000000..f4f34182 --- /dev/null +++ b/frontend/venome-molstar/lib/domain-annotations/color.d.ts @@ -0,0 +1,10 @@ +import { ColorTheme } from "molstar/lib/mol-theme/color"; +import { ThemeDataContext } from "molstar/lib/mol-theme/theme"; +import { ParamDefinition as PD } from "molstar/lib/mol-util/param-definition"; +export declare const DomainAnnotationsColorThemeParams: { + type: PD.Mapped, "">>; +}; +type Params = any; +export declare function DomainAnnotationsColorTheme(ctx: ThemeDataContext, props: PD.Values): ColorTheme; +export declare const DomainAnnotationsColorThemeProvider: ColorTheme.Provider; +export {}; diff --git a/frontend/venome-molstar/lib/domain-annotations/color.js b/frontend/venome-molstar/lib/domain-annotations/color.js new file mode 100644 index 00000000..e1256f08 --- /dev/null +++ b/frontend/venome-molstar/lib/domain-annotations/color.js @@ -0,0 +1,81 @@ +import { DomainAnnotations, DomainAnnotationsProvider } from "./prop"; +import { StructureElement } from "molstar/lib/mol-model/structure"; +import { ColorTheme } from "molstar/lib/mol-theme/color"; +import { Color } from "molstar/lib/mol-util/color"; +import { ParamDefinition as PD } from "molstar/lib/mol-util/param-definition"; +const DomainColors = [ + Color.fromRgb(170, 170, 170), + Color.fromRgb(255, 112, 3), +]; +export const DomainAnnotationsColorThemeParams = { + type: PD.MappedStatic("", { + "": PD.EmptyGroup(), + }), +}; +export function DomainAnnotationsColorTheme(ctx, props) { + let color; + if (ctx.structure && + !ctx.structure.isEmpty && + ctx.structure.models[0].customProperties.has(DomainAnnotationsProvider.descriptor)) { + const getDomains = DomainAnnotations.getDomains; + const issue = props.type.params.kind; + color = (location) => { + if (StructureElement.Location.is(location) && + getDomains(location).indexOf(issue) >= 0) { + return DomainColors[1]; + } + return DomainColors[0]; + }; + } + else { + color = () => DomainColors[0]; + } + return { + factory: DomainAnnotationsColorTheme, + granularity: "group", + color: color, + props: props, + description: "Highlights Sequnece and Structure Domain Annotations. Data obtained via PDBe.", + }; +} +export const DomainAnnotationsColorThemeProvider = { + name: "pdbe-domain-annotations", + label: "Domain annotations", + category: ColorTheme.Category.Misc, + factory: DomainAnnotationsColorTheme, + getParams: (ctx) => { + const domainNames = DomainAnnotations.getDomainNames(ctx.structure); + const domainTypes = DomainAnnotations.getDomainTypes(ctx.structure); + const optionObj = {}; + domainTypes.forEach((tp, index) => { + if (domainNames[index].length > 0) { + optionObj[tp] = PD.Group({ + kind: PD.Select(domainNames[index][0], PD.arrayToOptions(domainNames[index])), + }, { isFlat: true }); + } + }); + if (Object.keys(optionObj).length > 0) { + return { + type: PD.MappedStatic(optionObj[0], optionObj), + }; + } + else { + return { + type: PD.MappedStatic("", { + "": PD.EmptyGroup(), + }), + }; + } + }, + defaultValues: PD.getDefaultValues(DomainAnnotationsColorThemeParams), + isApplicable: (ctx) => DomainAnnotations.isApplicable(ctx.structure?.models[0]), + ensureCustomProperties: { + attach: (ctx, data) => { + return data.structure + ? DomainAnnotationsProvider.attach(ctx, data.structure.models[0], void 0, true) + : Promise.resolve(); + }, + detach: (data) => data.structure && + data.structure.models[0].customProperties.reference(DomainAnnotationsProvider.descriptor, false), + }, +}; diff --git a/frontend/venome-molstar/lib/domain-annotations/prop.d.ts b/frontend/venome-molstar/lib/domain-annotations/prop.d.ts new file mode 100644 index 00000000..b1985456 --- /dev/null +++ b/frontend/venome-molstar/lib/domain-annotations/prop.d.ts @@ -0,0 +1,35 @@ +import { Model, IndexedCustomProperty } from "molstar/lib/mol-model/structure"; +import { StructureElement, Structure } from "molstar/lib/mol-model/structure/structure"; +import { PropertyWrapper } from "molstar/lib/mol-model-props/common/wrapper"; +import { CustomModelProperty } from "molstar/lib/mol-model-props/common/custom-model-property"; +import { ParamDefinition as PD } from "molstar/lib/mol-util/param-definition"; +import { CustomProperty } from "molstar/lib/mol-model-props/common/custom-property"; +export { DomainAnnotations }; +type DomainAnnotations = PropertyWrapper<{ + domains: IndexedCustomProperty.Residue; + domainNames: string[][]; + domainTypes: string[]; +} | undefined>; +declare namespace DomainAnnotations { + const DefaultServerUrl = "https://www.ebi.ac.uk/pdbe/api/mappings"; + function getEntryUrl(pdbId: string, serverUrl: string): string; + function isApplicable(model?: Model): boolean; + function fromJson(model: Model, data: any): { + info: PropertyWrapper.Info; + data: { + domains: IndexedCustomProperty.Residue; + domainNames: string[][]; + domainTypes: string[]; + } | undefined; + }; + function fromServer(ctx: CustomProperty.Context, model: Model, props: DomainAnnotationsProps): Promise>; + function getDomains(e: StructureElement.Location): string[]; + function getDomainTypes(structure?: Structure): string[]; + function getDomainNames(structure?: Structure): string[] | string[][]; +} +export declare const DomainAnnotationsParams: { + serverUrl: PD.Text; +}; +export type DomainAnnotationsParams = typeof DomainAnnotationsParams; +export type DomainAnnotationsProps = PD.Values; +export declare const DomainAnnotationsProvider: CustomModelProperty.Provider; diff --git a/frontend/venome-molstar/lib/domain-annotations/prop.js b/frontend/venome-molstar/lib/domain-annotations/prop.js new file mode 100644 index 00000000..3573daa1 --- /dev/null +++ b/frontend/venome-molstar/lib/domain-annotations/prop.js @@ -0,0 +1,142 @@ +import { Model, Unit, IndexedCustomProperty, } from "molstar/lib/mol-model/structure"; +import { PropertyWrapper } from "molstar/lib/mol-model-props/common/wrapper"; +import { CustomModelProperty } from "molstar/lib/mol-model-props/common/custom-model-property"; +import { ParamDefinition as PD } from "molstar/lib/mol-util/param-definition"; +import { arraySetAdd } from "molstar/lib/mol-util/array"; +import { Asset } from "molstar/lib/mol-util/assets"; +import { CustomPropertyDescriptor } from "molstar/lib/mol-model/custom-property"; +export { DomainAnnotations }; +var DomainAnnotations; +(function (DomainAnnotations) { + DomainAnnotations.DefaultServerUrl = "https://www.ebi.ac.uk/pdbe/api/mappings"; + function getEntryUrl(pdbId, serverUrl) { + return `${serverUrl}/${pdbId.toLowerCase()}`; + } + DomainAnnotations.getEntryUrl = getEntryUrl; + function isApplicable(model) { + return !!model && Model.hasPdbId(model); + } + DomainAnnotations.isApplicable = isApplicable; + function fromJson(model, data) { + const info = PropertyWrapper.createInfo(); + const domainMap = createdomainMapFromJson(model, data); + return { info, data: domainMap }; + } + DomainAnnotations.fromJson = fromJson; + async function fromServer(ctx, model, props) { + const url = Asset.getUrlAsset(ctx.assetManager, getEntryUrl(model.entryId, props.serverUrl)); + const json = await ctx.assetManager + .resolve(url, "json") + .runInContext(ctx.runtime); + const data = json.data[model.entryId.toLowerCase()]; + if (!data) + throw new Error("missing data"); + return { value: fromJson(model, data), assets: [json] }; + } + DomainAnnotations.fromServer = fromServer; + const _emptyArray = []; + function getDomains(e) { + if (!Unit.isAtomic(e.unit)) + return _emptyArray; + const prop = DomainAnnotationsProvider.get(e.unit.model).value; + if (!prop || !prop.data) + return _emptyArray; + const rI = e.unit.residueIndex[e.element]; + return prop.data.domains.has(rI) + ? prop.data.domains.get(rI) + : _emptyArray; + } + DomainAnnotations.getDomains = getDomains; + function getDomainTypes(structure) { + if (!structure) + return _emptyArray; + const prop = DomainAnnotationsProvider.get(structure.models[0]).value; + if (!prop || !prop.data) + return _emptyArray; + return prop.data.domainTypes; + } + DomainAnnotations.getDomainTypes = getDomainTypes; + function getDomainNames(structure) { + if (!structure) + return _emptyArray; + const prop = DomainAnnotationsProvider.get(structure.models[0]).value; + if (!prop || !prop.data) + return _emptyArray; + return prop.data.domainNames; + } + DomainAnnotations.getDomainNames = getDomainNames; +})(DomainAnnotations || (DomainAnnotations = {})); +export const DomainAnnotationsParams = { + serverUrl: PD.Text(DomainAnnotations.DefaultServerUrl, { + description: "JSON API Server URL", + }), +}; +export const DomainAnnotationsProvider = CustomModelProperty.createProvider({ + label: "Domain annotations", + descriptor: CustomPropertyDescriptor({ + name: "domain_annotations", + }), + type: "static", + defaultParams: DomainAnnotationsParams, + getParams: (data) => DomainAnnotationsParams, + isApplicable: (data) => DomainAnnotations.isApplicable(data), + obtain: async (ctx, data, props) => { + const p = { ...PD.getDefaultValues(DomainAnnotationsParams), ...props }; + return await DomainAnnotations.fromServer(ctx, data, p); + }, +}); +function findChainLabel(map, label_entity_id, label_asym_id) { + const entityIndex = map.entities.getEntityIndex; + const eI = entityIndex(label_entity_id); + if (eI < 0 || !map.entity_index_label_asym_id.has(eI)) + return -1; + const cm = map.entity_index_label_asym_id.get(eI); + if (!cm) + return -1; + return cm.has(label_asym_id) ? cm.get(label_asym_id) : -1; +} +function findResidue(modelData, map, label_entity_id, label_asym_id, label_seq_id) { + const cI = findChainLabel(map, label_entity_id, label_asym_id); + if (cI < 0) + return -1; + const rm = map.chain_index_auth_seq_id.get(cI); + return rm.has(label_seq_id) ? rm.get(label_seq_id) : -1; +} +function createdomainMapFromJson(modelData, data) { + const domainTypes = []; + const domainNames = []; + const ret = new Map(); + const defaultDomains = ["Pfam", "InterPro", "CATH", "SCOP"]; + for (const db_name of Object.keys(data)) { + if (defaultDomains.indexOf(db_name) === -1) + continue; + const tempDomains = []; + domainTypes.push(db_name); + const db = data[db_name]; + for (const db_code of Object.keys(db)) { + const domain = db[db_code]; + for (const map of domain.mappings) { + arraySetAdd(tempDomains, domain.identifier); + const indexData = modelData.atomicHierarchy.index; + const indexMap = indexData.map; + for (let i = map.start.residue_number; i <= map.end.residue_number; i++) { + const seq_id = i; + const idx = findResidue(modelData, indexMap, map.entity_id + "", map.chain_id, seq_id); + let addVal = [domain.identifier]; + const prevVal = ret.get(idx); + if (prevVal) { + prevVal.push(domain.identifier); + addVal = prevVal; + } + ret.set(idx, addVal); + } + } + } + domainNames.push(tempDomains); + } + return { + domains: IndexedCustomProperty.fromResidueMap(ret), + domainNames, + domainTypes, + }; +} diff --git a/frontend/venome-molstar/lib/helpers.d.ts b/frontend/venome-molstar/lib/helpers.d.ts new file mode 100644 index 00000000..0fe7bd6d --- /dev/null +++ b/frontend/venome-molstar/lib/helpers.d.ts @@ -0,0 +1,106 @@ +import { Model, Structure } from "molstar/lib/mol-model/structure"; +import { BuiltInTrajectoryFormat } from "molstar/lib/mol-plugin-state/formats/trajectory"; +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import Expression from "molstar/lib/mol-script/language/expression"; +import { InitParams } from "./spec"; +export type SupportedFormats = "mmcif" | "bcif" | "cif" | "pdb" | "sdf"; +export type LoadParams = { + url: string; + format?: BuiltInTrajectoryFormat; + assemblyId?: string; + isHetView?: boolean; + isBinary?: boolean; + progressMessage?: string; +}; +export type MapParams = { + em?: MapStyle; + "2fo-fc"?: MapStyle; + "fo-fc(+ve)"?: MapStyle; + "fo-fc(-ve)"?: MapStyle; +}; +interface MapStyle { + opacity?: number; + wireframe?: boolean; +} +export declare namespace PDBeVolumes { + function mapParams(defaultParams: any, mapParams?: MapParams, ref?: string | number): any; + function displayUsibilityMessage(plugin: PluginContext): void; + function toggle(plugin: PluginContext): void; +} +export declare namespace AlphafoldView { + function getLociByPLDDT(score: number, contextData: Structure): import("molstar/lib/mol-model/structure/structure/element/loci").Loci; +} +export type LigandQueryParam = { + label_comp_id_list?: any; + auth_asym_id?: string; + struct_asym_id?: string; + label_comp_id?: string; + auth_seq_id?: number; + show_all?: boolean; +}; +export declare namespace LigandView { + function query(ligandViewParams: LigandQueryParam): { + core: Expression.Expression; + surroundings: Expression.Expression; + }; + function branchedQuery(params: any): { + core: Expression.Expression; + surroundings: Expression.Expression; + }; +} +export type QueryParam = { + auth_seq_id?: number; + entity_id?: string; + auth_asym_id?: string; + struct_asym_id?: string; + residue_number?: number; + start_residue_number?: number; + end_residue_number?: number; + auth_residue_number?: number; + auth_ins_code_id?: string; + start_auth_residue_number?: number; + start_auth_ins_code_id?: string; + end_auth_residue_number?: number; + end_auth_ins_code_id?: string; + atoms?: string[]; + label_comp_id?: string; + color?: any; + sideChain?: boolean; + representation?: string; + representationColor?: any; + focus?: boolean; + tooltip?: string; + start?: any; + end?: any; + atom_id?: number[]; + uniprot_accession?: string; + uniprot_residue_number?: number; + start_uniprot_residue_number?: number; + end_uniprot_residue_number?: number; +}; +export declare namespace QueryHelper { + function getQueryObject(params: QueryParam[], contextData: any): Expression.Expression; + function getInteractivityLoci(params: any, contextData: any): import("molstar/lib/mol-model/structure/structure/element/loci").Loci; + function getHetLoci(queryExp: Expression.Expression, contextData: any): import("molstar/lib/mol-model/structure/structure/element/loci").Loci; +} +export interface ModelInfo { + hetNames: string[]; + carbEntityCount: number; +} +export declare namespace ModelInfo { + function get(model: Model, structures: any): Promise; +} +/** Run `action` with showing a message in the bottom-left corner of the plugin UI */ +export declare function runWithProgressMessage(plugin: PluginContext, progressMessage: string | undefined, action: () => any): Promise; +/** Parameters for a request to ModelServer */ +export interface ModelServerRequest { + pdbId: string; + queryType: "full" | "residueSurroundings" | "atoms"; + queryParams?: Record; +} +/** Return URL for a ModelServer request. + * If `queryType` is 'full' and `lowPrecisionCoords` is false, return URL of the static file instead (updated mmCIF or bCIF). */ +export declare function getStructureUrl(initParams: InitParams, request: ModelServerRequest): string; +/** Create a copy of object `object`, fill in missing/undefined keys using `defaults` */ +export declare function addDefaults(object: Partial | undefined, defaults: T): T; +export {}; diff --git a/frontend/venome-molstar/lib/helpers.js b/frontend/venome-molstar/lib/helpers.js new file mode 100644 index 00000000..cccbc7d6 --- /dev/null +++ b/frontend/venome-molstar/lib/helpers.js @@ -0,0 +1,389 @@ +import { QualityAssessment } from "molstar/lib/extensions/model-archive/quality-assessment/prop"; +import { Queries, QueryContext, StructureProperties, StructureSelection, } from "molstar/lib/mol-model/structure"; +import { StructureQuery } from "molstar/lib/mol-model/structure/query/query"; +import { CreateVolumeStreamingInfo } from "molstar/lib/mol-plugin/behavior/dynamic/volume-streaming/transformers"; +import { PluginCommands } from "molstar/lib/mol-plugin/commands"; +import { MolScriptBuilder as MS } from "molstar/lib/mol-script/language/builder"; +import { compile } from "molstar/lib/mol-script/runtime/query/compiler"; +import { StateSelection } from "molstar/lib/mol-state"; +import { Task } from "molstar/lib/mol-task"; +import { SIFTSMapping } from "./sifts-mapping"; +export var PDBeVolumes; +(function (PDBeVolumes) { + function mapParams(defaultParams, mapParams, ref) { + const pdbeParams = { ...defaultParams }; + pdbeParams.options.behaviorRef = + "volume-streaming" + + "" + + Math.floor(Math.random() * Math.floor(100)); + pdbeParams.options.emContourProvider = "pdbe"; + pdbeParams.options.serverUrl = + "https://www.ebi.ac.uk/pdbe/volume-server"; + const MAIN_MAP_DEFAULTS = { opacity: 0.49, wireframe: false }; + const DIFF_MAP_DEFAULTS = { opacity: 0.3, wireframe: true }; + pdbeParams.options.channelParams["em"] = addDefaults(mapParams?.["em"], MAIN_MAP_DEFAULTS); + pdbeParams.options.channelParams["2fo-fc"] = addDefaults(mapParams?.["2fo-fc"], MAIN_MAP_DEFAULTS); + pdbeParams.options.channelParams["fo-fc(+ve)"] = addDefaults(mapParams?.["fo-fc(+ve)"], DIFF_MAP_DEFAULTS); + pdbeParams.options.channelParams["fo-fc(-ve)"] = addDefaults(mapParams?.["fo-fc(-ve)"], DIFF_MAP_DEFAULTS); + return pdbeParams; + } + PDBeVolumes.mapParams = mapParams; + function displayUsibilityMessage(plugin) { + PluginCommands.Toast.Show(plugin, { + title: "Volume", + message: "Streaming enabled, click on a residue or an atom to view the data.", + key: "toast-1", + timeoutMs: 7000, + }); + } + PDBeVolumes.displayUsibilityMessage = displayUsibilityMessage; + function toggle(plugin) { + const state = plugin.state.data; + const streamingState = state.select(StateSelection.Generators.ofTransformer(CreateVolumeStreamingInfo))[0]; + if (streamingState) { + PluginCommands.State.ToggleVisibility(plugin, { + state: state, + ref: streamingState.transform.ref, + }); + return; + } + } + PDBeVolumes.toggle = toggle; +})(PDBeVolumes || (PDBeVolumes = {})); +export var AlphafoldView; +(function (AlphafoldView) { + function getLociByPLDDT(score, contextData) { + const queryExp = MS.struct.modifier.union([ + MS.struct.modifier.wholeResidues([ + MS.struct.modifier.union([ + MS.struct.generator.atomGroups({ + "chain-test": MS.core.rel.eq([ + MS.ammp("objectPrimitive"), + "atomistic", + ]), + "residue-test": MS.core.rel.gr([ + QualityAssessment.symbols.pLDDT.symbol(), + score, + ]), + }), + ]), + ]), + ]); + const query = compile(queryExp); + const sel = query(new QueryContext(contextData)); + return StructureSelection.toLociWithSourceUnits(sel); + } + AlphafoldView.getLociByPLDDT = getLociByPLDDT; +})(AlphafoldView || (AlphafoldView = {})); +export var LigandView; +(function (LigandView) { + function query(ligandViewParams) { + const atomGroupsParams = { + "group-by": MS.core.str.concat([ + MS.struct.atomProperty.core.operatorName(), + MS.struct.atomProperty.macromolecular.residueKey(), + ]), + }; + // Residue Param + let residueParam; + if (ligandViewParams.auth_seq_id !== undefined) { + residueParam = MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_seq_id(), + ligandViewParams.auth_seq_id, + ]); + } + else if (ligandViewParams.label_comp_id) { + residueParam = MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.label_comp_id(), + ligandViewParams.label_comp_id, + ]); + } + if (residueParam) + atomGroupsParams["residue-test"] = residueParam; + // Chain Param + if (ligandViewParams.auth_asym_id) { + atomGroupsParams["chain-test"] = MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_asym_id(), + ligandViewParams.auth_asym_id, + ]); + } + else if (ligandViewParams.struct_asym_id) { + atomGroupsParams["chain-test"] = MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.label_asym_id(), + ligandViewParams.struct_asym_id, + ]); + } + // Construct core query + const core = ligandViewParams.show_all + ? MS.struct.generator.atomGroups(atomGroupsParams) + : MS.struct.filter.first([ + MS.struct.generator.atomGroups(atomGroupsParams), + ]); + // Construct surroundings query + const surroundings = MS.struct.modifier.includeSurroundings({ + 0: core, + radius: 5, + "as-whole-residues": true, + }); + return { + core, + surroundings, + }; + } + LigandView.query = query; + function branchedQuery(params) { + const entityObjArray = []; + params.atom_site.forEach((param) => { + const qEntities = { + "group-by": MS.core.str.concat([ + MS.struct.atomProperty.core.operatorName(), + MS.struct.atomProperty.macromolecular.residueKey(), + ]), + "residue-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_seq_id(), + param.auth_seq_id, + ]), + }; + entityObjArray.push(qEntities); + }); + const atmGroupsQueries = []; + entityObjArray.forEach((entityObj) => { + atmGroupsQueries.push(MS.struct.generator.atomGroups(entityObj)); + }); + const core = MS.struct.modifier.union([ + atmGroupsQueries.length === 1 + ? atmGroupsQueries[0] + : // Need to union before merge for fast performance + MS.struct.combinator.merge(atmGroupsQueries.map((q) => MS.struct.modifier.union([q]))), + ]); + // Construct surroundings query + const surroundings = MS.struct.modifier.includeSurroundings({ + 0: core, + radius: 5, + "as-whole-residues": true, + }); + return { + core, + surroundings, + }; + } + LigandView.branchedQuery = branchedQuery; +})(LigandView || (LigandView = {})); +export var QueryHelper; +(function (QueryHelper) { + function getQueryObject(params, contextData) { + const selections = []; + let siftMappings; + let currentAccession; + params.forEach((param) => { + const selection = {}; + // entity + if (param.entity_id) + selection["entityTest"] = (l) => StructureProperties.entity.id(l.element) === + param.entity_id; + // chain + if (param.struct_asym_id) { + selection["chainTest"] = (l) => StructureProperties.chain.label_asym_id(l.element) === + param.struct_asym_id; + } + else if (param.auth_asym_id) { + selection["chainTest"] = (l) => StructureProperties.chain.auth_asym_id(l.element) === + param.auth_asym_id; + } + // residues + if (param.label_comp_id) { + selection["residueTest"] = (l) => StructureProperties.atom.label_comp_id(l.element) === + param.label_comp_id; + } + else if (param.uniprot_accession && + param.uniprot_residue_number !== undefined) { + selection["residueTest"] = (l) => { + if (!siftMappings || + currentAccession !== param.uniprot_accession) { + siftMappings = SIFTSMapping.Provider.get(contextData.models[0]).value; + currentAccession = param.uniprot_accession; + } + const rI = StructureProperties.residue.key(l.element); + return (!!siftMappings && + param.uniprot_accession === + siftMappings.accession[rI] && + param.uniprot_residue_number === +siftMappings.num[rI]); + }; + } + else if (param.uniprot_accession && + param.start_uniprot_residue_number !== undefined && + param.end_uniprot_residue_number !== undefined) { + selection["residueTest"] = (l) => { + if (!siftMappings || + currentAccession !== param.uniprot_accession) { + siftMappings = SIFTSMapping.Provider.get(contextData.models[0]).value; + currentAccession = param.uniprot_accession; + } + const rI = StructureProperties.residue.key(l.element); + return (!!siftMappings && + param.uniprot_accession === + siftMappings.accession[rI] && + param.start_uniprot_residue_number <= + +siftMappings.num[rI] && + param.end_uniprot_residue_number >= + +siftMappings.num[rI]); + }; + } + else if (param.residue_number !== undefined) { + selection["residueTest"] = (l) => StructureProperties.residue.label_seq_id(l.element) === + param.residue_number; + } + else if (param.start_residue_number !== undefined && + param.end_residue_number !== undefined && + param.end_residue_number > param.start_residue_number) { + selection["residueTest"] = (l) => { + const labelSeqId = StructureProperties.residue.label_seq_id(l.element); + return (labelSeqId >= param.start_residue_number && + labelSeqId <= param.end_residue_number); + }; + } + else if (param.start_residue_number !== undefined && + param.end_residue_number !== undefined && + param.end_residue_number === param.start_residue_number) { + selection["residueTest"] = (l) => StructureProperties.residue.label_seq_id(l.element) === + param.start_residue_number; + } + else if (param.auth_seq_id !== undefined) { + selection["residueTest"] = (l) => StructureProperties.residue.auth_seq_id(l.element) === + param.auth_seq_id; + } + else if (param.auth_residue_number !== undefined && + !param.auth_ins_code_id) { + selection["residueTest"] = (l) => StructureProperties.residue.auth_seq_id(l.element) === + param.auth_residue_number; + } + else if (param.auth_residue_number !== undefined && + param.auth_ins_code_id) { + selection["residueTest"] = (l) => StructureProperties.residue.auth_seq_id(l.element) === + param.auth_residue_number; + } + else if (param.start_auth_residue_number !== undefined && + param.end_auth_residue_number !== undefined && + param.end_auth_residue_number > param.start_auth_residue_number) { + selection["residueTest"] = (l) => { + const authSeqId = StructureProperties.residue.auth_seq_id(l.element); + return (authSeqId >= param.start_auth_residue_number && + authSeqId <= param.end_auth_residue_number); + }; + } + else if (param.start_auth_residue_number !== undefined && + param.end_auth_residue_number !== undefined && + param.end_auth_residue_number === + param.start_auth_residue_number) { + selection["residueTest"] = (l) => StructureProperties.residue.auth_seq_id(l.element) === + param.start_auth_residue_number; + } + // atoms + if (param.atoms) { + selection["atomTest"] = (l) => param.atoms.includes(StructureProperties.atom.label_atom_id(l.element)); + } + if (param.atom_id) { + selection["atomTest"] = (l) => param.atom_id.includes(StructureProperties.atom.id(l.element)); + } + selections.push(selection); + }); + const atmGroupsQueries = []; + selections.forEach((selection) => { + atmGroupsQueries.push(Queries.generators.atoms(selection)); + }); + return Queries.combinators.merge(atmGroupsQueries); + } + QueryHelper.getQueryObject = getQueryObject; + function getInteractivityLoci(params, contextData) { + const sel = StructureQuery.run(QueryHelper.getQueryObject(params, contextData), contextData); + return StructureSelection.toLociWithSourceUnits(sel); + } + QueryHelper.getInteractivityLoci = getInteractivityLoci; + function getHetLoci(queryExp, contextData) { + const query = compile(queryExp); + const sel = query(new QueryContext(contextData)); + return StructureSelection.toLociWithSourceUnits(sel); + } + QueryHelper.getHetLoci = getHetLoci; +})(QueryHelper || (QueryHelper = {})); +export var ModelInfo; +(function (ModelInfo) { + async function get(model, structures) { + const { _rowCount: residueCount } = model.atomicHierarchy.residues; + const { offsets: residueOffsets } = model.atomicHierarchy.residueAtomSegments; + const chainIndex = model.atomicHierarchy.chainAtomSegments.index; + const hetNames = []; + let carbEntityCount = 0; + for (let rI = 0; rI < residueCount; rI++) { + const cI = chainIndex[residueOffsets[rI]]; + const eI = model.atomicHierarchy.index.getEntityFromChain(cI); + const entityType = model.entities.data.type.value(eI); + if (entityType !== "non-polymer" && entityType !== "branched") + continue; + // const comp_id = model.atomicHierarchy.atoms.label_comp_id.value(rI); + const comp_id = model.atomicHierarchy.atoms.label_comp_id.value(residueOffsets[rI]); + if (entityType === "branched") { + carbEntityCount++; + } + else { + if (hetNames.indexOf(comp_id) === -1) + hetNames.push(comp_id); + } + } + return { + hetNames, + carbEntityCount, + }; + } + ModelInfo.get = get; +})(ModelInfo || (ModelInfo = {})); +/** Run `action` with showing a message in the bottom-left corner of the plugin UI */ +export async function runWithProgressMessage(plugin, progressMessage, action) { + const task = Task.create(progressMessage ?? "Task", async (ctx) => { + let done = false; + try { + if (progressMessage) { + setTimeout(() => { + if (!done) + ctx.update(progressMessage); + }, 1000); // Delay the first update to force showing message in UI + } + await action(); + } + finally { + done = true; + } + }); + await plugin.runTask(task); +} +/** Return URL for a ModelServer request. + * If `queryType` is 'full' and `lowPrecisionCoords` is false, return URL of the static file instead (updated mmCIF or bCIF). */ +export function getStructureUrl(initParams, request) { + const pdbeUrl = initParams.pdbeUrl.replace(/\/$/, ""); // without trailing slash + const useStaticFile = request.queryType === "full" && !initParams.lowPrecisionCoords; + if (useStaticFile) { + const suffix = initParams.encoding === "bcif" ? ".bcif" : "_updated.cif"; + return `${pdbeUrl}/entry-files/download/${request.pdbId}${suffix}`; + } + else { + const queryParams = { + ...request.queryParams, + encoding: initParams.encoding, + lowPrecisionCoords: initParams.lowPrecisionCoords ? 1 : undefined, + }; + const queryString = Object.entries(queryParams) + .filter(([key, value]) => value !== undefined) + .map(([key, value]) => `${key}=${value}`) + .join("&"); + const url = `${pdbeUrl}/model-server/v1/${request.pdbId}/${request.queryType}`; + return queryString !== "" ? `${url}?${queryString}` : url; + } +} +/** Create a copy of object `object`, fill in missing/undefined keys using `defaults` */ +export function addDefaults(object, defaults) { + const result = { ...object }; + for (const key in defaults) { + result[key] ??= defaults[key]; + } + return result; +} diff --git a/frontend/venome-molstar/lib/index.d.ts b/frontend/venome-molstar/lib/index.d.ts new file mode 100644 index 00000000..1c697733 --- /dev/null +++ b/frontend/venome-molstar/lib/index.d.ts @@ -0,0 +1,98 @@ +import { Canvas3DProps } from "molstar/lib/mol-canvas3d/canvas3d"; +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import { Color } from "molstar/lib/mol-util/color/color"; +import { LoadParams, QueryParam } from "./helpers"; +import { ColorParams, InitParams } from "./spec"; +import "molstar/lib/mol-plugin-ui/skin/dark.scss"; +import "./overlay.scss"; +export declare class PDBeMolstarPlugin { + private _ev; + readonly events: { + loadComplete: import("rxjs").Subject; + }; + plugin: PluginContext; + initParams: InitParams; + targetElement: HTMLElement; + assemblyRef: string; + selectedParams: any; + defaultRendererProps: Canvas3DProps["renderer"]; + defaultMarkingProps: Canvas3DProps["marking"]; + isHighlightColorUpdated: boolean; + isSelectedColorUpdated: boolean; + /** Extract InitParams from attributes of an HTML element */ + static initParamsFromHtmlAttributes(element: HTMLElement): Partial; + render(target: string | HTMLElement, options: Partial): Promise; + getMoleculeSrcUrl(): { + url: string; + format: string; + isBinary: boolean; + }; + screenshotData(): Promise | undefined; + get state(): import("molstar/lib/mol-state/state").State; + createLigandStructure(isBranched: boolean): Promise; + load({ url, format, isBinary, assemblyId, progressMessage, }: LoadParams, fullLoad?: boolean): Promise; + applyVisualParams: () => void; + canvas: { + toggleControls: (isVisible?: boolean) => void; + toggleExpanded: (isExpanded?: boolean) => void; + setBgColor: (color?: { + r: number; + g: number; + b: number; + }) => Promise; + applySettings: (settings?: { + color?: { + r: number; + g: number; + b: number; + }; + lighting?: string; + }) => Promise; + }; + getLociForParams(params: QueryParam[], structureNumber?: number): import("molstar/lib/mol-model/structure/structure/element/loci").Loci | { + kind: "empty-loci"; + }; + getLociByPLDDT(score: number, structureNumber?: number): import("molstar/lib/mol-model/structure/structure/element/loci").Loci | { + kind: "empty-loci"; + }; + normalizeColor(colorVal: any, defaultColor?: Color): Color; + visual: { + highlight: (params: { + data: QueryParam[]; + color?: any; + focus?: boolean; + structureNumber?: number; + }) => void; + clearHighlight: () => Promise; + select: (params: { + data: QueryParam[]; + nonSelectedColor?: any; + addedRepr?: boolean; + structureNumber?: number; + }) => Promise; + clearSelection: (structureNumber?: number) => Promise; + update: (options: Partial, fullLoad?: boolean) => Promise; + visibility: (data: { + [key: string]: any; + polymer?: boolean | undefined; + het?: boolean | undefined; + water?: boolean | undefined; + carbs?: boolean | undefined; + nonStandard?: boolean | undefined; + maps?: boolean | undefined; + }) => Promise; + toggleSpin: (isSpinning?: boolean, resetCamera?: boolean) => Promise; + focus: (params: QueryParam[], structureNumber?: number) => Promise; + setColor: (param: { + highlight?: ColorParams; + select?: ColorParams; + }) => Promise; + reset: (params: { + camera?: boolean; + theme?: boolean; + highlightColor?: boolean; + selectColor?: boolean; + }) => Promise; + }; + clear(): Promise; +} diff --git a/frontend/venome-molstar/lib/index.js b/frontend/venome-molstar/lib/index.js new file mode 100644 index 00000000..051e2e80 --- /dev/null +++ b/frontend/venome-molstar/lib/index.js @@ -0,0 +1,928 @@ +import { GeometryExport } from "molstar/lib/extensions/geo-export"; +import { MAQualityAssessment } from "molstar/lib/extensions/model-archive/quality-assessment/behavior"; +import { Mp4Export } from "molstar/lib/extensions/mp4-export"; +import { PDBeStructureQualityReport } from "molstar/lib/extensions/pdbe"; +import { RCSBAssemblySymmetry, RCSBAssemblySymmetryConfig, } from "molstar/lib/extensions/rcsb/assembly-symmetry/behavior"; +import { EmptyLoci, Loci } from "molstar/lib/mol-model/loci"; +import { AnimateAssemblyUnwind } from "molstar/lib/mol-plugin-state/animation/built-in/assembly-unwind"; +import { AnimateCameraRock } from "molstar/lib/mol-plugin-state/animation/built-in/camera-rock"; +import { AnimateCameraSpin } from "molstar/lib/mol-plugin-state/animation/built-in/camera-spin"; +import { AnimateModelIndex } from "molstar/lib/mol-plugin-state/animation/built-in/model-index"; +import { AnimateStructureSpin } from "molstar/lib/mol-plugin-state/animation/built-in/spin-structure"; +import { AnimateStateInterpolation } from "molstar/lib/mol-plugin-state/animation/built-in/state-interpolation"; +import { AnimateStateSnapshots } from "molstar/lib/mol-plugin-state/animation/built-in/state-snapshots"; +import { clearStructureOverpaint } from "molstar/lib/mol-plugin-state/helpers/structure-overpaint"; +import { createStructureRepresentationParams } from "molstar/lib/mol-plugin-state/helpers/structure-representation-params"; +import { StructureComponentManager } from "molstar/lib/mol-plugin-state/manager/structure/component"; +import { createPluginUI } from "molstar/lib/mol-plugin-ui/react18"; +import { FocusLoci } from "molstar/lib/mol-plugin/behavior/dynamic/camera"; +import { SelectLoci } from "molstar/lib/mol-plugin/behavior/dynamic/representation"; +import { StructureFocusRepresentation } from "molstar/lib/mol-plugin/behavior/dynamic/selection/structure-focus-representation"; +import { InitVolumeStreaming } from "molstar/lib/mol-plugin/behavior/dynamic/volume-streaming/transformers"; +import { PluginCommands } from "molstar/lib/mol-plugin/commands"; +import { PluginConfig } from "molstar/lib/mol-plugin/config"; +import { PluginLayoutStateParams } from "molstar/lib/mol-plugin/layout"; +import { PluginSpec } from "molstar/lib/mol-plugin/spec"; +import { StateSelection, StateTransform } from "molstar/lib/mol-state"; +import { ElementSymbolColorThemeParams } from "molstar/lib/mol-theme/color/element-symbol"; +import { Asset } from "molstar/lib/mol-util/assets"; +import { Color } from "molstar/lib/mol-util/color/color"; +import { ParamDefinition } from "molstar/lib/mol-util/param-definition"; +import { RxEventHelper } from "molstar/lib/mol-util/rx-event-helper"; +import { CustomEvents } from "./custom-events"; +import { PDBeDomainAnnotations } from "./domain-annotations/behavior"; +import { AlphafoldView, LigandView, PDBeVolumes, QueryHelper, addDefaults, getStructureUrl, runWithProgressMessage, } from "./helpers"; +import { LoadingOverlay } from "./overlay"; +import { PluginCustomState } from "./plugin-custom-state"; +import { DefaultParams, DefaultPluginUISpec, validateInitParams, } from "./spec"; +import { initParamsFromHtmlAttributes } from "./spec-from-html"; +import { subscribeToComponentEvents } from "./subscribe-events"; +import { initSuperposition } from "./superposition"; +import { SuperpositionFocusRepresentation } from "./superposition-focus-representation"; +import { LeftPanelControls } from "./ui/pdbe-left-panel"; +import { PDBeLigandViewStructureTools, PDBeStructureTools, PDBeSuperpositionStructureTools, } from "./ui/pdbe-structure-controls"; +import { PDBeViewportControls } from "./ui/pdbe-viewport-controls"; +import { SuperpostionViewport } from "./ui/superposition-viewport"; +import "molstar/lib/mol-plugin-ui/skin/dark.scss"; +import "./overlay.scss"; +export class PDBeMolstarPlugin { + _ev = RxEventHelper.create(); + events = { + loadComplete: this._ev(), + }; + plugin; + initParams; + targetElement; + assemblyRef = ""; + selectedParams; + defaultRendererProps; + defaultMarkingProps; + isHighlightColorUpdated = false; + isSelectedColorUpdated = false; + /** Extract InitParams from attributes of an HTML element */ + static initParamsFromHtmlAttributes(element) { + return initParamsFromHtmlAttributes(element); + } + async render(target, options) { + console.debug("Rendering PDBeMolstarPlugin instance with options:", options); + // Validate options + if (!options) { + console.error("Missing `options` argument to `PDBeMolstarPlugin.render"); + return; + } + const validationIssues = validateInitParams(options); + if (validationIssues) { + console.error("Invalid PDBeMolstarPlugin options:", options); + return; + } + this.initParams = addDefaults(options, DefaultParams); + // Set PDBe Plugin Spec + const pdbePluginSpec = DefaultPluginUISpec(); + pdbePluginSpec.config ??= []; + if (!this.initParams.ligandView && + !this.initParams.superposition && + this.initParams.selectInteraction) { + pdbePluginSpec.behaviors.push(PluginSpec.Behavior(StructureFocusRepresentation)); + } + if (this.initParams.superposition) { + pdbePluginSpec.behaviors.push(PluginSpec.Behavior(SuperpositionFocusRepresentation), PluginSpec.Behavior(MAQualityAssessment, { + autoAttach: true, + showTooltip: true, + })); + } + // Add custom properties + if (this.initParams.domainAnnotation) { + pdbePluginSpec.behaviors.push(PluginSpec.Behavior(PDBeDomainAnnotations, { + autoAttach: true, + showTooltip: false, + })); + } + if (this.initParams.validationAnnotation) { + pdbePluginSpec.behaviors.push(PluginSpec.Behavior(PDBeStructureQualityReport, { + autoAttach: true, + showTooltip: false, + })); + } + if (this.initParams.symmetryAnnotation) { + pdbePluginSpec.behaviors.push(PluginSpec.Behavior(RCSBAssemblySymmetry)); + pdbePluginSpec.config.push([RCSBAssemblySymmetryConfig.DefaultServerType, "pdbe"], [ + RCSBAssemblySymmetryConfig.DefaultServerUrl, + "https://www.ebi.ac.uk/pdbe/aggregated-api/pdb/symmetry", + ], [RCSBAssemblySymmetryConfig.ApplyColors, false]); + } + pdbePluginSpec.layout = { + initial: { + isExpanded: this.initParams.expanded, + showControls: !this.initParams.hideControls, + regionState: { + left: "full", + right: "full", + top: this.initParams.sequencePanel ? "full" : "hidden", + bottom: "full", + }, + controlsDisplay: this.initParams.reactive + ? "reactive" + : this.initParams.landscape + ? "landscape" + : PluginLayoutStateParams.controlsDisplay.defaultValue, + }, + }; + pdbePluginSpec.components = { + controls: { + left: LeftPanelControls, + // right: DefaultStructureTools, + // top: 'none', + bottom: "none", + }, + viewport: { + controls: PDBeViewportControls, + view: this.initParams.superposition + ? SuperpostionViewport + : void 0, + }, + remoteState: "none", + structureTools: this.initParams.superposition + ? PDBeSuperpositionStructureTools + : this.initParams.ligandView + ? PDBeLigandViewStructureTools + : PDBeStructureTools, + }; + if (this.initParams.alphafoldView) { + pdbePluginSpec.behaviors.push(PluginSpec.Behavior(MAQualityAssessment, { + autoAttach: true, + showTooltip: true, + })); + } + pdbePluginSpec.config.push([ + PluginConfig.Structure.DefaultRepresentationPresetParams, + { + theme: { + globalName: this.initParams.alphafoldView + ? "plddt-confidence" + : undefined, + carbonColor: { name: "element-symbol", params: {} }, + focus: { + name: "element-symbol", + params: { + carbonColor: { name: "element-symbol", params: {} }, + }, + }, + }, + }, + ]); + ElementSymbolColorThemeParams.carbonColor.defaultValue = { + name: "element-symbol", + params: {}, + }; + // Add animation props + if (!this.initParams.ligandView && !this.initParams.superposition) { + pdbePluginSpec.animations = [ + AnimateModelIndex, + AnimateCameraSpin, + AnimateCameraRock, + AnimateStateSnapshots, + AnimateAssemblyUnwind, + AnimateStructureSpin, + AnimateStateInterpolation, + ]; + pdbePluginSpec.behaviors.push(PluginSpec.Behavior(Mp4Export)); + pdbePluginSpec.behaviors.push(PluginSpec.Behavior(GeometryExport)); + } + if (this.initParams.hideCanvasControls.includes("expand")) + pdbePluginSpec.config.push([ + PluginConfig.Viewport.ShowExpand, + false, + ]); + if (this.initParams.hideCanvasControls.includes("selection")) + pdbePluginSpec.config.push([ + PluginConfig.Viewport.ShowSelectionMode, + false, + ]); + if (this.initParams.hideCanvasControls.includes("animation")) + pdbePluginSpec.config.push([ + PluginConfig.Viewport.ShowAnimation, + false, + ]); + if (this.initParams.hideCanvasControls.includes("controlToggle")) + pdbePluginSpec.config.push([ + PluginConfig.Viewport.ShowControls, + false, + ]); + if (this.initParams.hideCanvasControls.includes("controlInfo")) + pdbePluginSpec.config.push([ + PluginConfig.Viewport.ShowSettings, + false, + ]); + // override default event bindings + if (this.initParams.selectBindings) { + pdbePluginSpec.behaviors.push(PluginSpec.Behavior(SelectLoci, { + bindings: this.initParams.selectBindings, + })); + } + if (this.initParams.focusBindings) { + pdbePluginSpec.behaviors.push(PluginSpec.Behavior(FocusLoci, { + bindings: this.initParams.focusBindings, + })); + } + this.targetElement = + typeof target === "string" + ? document.getElementById(target) + : target; + this.targetElement.viewerInstance = this; + // Create/ Initialise Plugin + this.plugin = await createPluginUI(this.targetElement, pdbePluginSpec); + PluginCustomState(this.plugin).initParams = { ...this.initParams }; + PluginCustomState(this.plugin).events = { + segmentUpdate: this._ev(), + superpositionInit: this._ev(), + isBusy: this._ev(), + }; + // Set background colour + if (this.initParams.bgColor || this.initParams.lighting) { + this.canvas.applySettings({ + color: this.initParams.bgColor, + lighting: this.initParams.lighting, + }); + } + // Set selection granularity + if (this.initParams.granularity) { + this.plugin.managers.interactivity.setProps({ + granularity: this.initParams.granularity, + }); + } + // Set default highlight and selection colors + if (this.initParams.highlightColor || this.initParams.selectColor) { + this.visual.setColor({ + highlight: this.initParams.highlightColor, + select: this.initParams.selectColor, + }); + } + // Save renderer defaults + this.defaultRendererProps = { ...this.plugin.canvas3d.props.renderer }; + this.defaultMarkingProps = { ...this.plugin.canvas3d.props.marking }; + if (this.initParams.superposition) { + // Set left panel tab + this.plugin.behaviors.layout.leftPanelTabName.next("segments"); + // Initialise superposition + if (this.initParams.loadingOverlay) { + new LoadingOverlay(this.targetElement, { + resize: this.plugin?.canvas3d?.resized, + hide: this.events.loadComplete, + }).show(); + } + initSuperposition(this.plugin, this.events.loadComplete); + } + else { + // Collapse left panel and set left panel tab to none + PluginCommands.Layout.Update(this.plugin, { + state: { + regionState: { + ...this.plugin.layout.state.regionState, + left: "collapsed", + }, + }, + }); + this.plugin.behaviors.layout.leftPanelTabName.next("none"); + // Load Molecule CIF or coordQuery and Parse + const dataSource = this.getMoleculeSrcUrl(); + if (dataSource) { + if (this.initParams.loadingOverlay) { + new LoadingOverlay(this.targetElement, { + resize: this.plugin?.canvas3d?.resized, + hide: this.events.loadComplete, + }).show(); + } + this.load({ + url: dataSource.url, + format: dataSource.format, + assemblyId: this.initParams.assemblyId, + isBinary: dataSource.isBinary, + progressMessage: `Loading ${this.initParams.moleculeId ?? ""} ...`, + }); + } + // Binding to other PDB Component events + if (this.initParams.subscribeEvents) { + subscribeToComponentEvents(this); + } + // Event handling + CustomEvents.add(this.plugin, this.targetElement); + } + } + getMoleculeSrcUrl() { + if (this.initParams.customData) { + let { url, format, binary } = this.initParams.customData; + if (!url || !format) { + throw new Error(`Provide all custom data parameters`); + } + if (format === "cif" || format === "bcif") + format = "mmcif"; + // Validate supported format + const supportedFormats = ["mmcif", "pdb", "sdf"]; + if (!supportedFormats.includes(format)) { + throw new Error(`${format} not supported.`); + } + return { + url: url, + format: format, + isBinary: binary, + }; + } + if (this.initParams.moleculeId) { + const request = { + pdbId: this.initParams.moleculeId, + queryType: "full", + queryParams: {}, + }; + if (this.initParams.ligandView) { + request.queryType = "residueSurroundings"; + request.queryParams["data_source"] = "pdb-h"; + if (!this.initParams.ligandView.label_comp_id_list) { + request.queryParams["label_comp_id"] = + this.initParams.ligandView.label_comp_id; + request.queryParams["auth_seq_id"] = + this.initParams.ligandView.auth_seq_id; + request.queryParams["auth_asym_id"] = + this.initParams.ligandView.auth_asym_id; + } + } + return { + url: getStructureUrl(this.initParams, request), + format: "mmcif", + isBinary: this.initParams.encoding === "bcif", + }; + } + throw new Error(`Mandatory parameters missing! (customData or moleculeId must be defined)`); + } + screenshotData() { + return this.plugin.helpers.viewportScreenshot?.getImageDataUri(); + } + get state() { + return this.plugin.state.data; + } + async createLigandStructure(isBranched) { + if (this.assemblyRef === "") + return; + for await (const comp of this.plugin.managers.structure.hierarchy + .currentComponentGroups) { + await PluginCommands.State.RemoveObject(this.plugin, { + state: comp[0].cell.parent, + ref: comp[0].cell.transform.ref, + removeParentGhosts: true, + }); + } + const structure = this.state.select(this.assemblyRef)[0]; + let ligandQuery; + if (isBranched) { + ligandQuery = LigandView.branchedQuery(this.initParams.ligandView?.label_comp_id_list); + } + else { + ligandQuery = LigandView.query(this.initParams.ligandView); + } + const ligandVis = await this.plugin.builders.structure.tryCreateComponentFromExpression(structure, ligandQuery.core, "pivot", { label: "Ligand" }); + if (ligandVis) + await this.plugin.builders.structure.representation.addRepresentation(ligandVis, { + type: "ball-and-stick", + color: "element-symbol", + colorParams: { + carbonColor: { name: "element-symbol", params: {} }, + }, + size: "uniform", + sizeParams: { value: 2.5 }, + }, { tag: "ligand-vis" }); + const ligandSurr = await this.plugin.builders.structure.tryCreateComponentFromExpression(structure, ligandQuery.surroundings, "rest", { label: "Surroundings" }); + if (ligandSurr) + await this.plugin.builders.structure.representation.addRepresentation(ligandSurr, { + type: "ball-and-stick", + color: "element-symbol", + colorParams: { + carbonColor: { name: "element-symbol", params: {} }, + }, + size: "uniform", + sizeParams: { value: 0.8 }, + }); + // Focus ligand + const ligRef = StateSelection.findTagInSubtree(this.plugin.state.data.tree, StateTransform.RootRef, "ligand-vis"); + if (!ligRef) + return; + const cell = this.plugin.state.data.cells.get(ligRef); + if (cell?.obj) { + const repr = cell.obj.data.repr; + const ligLoci = repr.getAllLoci()[0]; // getAllLoci returns multiple copies of the same loci (one per representation visual) + this.plugin.managers.structure.focus.setFromLoci(ligLoci); + // focus-add is not handled in camera behavior, doing it here + const current = this.plugin.managers.structure.focus.current?.loci; + if (current) + this.plugin.managers.camera.focusLoci(current); + } + } + async load({ url, format = "mmcif", isBinary = false, assemblyId = "", progressMessage, }, fullLoad = true) { + await runWithProgressMessage(this.plugin, progressMessage, async () => { + let success = false; + try { + if (fullLoad) + await this.clear(); + const isHetView = this.initParams.ligandView ? true : false; + let downloadOptions = void 0; + let isBranchedView = false; + if (this.initParams.ligandView && + this.initParams.ligandView.label_comp_id_list) { + isBranchedView = true; + downloadOptions = { + body: JSON.stringify(this.initParams.ligandView.label_comp_id_list), + headers: [["Content-type", "application/json"]], + }; + } + const data = await this.plugin.builders.data.download({ url: Asset.Url(url, downloadOptions), isBinary }, { state: { isGhost: true } }); + const trajectory = await this.plugin.builders.structure.parseTrajectory(data, format); + if (!isHetView) { + await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, this.initParams.defaultPreset, { + structure: assemblyId + ? assemblyId === "preferred" + ? void 0 + : { + name: "assembly", + params: { id: assemblyId }, + } + : { name: "model", params: {} }, + showUnitcell: false, + representationPreset: "auto", + }); + if (this.initParams.hideStructure.length > 0 || + this.initParams.visualStyle) { + this.applyVisualParams(); + } + } + else { + const model = await this.plugin.builders.structure.createModel(trajectory); + await this.plugin.builders.structure.createStructure(model, { name: "model", params: {} }); + } + // show selection if param is set + if (this.initParams.selection) { + this.visual.select(this.initParams.selection); + } + // Store assembly ref + const pivotIndex = this.plugin.managers.structure.hierarchy.selection + .structures.length - 1; + const pivot = this.plugin.managers.structure.hierarchy.selection + .structures[pivotIndex]; + if (pivot && pivot.cell.parent) + this.assemblyRef = pivot.cell.transform.ref; + // Load Volume + if (this.initParams.loadMaps) { + if (this.assemblyRef === "") + return; + const asm = this.state.select(this.assemblyRef)[0].obj; + const defaultMapParams = InitVolumeStreaming.createDefaultParams(asm, this.plugin); + const pdbeMapParams = PDBeVolumes.mapParams(defaultMapParams, this.initParams.mapSettings, ""); + if (pdbeMapParams) { + await this.plugin.runTask(this.state.applyAction(InitVolumeStreaming, pdbeMapParams, this.assemblyRef)); + if (pdbeMapParams.method !== "em" && + !this.initParams.ligandView) + PDBeVolumes.displayUsibilityMessage(this.plugin); + } + } + // Create Ligand Representation + if (isHetView) { + await this.createLigandStructure(isBranchedView); + } + success = true; + } + finally { + this.events.loadComplete.next(success); + } + }); + } + applyVisualParams = () => { + const componentGroups = this.plugin.managers.structure.hierarchy.currentComponentGroups; + for (const compGroup of componentGroups) { + const compRef = compGroup[compGroup.length - 1]; + const tag = compRef.key ?? ""; + const remove = this.initParams.hideStructure.some((type) => StructureComponentTags[type]?.includes(tag)); + if (remove) { + this.plugin.managers.structure.hierarchy.remove([compRef]); + } + if (!remove && this.initParams.visualStyle) { + if (compRef && compRef.representations) { + compRef.representations.forEach((rep) => { + const currentParams = createStructureRepresentationParams(this.plugin, void 0, { type: this.initParams.visualStyle }); + this.plugin.managers.structure.component.updateRepresentations([compRef], rep, currentParams); + }); + } + } + } + }; + canvas = { + toggleControls: (isVisible) => { + if (typeof isVisible === "undefined") + isVisible = !this.plugin.layout.state.showControls; + PluginCommands.Layout.Update(this.plugin, { + state: { showControls: isVisible }, + }); + }, + toggleExpanded: (isExpanded) => { + if (typeof isExpanded === "undefined") + isExpanded = !this.plugin.layout.state.isExpanded; + PluginCommands.Layout.Update(this.plugin, { + state: { isExpanded: isExpanded }, + }); + }, + setBgColor: async (color) => { + if (!color) + return; + await this.canvas.applySettings({ color }); + }, + applySettings: async (settings) => { + if (!settings) + return; + if (!this.plugin.canvas3d) + return; + const renderer = { ...this.plugin.canvas3d.props.renderer }; + if (settings.color) { + renderer.backgroundColor = Color.fromRgb(settings.color.r, settings.color.g, settings.color.b); + } + if (settings.lighting) { + renderer.style = { name: settings.lighting }; // I don't think this does anything and I don't see how it could ever have worked + } + await PluginCommands.Canvas3D.SetSettings(this.plugin, { + settings: { renderer }, + }); + }, + }; + getLociForParams(params, structureNumber) { + let assemblyRef = this.assemblyRef; + if (structureNumber) { + assemblyRef = + this.plugin.managers.structure.hierarchy.current.structures[structureNumber - 1].cell.transform.ref; + } + if (assemblyRef === "") + return EmptyLoci; + const data = this.plugin.state.data.select(assemblyRef)[0] + .obj.data; + if (!data) + return EmptyLoci; + return QueryHelper.getInteractivityLoci(params, data); + } + getLociByPLDDT(score, structureNumber) { + let assemblyRef = this.assemblyRef; + if (structureNumber) { + assemblyRef = + this.plugin.managers.structure.hierarchy.current.structures[structureNumber - 1].cell.transform.ref; + } + if (assemblyRef === "") + return EmptyLoci; + const data = this.plugin.state.data.select(assemblyRef)[0] + .obj.data; + if (!data) + return EmptyLoci; + return AlphafoldView.getLociByPLDDT(score, data); + } + normalizeColor(colorVal, defaultColor) { + let color = Color.fromRgb(170, 170, 170); + try { + if (typeof colorVal.r !== "undefined") { + color = Color.fromRgb(colorVal.r, colorVal.g, colorVal.b); + } + else if (colorVal[0] === "#") { + color = Color(Number(`0x${colorVal.substr(1)}`)); + } + else { + color = Color(colorVal); + } + } + catch (e) { + if (defaultColor) + color = defaultColor; + } + return color; + } + visual = { + highlight: (params) => { + const loci = this.getLociForParams(params.data, params.structureNumber); + if (Loci.isEmpty(loci)) + return; + if (params.color) { + this.visual.setColor({ highlight: params.color }); + } + this.plugin.managers.interactivity.lociHighlights.highlightOnly({ + loci, + }); + if (params.focus) + this.plugin.managers.camera.focusLoci(loci); + }, + clearHighlight: async () => { + this.plugin.managers.interactivity.lociHighlights.highlightOnly({ + loci: EmptyLoci, + }); + if (this.isHighlightColorUpdated) + this.visual.reset({ highlightColor: true }); + }, + select: async (params) => { + // clear prvious selection + if (this.selectedParams) { + await this.visual.clearSelection(params.structureNumber); + } + // Structure list to apply selection + let structureData = this.plugin.managers.structure.hierarchy.current.structures; + if (params.structureNumber) { + structureData = [ + this.plugin.managers.structure.hierarchy.current.structures[params.structureNumber - 1], + ]; + } + // set non selected theme color + if (params.nonSelectedColor) { + for await (const s of structureData) { + await this.plugin.managers.structure.component.updateRepresentationsTheme(s.components, { + color: "uniform", + colorParams: { + value: this.normalizeColor(params.nonSelectedColor), + }, + }); + } + } + // apply individual selections + for await (const param of params.data) { + // get loci from param + const loci = this.getLociForParams([param], params.structureNumber); + if (Loci.isEmpty(loci)) + return; + // set default selection color to minimise change display + this.visual.setColor({ + select: param.color + ? param.color + : { r: 255, g: 112, b: 3 }, + }); + // apply selection + this.plugin.managers.interactivity.lociSelects.selectOnly({ + loci, + }); + // create theme param values and apply them to create overpaint + const themeParams = StructureComponentManager.getThemeParams(this.plugin, this.plugin.managers.structure.component.pivotStructure); + const colorValue = ParamDefinition.getDefaultValues(themeParams); + colorValue.action.params = { + color: param.color + ? this.normalizeColor(param.color) + : Color.fromRgb(255, 112, 3), + opacity: 1, + }; + await this.plugin.managers.structure.component.applyTheme(colorValue, structureData); + // add new representations + if (param.sideChain || param.representation) { + let repr = "ball-and-stick"; + if (param.representation) + repr = param.representation; + const defaultParams = StructureComponentManager.getAddParams(this.plugin, { + allowNone: false, + hideSelection: true, + checkExisting: true, + }); + const defaultValues = ParamDefinition.getDefaultValues(defaultParams); + defaultValues.options = { + label: "selection-by-script", + checkExisting: params.structureNumber ? false : true, + }; + const values = { + ...defaultValues, + ...{ representation: repr }, + }; + const structures = this.plugin.managers.structure.hierarchy.getStructuresWithSelection(); + await this.plugin.managers.structure.component.add(values, structures); + // Apply uniform theme + if (param.representationColor) { + let updatedStructureData = this.plugin.managers.structure.hierarchy.current + .structures; + if (params.structureNumber) { + updatedStructureData = [ + this.plugin.managers.structure.hierarchy.current + .structures[params.structureNumber - 1], + ]; + } + const comps = updatedStructureData[0].components; + const lastCompsIndex = comps.length - 1; + const recentRepComp = [comps[lastCompsIndex]]; + const uniformColor = param.representationColor + ? this.normalizeColor(param.representationColor) + : Color.fromRgb(255, 112, 3); + this.plugin.managers.structure.component.updateRepresentationsTheme(recentRepComp, { + color: "uniform", + colorParams: { value: uniformColor }, + }); + } + params.addedRepr = true; + } + // focus loci + if (param.focus) + this.plugin.managers.camera.focusLoci(loci); + // remove selection + this.plugin.managers.interactivity.lociSelects.deselect({ + loci, + }); + } + // reset selection color + this.visual.reset({ selectColor: true }); + // save selection params to optimise clear + this.selectedParams = params; + }, + clearSelection: async (structureNumber) => { + const structIndex = structureNumber ? structureNumber - 1 : 0; + this.plugin.managers.interactivity.lociSelects.deselectAll(); + // reset theme to default + if (this.selectedParams && this.selectedParams.nonSelectedColor) { + this.visual.reset({ theme: true }); + } + // remove overpaints + await clearStructureOverpaint(this.plugin, this.plugin.managers.structure.hierarchy.current.structures[structIndex].components); + // remove selection representations + if (this.selectedParams && this.selectedParams.addedRepr) { + const selReprCells = []; + for (const c of this.plugin.managers.structure.hierarchy.current + .structures[structIndex].components) { + if (c.cell && + c.cell.params && + c.cell.params.values && + c.cell.params.values.label === "selection-by-script") + selReprCells.push(c.cell); + } + if (selReprCells.length > 0) { + for await (const selReprCell of selReprCells) { + await PluginCommands.State.RemoveObject(this.plugin, { + state: selReprCell.parent, + ref: selReprCell.transform.ref, + }); + } + } + } + this.selectedParams = undefined; + }, + update: async (options, fullLoad) => { + console.debug("Updating PDBeMolstarPlugin instance with options:", options); + // Validate options + if (!options) { + console.error("Missing `options` argument to `PDBeMolstarPlugin.visual.update"); + return; + } + const validationIssues = validateInitParams(options); + if (validationIssues) { + console.error("Invalid PDBeMolstarPlugin options:", options); + return; + } + this.initParams = addDefaults(options, DefaultParams); + if (!this.initParams.moleculeId && !this.initParams.customData) + return false; + if (this.initParams.customData && + this.initParams.customData.url && + !this.initParams.customData.format) + return false; + PluginCustomState(this.plugin).initParams = this.initParams; + // Show/hide buttons in the viewport control panel + this.plugin.config.set(PluginConfig.Viewport.ShowExpand, !this.initParams.hideCanvasControls.includes("expand")); + this.plugin.config.set(PluginConfig.Viewport.ShowSelectionMode, !this.initParams.hideCanvasControls.includes("selection")); + this.plugin.config.set(PluginConfig.Viewport.ShowAnimation, !this.initParams.hideCanvasControls.includes("animation")); + this.plugin.config.set(PluginConfig.Viewport.ShowControls, !this.initParams.hideCanvasControls.includes("controlToggle")); + this.plugin.config.set(PluginConfig.Viewport.ShowSettings, !this.initParams.hideCanvasControls.includes("controlInfo")); + // Set background colour + if (this.initParams.bgColor || this.initParams.lighting) { + await this.canvas.applySettings({ + color: this.initParams.bgColor, + lighting: this.initParams.lighting, + }); + } + // Load Molecule CIF or coordQuery and Parse + const dataSource = this.getMoleculeSrcUrl(); + if (dataSource) { + await this.load({ + url: dataSource.url, + format: dataSource.format, + assemblyId: this.initParams.assemblyId, + isBinary: dataSource.isBinary, + }, fullLoad); + } + }, + visibility: async (data) => { + if (!data) + return; + for (const visual in data) { + const tags = StructureComponentTags[visual] ?? []; + for (const tag of tags) { + const componentRef = StateSelection.findTagInSubtree(this.plugin.state.data.tree, StateTransform.RootRef, tag); + if (componentRef) { + const compVisual = this.plugin.state.data.select(componentRef)[0]; + if (compVisual && compVisual.obj) { + const currentlyVisible = compVisual.state && compVisual.state.isHidden + ? false + : true; + if (data[visual] !== currentlyVisible) { + await PluginCommands.State.ToggleVisibility(this.plugin, { state: this.state, ref: componentRef }); + } + } + } + } + } + }, + toggleSpin: async (isSpinning, resetCamera) => { + if (!this.plugin.canvas3d) + return; + const trackball = this.plugin.canvas3d.props.trackball; + let toggleSpinParam = trackball.animate.name === "spin" + ? { name: "off", params: {} } + : { name: "spin", params: { speed: 1 } }; + if (typeof isSpinning !== "undefined") { + toggleSpinParam = { name: "off", params: {} }; + if (isSpinning) + toggleSpinParam = { name: "spin", params: { speed: 1 } }; + } + await PluginCommands.Canvas3D.SetSettings(this.plugin, { + settings: { + trackball: { ...trackball, animate: toggleSpinParam }, + }, + }); + if (resetCamera) + await PluginCommands.Camera.Reset(this.plugin, {}); + }, + focus: async (params, structureNumber) => { + const loci = this.getLociForParams(params, structureNumber); + this.plugin.managers.camera.focusLoci(loci); + }, + setColor: async (param) => { + if (!this.plugin.canvas3d) + return; + if (!param.highlight && !param.select) + return; + const renderer = { ...this.plugin.canvas3d.props.renderer }; + const marking = { ...this.plugin.canvas3d.props.marking }; + if (param.highlight) { + renderer.highlightColor = this.normalizeColor(param.highlight); + marking.highlightEdgeColor = Color.darken(this.normalizeColor(param.highlight), 1); + this.isHighlightColorUpdated = true; + } + if (param.select) { + renderer.selectColor = this.normalizeColor(param.select); + marking.selectEdgeColor = Color.darken(this.normalizeColor(param.select), 1); + this.isSelectedColorUpdated = true; + } + await PluginCommands.Canvas3D.SetSettings(this.plugin, { + settings: { renderer, marking }, + }); + }, + reset: async (params) => { + if (params.camera) + await PluginCommands.Camera.Reset(this.plugin, { + durationMs: 250, + }); + if (params.theme) { + const defaultTheme = { + color: this.initParams.alphafoldView + ? "plddt-confidence" + : "default", + }; + const componentGroups = this.plugin.managers.structure.hierarchy + .currentComponentGroups; + for (const compGrp of componentGroups) { + await this.plugin.managers.structure.component.updateRepresentationsTheme(compGrp, defaultTheme); + } + } + if (params.highlightColor || params.selectColor) { + if (!this.plugin.canvas3d) + return; + const renderer = { ...this.plugin.canvas3d.props.renderer }; + const marking = { ...this.plugin.canvas3d.props.marking }; + if (params.highlightColor) { + renderer.highlightColor = + this.defaultRendererProps.highlightColor; + marking.highlightEdgeColor = + this.defaultMarkingProps.highlightEdgeColor; + this.isHighlightColorUpdated = false; + } + if (params.selectColor) { + renderer.selectColor = + this.defaultRendererProps.selectColor; + marking.selectEdgeColor = + this.defaultMarkingProps.selectEdgeColor; + this.isSelectedColorUpdated = false; + } + await PluginCommands.Canvas3D.SetSettings(this.plugin, { + settings: { renderer, marking }, + }); + } + }, + }; + async clear() { + await this.plugin.clear(); + this.assemblyRef = ""; + this.selectedParams = void 0; + this.isHighlightColorUpdated = false; + this.isSelectedColorUpdated = false; + } +} +const StructureComponentTags = { + polymer: ["structure-component-static-polymer"], + het: [ + "structure-component-static-ligand", + "structure-component-static-ion", + ], + water: ["structure-component-static-water"], + carbs: ["structure-component-static-branched"], + nonStandard: ["structure-component-static-non-standard"], + coarse: ["structure-component-static-coarse"], + maps: ["volume-streaming-info"], +}; +window.PDBeMolstarPlugin = PDBeMolstarPlugin; diff --git a/frontend/venome-molstar/lib/labels.d.ts b/frontend/venome-molstar/lib/labels.d.ts new file mode 100644 index 00000000..e6f58abb --- /dev/null +++ b/frontend/venome-molstar/lib/labels.d.ts @@ -0,0 +1,2 @@ +import { PluginBehavior } from "molstar/lib/mol-plugin/behavior"; +export declare const PDBeLociLabelProvider: import("molstar/lib/mol-state/transformer").StateTransformer; diff --git a/frontend/venome-molstar/lib/labels.js b/frontend/venome-molstar/lib/labels.js new file mode 100644 index 00000000..7de23978 --- /dev/null +++ b/frontend/venome-molstar/lib/labels.js @@ -0,0 +1,46 @@ +import { PluginBehavior } from "molstar/lib/mol-plugin/behavior"; +import { StructureElement, StructureProperties, } from "molstar/lib/mol-model/structure"; +import { lociLabel } from "molstar/lib/mol-theme/label"; +import { PluginCustomState } from "./plugin-custom-state"; +export const PDBeLociLabelProvider = PluginBehavior.create({ + name: "pdbe-loci-label-provider", + category: "interaction", + ctor: class { + ctx; + f = { + label: (loci) => { + const superpositionView = PluginCustomState(this.ctx) + .initParams.superposition; + const label = []; + if (!superpositionView && + StructureElement.Loci.is(loci) && + loci.elements.length === 1) { + const entityNames = new Set(); + for (const { unit: u } of loci.elements) { + const l = StructureElement.Location.create(loci.structure, u, u.elements[0]); + const name = StructureProperties.entity + .pdbx_description(l) + .join(", "); + entityNames.add(name); + } + if (entityNames.size === 1) + entityNames.forEach((name) => label.push(name)); + } + label.push(lociLabel(loci)); + return label.filter((l) => !!l).join("
"); + }, + group: (label) => label.toString().replace(/Model [0-9]+/g, "Models"), + priority: 100, + }; + register() { + this.ctx.managers.lociLabels.addProvider(this.f); + } + unregister() { + this.ctx.managers.lociLabels.removeProvider(this.f); + } + constructor(ctx) { + this.ctx = ctx; + } + }, + display: { name: "Provide PDBe Loci Label" }, +}); diff --git a/frontend/venome-molstar/lib/loci-details.d.ts b/frontend/venome-molstar/lib/loci-details.d.ts new file mode 100644 index 00000000..73ca739e --- /dev/null +++ b/frontend/venome-molstar/lib/loci-details.d.ts @@ -0,0 +1,27 @@ +import { Bond } from "molstar/lib/mol-model/structure"; +import { Loci } from "molstar/lib/mol-model/loci"; +export type EventDetail = { + models?: string[]; + entity_id?: string; + label_asym_id?: string; + asym_id?: string; + auth_asym_id?: string; + unp_accession?: string; + unp_seq_id?: number; + seq_id?: number; + auth_seq_id?: number; + ins_code?: string; + comp_id?: string; + atom_id?: string[]; + alt_id?: string; + micro_het_comp_ids?: string[]; + seq_id_begin?: number; + seq_id_end?: number; + button?: number; + modifiers?: any; +}; +type LabelGranularity = "element" | "conformation" | "residue" | "chain" | "structure"; +export declare function lociDetails(loci: Loci): EventDetail | undefined; +export declare function bondLabel(bond: Bond.Location, granularity: LabelGranularity): any; +export declare function _bundleLabel(bundle: Loci.Bundle, granularity: LabelGranularity): EventDetail | (EventDetail | undefined)[]; +export {}; diff --git a/frontend/venome-molstar/lib/loci-details.js b/frontend/venome-molstar/lib/loci-details.js new file mode 100644 index 00000000..e0404b8d --- /dev/null +++ b/frontend/venome-molstar/lib/loci-details.js @@ -0,0 +1,141 @@ +import { Unit, StructureElement, StructureProperties as Props, } from "molstar/lib/mol-model/structure"; +import { OrderedSet } from "molstar/lib/mol-data/int"; +import { SIFTSMapping as BestDatabaseSequenceMappingProp } from "molstar/lib/mol-model-props/sequence/sifts-mapping"; +export function lociDetails(loci) { + switch (loci.kind) { + case "structure-loci": + return { + models: loci.structure.models + .map((m) => m.entry) + .filter((l) => !!l), + }; + case "element-loci": + return structureElementStatsDetail(StructureElement.Stats.ofLoci(loci)); + case "bond-loci": + const bond = loci.bonds[0]; + return bond ? bondLabel(bond, "element") : ""; + default: + return void 0; + } +} +function structureElementStatsDetail(stats) { + const { chainCount, residueCount, elementCount } = stats; + if (elementCount === 1 && residueCount === 0 && chainCount === 0) { + return getElementDetails(stats.firstElementLoc, "element"); + } + else if (elementCount === 0 && residueCount === 1 && chainCount === 0) { + return getElementDetails(stats.firstResidueLoc, "residue"); + } + else { + return void 0; + } +} +function getElementDetails(location, granularity = "element") { + const basicDetails = {}; + let entry = location.unit.model.entry; + if (entry.length > 30) + entry = entry.substr(0, 27) + "\u2026"; // ellipsis + basicDetails["entry_id"] = entry; // entry + if (granularity !== "structure") { + basicDetails["model"] = location.unit.model.modelNum; // model + basicDetails["instance"] = location.unit.conformation.operator.name; // instance + } + let elementDetails; + if (Unit.isAtomic(location.unit)) { + elementDetails = atomicElementDetails(location, granularity); + } + else if (Unit.isCoarse(location.unit)) { + elementDetails = coarseElementDetails(location, granularity); + } + return { ...basicDetails, ...elementDetails }; +} +function atomicElementDetails(location, granularity) { + const elementDetails = { + entity_id: Props.chain.label_entity_id(location), + label_asym_id: Props.chain.label_asym_id(location), + auth_asym_id: Props.chain.auth_asym_id(location), + unp_accession: undefined, + unp_seq_id: undefined, + seq_id: Props.residue.label_seq_id(location), + auth_seq_id: Props.residue.auth_seq_id(location), + ins_code: Props.residue.pdbx_PDB_ins_code(location), + comp_id: Props.atom.label_comp_id(location), + atom_id: [Props.atom.label_atom_id(location)], + alt_id: Props.atom.label_alt_id(location), + }; + const unpLabel = BestDatabaseSequenceMappingProp.getLabel(location); + if (unpLabel) { + const unpLabelDetails = unpLabel.split(" "); + if (unpLabelDetails[0] === "UNP") { + elementDetails.unp_accession = unpLabelDetails[1]; + elementDetails.unp_seq_id = +unpLabelDetails[2]; + } + } + const microHetCompIds = Props.residue.microheterogeneityCompIds(location); + elementDetails["micro_het_comp_ids"] = + granularity === "residue" && microHetCompIds.length > 1 + ? microHetCompIds + : [elementDetails["comp_id"]]; + return elementDetails; +} +function coarseElementDetails(location, granularity) { + const elementDetails = { + asym_id: Props.coarse.asym_id(location), + seq_id_begin: Props.coarse.seq_id_begin(location), + seq_id_end: Props.coarse.seq_id_end(location), + }; + if (granularity === "residue") { + if (elementDetails.seq_id_begin === elementDetails.seq_id_end) { + const entityIndex = Props.coarse.entityKey(location); + const seq = location.unit.model.sequence.byEntityKey[entityIndex]; + elementDetails["comp_id"] = seq.sequence.compId.value(elementDetails.seq_id_begin - 1); // 1-indexed + } + } + return elementDetails; +} +export function bondLabel(bond, granularity) { + return _bundleLabel({ + loci: [ + StructureElement.Loci(bond.aStructure, [ + { + unit: bond.aUnit, + indices: OrderedSet.ofSingleton(bond.aIndex), + }, + ]), + StructureElement.Loci(bond.bStructure, [ + { + unit: bond.bUnit, + indices: OrderedSet.ofSingleton(bond.bIndex), + }, + ]), + ], + }, granularity); +} +export function _bundleLabel(bundle, granularity) { + let isSingleElements = true; + for (const l of bundle.loci) { + if (!StructureElement.Loci.is(l) || + StructureElement.Loci.size(l) !== 1) { + isSingleElements = false; + break; + } + } + if (isSingleElements) { + const locations = bundle.loci.map((l) => { + const { unit, indices } = l.elements[0]; + return StructureElement.Location.create(l.structure, unit, unit.elements[OrderedSet.start(indices)]); + }); + const elementDetailsArr = locations.map((l) => getElementDetails(l, granularity)); + const atomIds = [ + elementDetailsArr[0].atom_id[0], + elementDetailsArr[1].atom_id[0], + ]; + const elementDetails = elementDetailsArr[0]; + elementDetails["atom_id"] = atomIds; + return elementDetails; + } + else { + const elementDetails = bundle.loci.map((l) => lociDetails(l)); + return elementDetails; + } +} diff --git a/frontend/venome-molstar/lib/overlay.d.ts b/frontend/venome-molstar/lib/overlay.d.ts new file mode 100644 index 00000000..2adc5879 --- /dev/null +++ b/frontend/venome-molstar/lib/overlay.d.ts @@ -0,0 +1,16 @@ +import { Subject } from 'rxjs'; +type OverlayEvents = 'resize' | 'hide'; +/** Shows overlay layer with animated PDBe logo */ +export declare class LoadingOverlay { + private readonly target; + private readonly subjects; + private readonly overlayHtml; + private readonly subscriptions; + constructor(target: HTMLElement, subjects?: { + readonly [key in OverlayEvents]?: Subject; + }, overlayHtml?: string); + private getOverlayParent; + show(): void; + hide(): void; +} +export {}; diff --git a/frontend/venome-molstar/lib/overlay.js b/frontend/venome-molstar/lib/overlay.js new file mode 100644 index 00000000..c63ba9c3 --- /dev/null +++ b/frontend/venome-molstar/lib/overlay.js @@ -0,0 +1,50 @@ +const PdbeAnimatedLogoSvg = ''; +const OverlayBox = `
${PdbeAnimatedLogoSvg}
`; +/** Shows overlay layer with animated PDBe logo */ +export class LoadingOverlay { + target; + subjects; + overlayHtml; + subscriptions = {}; + constructor(target, subjects = {}, overlayHtml = OverlayBox) { + this.target = target; + this.subjects = subjects; + this.overlayHtml = overlayHtml; + } + getOverlayParent() { + return this.target.parentElement ?? document.body; + } + show() { + this.hide(); + const overlayParent = this.getOverlayParent(); + const divOverlay = document.createElement('div'); + divOverlay.classList.add('pdbemolstar-overlay'); + // divOverlay.setAttribute('title', 'Loading...'); + divOverlay.innerHTML = this.overlayHtml; + overlayParent.appendChild(divOverlay); + const resize = () => { + const viewerRect = this.target.getElementsByClassName('msp-layout-main').item(0)?.getBoundingClientRect(); + if (viewerRect) { + const { left, top, width, height } = viewerRect; + const origin = this.target.offsetParent?.getBoundingClientRect() ?? { left: 0, top: 0 }; + divOverlay.setAttribute('style', `position: absolute; left: ${left - origin?.left}px; top: ${top - origin.top}px; width: ${width}px; height: ${height}px;`); + } + else { + divOverlay.setAttribute('style', `position: fixed; top: 0px; bottom: 0px; left: 0px; right: 0px;`); + } + }; + resize(); + this.subscriptions.resize = this.subjects.resize?.subscribe(() => resize()); + this.subscriptions.hide = this.subjects.hide?.subscribe(() => this.hide()); + } + hide() { + const existingOverlays = this.getOverlayParent().getElementsByClassName('pdbemolstar-overlay'); + for (let i = 0; i < existingOverlays.length; i++) { + existingOverlays.item(i)?.remove(); + } + this.subscriptions.resize?.unsubscribe(); + this.subscriptions.resize = undefined; + this.subscriptions.hide?.unsubscribe(); + this.subscriptions.hide = undefined; + } +} diff --git a/frontend/venome-molstar/lib/overlay.scss b/frontend/venome-molstar/lib/overlay.scss new file mode 100644 index 00000000..d47fb070 --- /dev/null +++ b/frontend/venome-molstar/lib/overlay.scss @@ -0,0 +1,46 @@ +.pdbemolstar-overlay { + z-index: 1000; + position: fixed; + top: 0px; + bottom: 0px; + left: 0px; + right: 0px; + display: flex; + justify-content: center; + align-items: center; + pointer-events: none; +} + +.pdbemolstar-overlay-box { + width: 25%; + height: 25%; +} + +svg.pdbe-animated-logo { + background-color: transparent; + width: 100%; + height: 100%; + opacity: 80%; + + .path-fg { + stroke-dasharray: 1812 250; + stroke-dashoffset: -250; + animation: dash linear normal infinite; + animation-duration: 5s; + animation-delay: 1s; + } + @keyframes dash { + 0% { + stroke-dashoffset: 1812; + } + 80% { + stroke-dashoffset: -250; + } + 100% { + stroke-dashoffset: -250; + } + } +} +.msp-plugin .msp-viewport-controls-buttons .msp-btn-link-toggle-off { + background: black !important; +} diff --git a/frontend/venome-molstar/lib/plugin-custom-state.d.ts b/frontend/venome-molstar/lib/plugin-custom-state.d.ts new file mode 100644 index 00000000..2e909220 --- /dev/null +++ b/frontend/venome-molstar/lib/plugin-custom-state.d.ts @@ -0,0 +1,84 @@ +import { SymmetryOperator } from "molstar/lib/mol-math/geometry"; +import { Mat4 } from "molstar/lib/mol-math/linear-algebra"; +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import { StateSelection, StateTransform } from "molstar/lib/mol-state"; +import { Subject } from "rxjs"; +import { InitParams } from "./spec"; +export interface PluginCustomState { + initParams?: InitParams; + events?: { + segmentUpdate: Subject; + superpositionInit: Subject; + isBusy: Subject; + }; + superpositionState?: { + models: { + [molId: string]: string; + }; + entries: { + [pdbId: string]: StateSelection.Selector; + }; + refMaps: { + [ref: string]: string; + }; + segmentData: Segment[] | undefined; + matrixData: { + [key: string]: { + matrix: number[][]; + }; + }; + activeSegment: number; + loadedStructs: string[][]; + visibleRefs: StateTransform.Ref[][]; + invalidStruct: string[]; + noMatrixStruct: string[]; + hets: { + [key: string]: unknown[]; + }; + colorPalette: [ + "dark-2", + "red-yellow-green", + "paired", + "set-1", + "accent", + "set-2", + "rainbow" + ]; + colorState: { + palleteIndex: number; + colorIndex: number; + }[]; + alphafold: { + apiData: { + cif: string; + pae: string; + length: number; + }; + length: number; + ref: string; + traceOnly: boolean; + visibility: boolean[]; + transforms: Mat4[]; + rmsds: string[][]; + coordinateSystems: (SymmetryOperator | undefined)[]; + }; + }; + superpositionError?: string; +} +export interface ClusterMember { + pdb_id: string; + auth_asym_id: string; + struct_asym_id: string; + entity_id: number; + is_representative: boolean; +} +export interface Segment { + segment_start: number; + segment_end: number; + clusters: ClusterMember[][]; + isHetView?: boolean; + isBinary?: boolean; +} +/** Access `plugin.customState` only through this function to get proper typing. + * Supports getting and setting properties. */ +export declare function PluginCustomState(plugin: PluginContext): PluginCustomState; diff --git a/frontend/venome-molstar/lib/plugin-custom-state.js b/frontend/venome-molstar/lib/plugin-custom-state.js new file mode 100644 index 00000000..65918a95 --- /dev/null +++ b/frontend/venome-molstar/lib/plugin-custom-state.js @@ -0,0 +1,5 @@ +/** Access `plugin.customState` only through this function to get proper typing. + * Supports getting and setting properties. */ +export function PluginCustomState(plugin) { + return (plugin.customState ??= {}); +} diff --git a/frontend/venome-molstar/lib/sifts-mapping.d.ts b/frontend/venome-molstar/lib/sifts-mapping.d.ts new file mode 100644 index 00000000..2fa430ba --- /dev/null +++ b/frontend/venome-molstar/lib/sifts-mapping.d.ts @@ -0,0 +1,16 @@ +import { Model } from "molstar/lib/mol-model/structure"; +import { StructureElement } from "molstar/lib/mol-model/structure/structure"; +import { CustomModelProperty } from "molstar/lib/mol-model-props/common/custom-model-property"; +export { SIFTSMapping as SIFTSMapping }; +export interface SIFTSMappingMapping { + readonly dbName: string[]; + readonly accession: string[]; + readonly num: string[]; + readonly residue: string[]; +} +declare namespace SIFTSMapping { + const Provider: CustomModelProperty.Provider<{}, SIFTSMappingMapping>; + function isAvailable(model: Model): boolean; + function getKey(loc: StructureElement.Location): string; + function getLabel(loc: StructureElement.Location): string | undefined; +} diff --git a/frontend/venome-molstar/lib/sifts-mapping.js b/frontend/venome-molstar/lib/sifts-mapping.js new file mode 100644 index 00000000..1442bb54 --- /dev/null +++ b/frontend/venome-molstar/lib/sifts-mapping.js @@ -0,0 +1,83 @@ +import { Column } from "molstar/lib/mol-data/db"; +import { MmcifFormat } from "molstar/lib/mol-model-formats/structure/mmcif"; +import { CustomPropertyDescriptor } from "molstar/lib/mol-model/custom-property"; +import { CustomModelProperty } from "molstar/lib/mol-model-props/common/custom-model-property"; +export { SIFTSMapping as SIFTSMapping }; +var SIFTSMapping; +(function (SIFTSMapping) { + SIFTSMapping.Provider = CustomModelProperty.createProvider({ + label: "SIFTS Mapping", + descriptor: CustomPropertyDescriptor({ + name: "sifts_sequence_mapping", + }), + type: "static", + defaultParams: {}, + getParams: () => ({}), + isApplicable: (data) => isAvailable(data), + obtain: async (ctx, data) => { + return { value: fromCif(data) }; + }, + }); + function isAvailable(model) { + if (!MmcifFormat.is(model.sourceData)) + return false; + const { pdbx_sifts_xref_db_name: db_name, pdbx_sifts_xref_db_acc: db_acc, pdbx_sifts_xref_db_num: db_num, pdbx_sifts_xref_db_res: db_res, } = model.sourceData.data.db.atom_site; + return (db_name.isDefined && + db_acc.isDefined && + db_num.isDefined && + db_res.isDefined); + } + SIFTSMapping.isAvailable = isAvailable; + function getKey(loc) { + const model = loc.unit.model; + const data = SIFTSMapping.Provider.get(model).value; + if (!data) + return ""; + const rI = model.atomicHierarchy.residueAtomSegments.index[loc.element]; + return data.accession[rI]; + } + SIFTSMapping.getKey = getKey; + function getLabel(loc) { + const model = loc.unit.model; + const data = SIFTSMapping.Provider.get(model).value; + if (!data) + return; + const rI = model.atomicHierarchy.residueAtomSegments.index[loc.element]; + const dbName = data.dbName[rI]; + if (!dbName) + return; + return `${dbName} ${data.accession[rI]} ${data.num[rI]} ${data.residue[rI]}`; + } + SIFTSMapping.getLabel = getLabel; + function fromCif(model) { + if (!MmcifFormat.is(model.sourceData)) + return; + const { pdbx_sifts_xref_db_name: db_name, pdbx_sifts_xref_db_acc: db_acc, pdbx_sifts_xref_db_num: db_num, pdbx_sifts_xref_db_res: db_res, } = model.sourceData.data.db.atom_site; + if (!db_name.isDefined || + !db_acc.isDefined || + !db_num.isDefined || + !db_res.isDefined) + return; + const { atomSourceIndex } = model.atomicHierarchy; + const { count, offsets: residueOffsets } = model.atomicHierarchy.residueAtomSegments; + const dbName = new Array(count); + const accession = new Array(count); + const num = new Array(count); + const residue = new Array(count); + for (let i = 0; i < count; i++) { + const row = atomSourceIndex.value(residueOffsets[i]); + if (db_name.valueKind(row) !== Column.ValueKind.Present) { + dbName[i] = ""; + accession[i] = ""; + num[i] = ""; + residue[i] = ""; + continue; + } + dbName[i] = db_name.value(row); + accession[i] = db_acc.value(row); + num[i] = db_num.value(row); + residue[i] = db_res.value(row); + } + return { dbName, accession, num, residue }; + } +})(SIFTSMapping || (SIFTSMapping = {})); diff --git a/frontend/venome-molstar/lib/sifts-mappings-behaviour.d.ts b/frontend/venome-molstar/lib/sifts-mappings-behaviour.d.ts new file mode 100644 index 00000000..b496adec --- /dev/null +++ b/frontend/venome-molstar/lib/sifts-mappings-behaviour.d.ts @@ -0,0 +1,5 @@ +import { PluginBehavior } from "molstar/lib/mol-plugin/behavior"; +export declare const PDBeSIFTSMapping: import("molstar/lib/mol-state/transformer").StateTransformer; diff --git a/frontend/venome-molstar/lib/sifts-mappings-behaviour.js b/frontend/venome-molstar/lib/sifts-mappings-behaviour.js new file mode 100644 index 00000000..15249661 --- /dev/null +++ b/frontend/venome-molstar/lib/sifts-mappings-behaviour.js @@ -0,0 +1,54 @@ +import { OrderedSet } from "molstar/lib/mol-data/int"; +import { SIFTSMapping as BestDatabaseSequenceMappingProp } from "./sifts-mapping"; +import { SIFTSMappingColorThemeProvider } from "molstar/lib/mol-model-props/sequence/themes/sifts-mapping"; +import { StructureElement } from "molstar/lib/mol-model/structure"; +import { ParamDefinition as PD } from "molstar/lib/mol-util/param-definition"; +import { PluginBehavior } from "molstar/lib/mol-plugin/behavior"; +export const PDBeSIFTSMapping = PluginBehavior.create({ + name: "pdbe-sifts-mapping-prop", + category: "custom-props", + display: { name: "PDBe SIFTS Mapping" }, + ctor: class extends PluginBehavior.Handler { + provider = BestDatabaseSequenceMappingProp.Provider; + labelProvider = { + label: (loci) => { + if (!this.params.showTooltip) + return; + return PDBeBestDatabaseSequenceMappingLabel(loci); + }, + }; + update(p) { + const updated = this.params.autoAttach !== p.autoAttach || + this.params.showTooltip !== p.showTooltip; + this.params.autoAttach = p.autoAttach; + this.params.showTooltip = p.showTooltip; + this.ctx.customStructureProperties.setDefaultAutoAttach(this.provider.descriptor.name, this.params.autoAttach); + return updated; + } + register() { + this.ctx.customModelProperties.register(this.provider, this.params.autoAttach); + this.ctx.representation.structure.themes.colorThemeRegistry.add(SIFTSMappingColorThemeProvider); + this.ctx.managers.lociLabels.addProvider(this.labelProvider); + } + unregister() { + this.ctx.customModelProperties.unregister(this.provider.descriptor.name); + this.ctx.representation.structure.themes.colorThemeRegistry.remove(SIFTSMappingColorThemeProvider); + this.ctx.managers.lociLabels.removeProvider(this.labelProvider); + } + }, + params: () => ({ + autoAttach: PD.Boolean(true), + showTooltip: PD.Boolean(true), + }), +}); +// +function PDBeBestDatabaseSequenceMappingLabel(loci) { + if (loci.kind === "element-loci") { + if (loci.elements.length === 0) + return; + const e = loci.elements[0]; + const u = e.unit; + const se = StructureElement.Location.create(loci.structure, u, u.elements[OrderedSet.getAt(e.indices, 0)]); + return BestDatabaseSequenceMappingProp.getLabel(se); + } +} diff --git a/frontend/venome-molstar/lib/spec-from-html.d.ts b/frontend/venome-molstar/lib/spec-from-html.d.ts new file mode 100644 index 00000000..c6afcf10 --- /dev/null +++ b/frontend/venome-molstar/lib/spec-from-html.d.ts @@ -0,0 +1,3 @@ +import { InitParams } from './spec'; +/** Extract InitParams from attributes of an HTML element */ +export declare function initParamsFromHtmlAttributes(element: HTMLElement): Partial; diff --git a/frontend/venome-molstar/lib/spec-from-html.js b/frontend/venome-molstar/lib/spec-from-html.js new file mode 100644 index 00000000..c31237cb --- /dev/null +++ b/frontend/venome-molstar/lib/spec-from-html.js @@ -0,0 +1,109 @@ +import { Encoding, Lighting, Preset, VisualStyle, validateInitParams } from './spec'; +/** Extract InitParams from attributes of an HTML element */ +export function initParamsFromHtmlAttributes(element) { + const params = loadHtmlAttributes(element, InitParamsLoadingActions, {}); + const validationIssues = validateInitParams(params); + if (validationIssues) + console.error('Invalid PDBeMolstarPlugin options:', params); + return params; +} +/** Actions for loading individual HTML attributes into InitParams object */ +const InitParamsLoadingActions = { + 'molecule-id': setString('moleculeId'), + 'custom-data-url': (value, params) => { (params.customData ??= defaultCustomData()).url = value; }, + 'custom-data-format': (value, params) => { (params.customData ??= defaultCustomData()).format = value; }, + 'custom-data-binary': (value, params) => { (params.customData ??= defaultCustomData()).binary = parseBool(value); }, + 'assembly-id': setString('assemblyId'), + 'default-preset': setLiteral(Preset, 'defaultPreset'), + 'ligand-label-comp-id': (value, params) => { (params.ligandView ??= {}).label_comp_id = value; }, + 'ligand-auth-asym-id': (value, params) => { (params.ligandView ??= {}).auth_asym_id = value; }, + 'ligand-struct-asym-id': (value, params) => { (params.ligandView ??= {}).struct_asym_id = value; }, + 'ligand-auth-seq-id': (value, params) => { (params.ligandView ??= {}).auth_seq_id = Number(value); }, + 'ligand-show-all': (value, params) => { (params.ligandView ??= {}).show_all = parseBool(value); }, + 'alphafold-view': setBool('alphafoldView'), + 'visual-style': setLiteral(VisualStyle, 'visualStyle'), + 'hide-polymer': pushItem('hideStructure', 'polymer'), + 'hide-water': pushItem('hideStructure', 'water'), + 'hide-het': pushItem('hideStructure', 'het'), + 'hide-carbs': pushItem('hideStructure', 'carbs'), + 'hide-non-standard': pushItem('hideStructure', 'nonStandard'), + 'hide-coarse': pushItem('hideStructure', 'coarse'), + 'load-maps': setBool('loadMaps'), + 'bg-color-r': setColorComponent('bgColor', 'r'), + 'bg-color-g': setColorComponent('bgColor', 'g'), + 'bg-color-b': setColorComponent('bgColor', 'b'), + 'highlight-color-r': setColorComponent('highlightColor', 'r'), + 'highlight-color-g': setColorComponent('highlightColor', 'g'), + 'highlight-color-b': setColorComponent('highlightColor', 'b'), + 'select-color-r': setColorComponent('selectColor', 'r'), + 'select-color-g': setColorComponent('selectColor', 'g'), + 'select-color-b': setColorComponent('selectColor', 'b'), + 'lighting': setLiteral(Lighting, 'lighting'), + 'validation-annotation': setBool('validationAnnotation'), + 'domain-annotation': setBool('domainAnnotation'), + 'symmetry-annotation': setBool('symmetryAnnotation'), + 'pdbe-url': setString('pdbeUrl'), + 'encoding': setLiteral(Encoding, 'encoding'), + 'low-precision': setBool('lowPrecisionCoords'), + 'select-interaction': setBool('selectInteraction'), + 'subscribe-events': setBool('subscribeEvents'), + 'hide-controls': setBool('hideControls'), + 'hide-expand-icon': pushItem('hideCanvasControls', 'expand'), + 'hide-selection-icon': pushItem('hideCanvasControls', 'selection'), + 'hide-animation-icon': pushItem('hideCanvasControls', 'animation'), + 'hide-control-toggle-icon': pushItem('hideCanvasControls', 'controlToggle'), + 'hide-control-info-icon': pushItem('hideCanvasControls', 'controlInfo'), + 'sequence-panel': setBool('sequencePanel'), + 'pdbe-link': setBool('pdbeLink'), + 'loading-overlay': setBool('loadingOverlay'), + 'expanded': setBool('expanded'), + 'landscape': setBool('landscape'), + 'reactive': setBool('reactive'), +}; +/** Load attributes of an HTML element into a context */ +function loadHtmlAttributes(element, actions, context) { + for (const attribute in actions) { + const value = element.getAttribute(attribute); + if (typeof value === 'string') { + actions[attribute](value, context); + } + } + return context; +} +function setString(key) { + return (value, obj) => { obj[key] = value; }; +} +function setLiteral(allowedValues, key) { + return (value, ctx) => { + if (!allowedValues.includes(value)) + console.error(`Value "${value}" is not valid for type ${allowedValues.map(s => `"${s}"`).join(' | ')}`); + ctx[key] = value; + }; +} +function setBool(key) { + return (value, obj) => { obj[key] = parseBool(value); }; +} +function setColorComponent(key, component) { + return (value, obj) => { + const color = obj[key] ??= { r: 0, g: 0, b: 0 }; + color[component] = Number(value); + }; +} +function pushItem(key, item) { + return (value, obj) => { + if (parseBool(value)) { + const array = obj[key] ??= []; + array.push(item); + } + }; +} +/** Parse a string into a boolean. + * Consider strings like 'false', 'OFF', '0' as false; others as true. + * Empty string is parsed as true, because HTML attribute without value must be treated as truthy. */ +function parseBool(value) { + const FalseyStrings = ['false', 'off', '0']; + return !FalseyStrings.includes(value.toLowerCase()); +} +function defaultCustomData() { + return { url: '', format: '', binary: false }; +} diff --git a/frontend/venome-molstar/lib/spec.d.ts b/frontend/venome-molstar/lib/spec.d.ts new file mode 100644 index 00000000..676c8a05 --- /dev/null +++ b/frontend/venome-molstar/lib/spec.d.ts @@ -0,0 +1,122 @@ +import { Loci } from "molstar/lib/mol-model/loci"; +import { PluginUISpec } from "molstar/lib/mol-plugin-ui/spec"; +import { DefaultFocusLociBindings } from "molstar/lib/mol-plugin/behavior/dynamic/camera"; +import { DefaultSelectLociBindings } from "molstar/lib/mol-plugin/behavior/dynamic/representation"; +import { PluginSpec } from "molstar/lib/mol-plugin/spec"; +import { LigandQueryParam, MapParams, QueryParam } from "./helpers"; +export declare const DefaultPluginSpec: () => PluginSpec; +export declare const DefaultPluginUISpec: () => PluginUISpec; +/** RGB color (r, g, b values 0-255) */ +export interface ColorParams { + r: number; + g: number; + b: number; +} +export declare const Preset: readonly ["default", "unitcell", "all-models", "supercell"]; +export type Preset = (typeof Preset)[number]; +export declare const Lighting: readonly ["flat", "matte", "glossy", "metallic", "plastic"]; +export type Lighting = (typeof Lighting)[number]; +export declare const VisualStyle: readonly ["cartoon", "ball-and-stick", "carbohydrate", "ellipsoid", "gaussian-surface", "molecular-surface", "point", "putty", "spacefill"]; +export type VisualStyle = (typeof VisualStyle)[number]; +export declare const Encoding: readonly ["cif", "bcif"]; +export type Encoding = (typeof Encoding)[number]; +/** Options for initializing `PDBeMolstarPlugin` */ +export interface InitParams { + /** PDB ID (example: '1cbs'), or UniProt ID if `superposition` is `true`. Leave `undefined` only when setting `customData` */ + moleculeId?: string; + /** Load data from a specific data source. + * Example: `{ url: 'https://www.ebi.ac.uk/pdbe/model-server/v1/1cbs/atoms?label_entity_id=1&auth_asym_id=A&encoding=bcif', format: 'cif', binary: true }` */ + customData?: { + url: string; + format: string; + binary: boolean; + }; + /** Leave `undefined` to load deposited model structure. Use assembly identifier to load assembly structure. or 'preferred' to load default assembly (i.e. the first assembly). */ + assemblyId?: string; + /** Specify type of structure to be loaded */ + defaultPreset: Preset; + /** Use to display the PDBe ligand page 3D view like here (https://www.ebi.ac.uk/pdbe/entry/pdb/1cbs/bound/REA). + * Example: `{ label_comp_id: 'REA' }`. At least one is required of `label_comp_id` and `auth_seq_id` */ + ligandView?: LigandQueryParam; + /** This applies AlphaFold confidence score colouring theme for AlphaFold model */ + alphafoldView: boolean; + /** Display the superposed structures view like the one on the PDBe-KB pages. */ + superposition: boolean; + /** Customize the superposed structures view. Example: `{ matrixAccession: 'P08684', segment: 1, ligandView: true, ligandColor: { r: 255, g: 255, b: 50} }`. */ + superpositionParams?: { + matrixAccession?: string; + segment?: number; + cluster?: number[]; + superposeCompleteCluster?: boolean; + ligandView?: boolean; + superposeAll?: boolean; + ligandColor?: ColorParams; + }; + /** Specify parts of the structure to highlight with different colors */ + selection?: { + data: QueryParam[]; + nonSelectedColor?: ColorParams; + clearPrevious?: boolean; + }; + /** Leave `undefined` to keep both cartoon and ball-and-sticks based on component type */ + visualStyle?: VisualStyle; + /** Molstar renders multiple visuals (polymer, ligand, water...) visuals by default. This option is to exclude any of these default visuals */ + hideStructure: ("polymer" | "het" | "water" | "carbs" | "nonStandard" | "coarse")[]; + /** Load electron density (or EM) maps from Volume Server if value is set to true */ + loadMaps: boolean; + /** Customize map style (opacity and solid/wireframe) */ + mapSettings?: MapParams; + /** Canvas background color */ + bgColor: ColorParams; + /** Color appearing on mouse-over */ + highlightColor?: ColorParams; + /** Color for marking the selected part of structure (when Selection Mode is active) */ + selectColor?: ColorParams; + /** Default lighting (I don't think it really works) */ + lighting?: Lighting; + /** Load Validation Report Annotations. Adds 'Annotations' control in the menu */ + validationAnnotation: boolean; + /** Load Domain Annotations. Adds 'Annotations' control in the menu */ + domainAnnotation: boolean; + /** Load Assembly Symmetry Annotations. Adds 'Annotations' control in the menu */ + symmetryAnnotation: boolean; + /** This option is to set the default base URL for the data source. Mostly used internally to test the plugin on different environments */ + pdbeUrl: string; + /** Preferred encoding of input structural data */ + encoding: Encoding; + /** Load low precision coordinates from Model Server */ + lowPrecisionCoords: boolean; + /** Controls the action performed when clicking a residue. `true` (default) will zoom the residue + * and show ball-and-stick visual for its surroundings, `false` will only zoom the residue. + * If `ligandView` or `superposition` option is set, `selectInteraction` behaves as if `false`. */ + selectInteraction: boolean; + /** Override mouse selection behavior */ + selectBindings?: typeof DefaultSelectLociBindings; + /** Override mouse click focus behaviour */ + focusBindings?: typeof DefaultFocusLociBindings; + /** Structure granularity level for interactions like highlight, focus, select. + * (Granularity levels ending with `Instances` treat multiple copies of the same element/residue/chain in an assembly as one object). */ + granularity?: Loci.Granularity; + /** Subscribe to other PDB Web-components custom events */ + subscribeEvents: boolean; + /** Hide all control panels by default (can be shown by the Toggle Controls Panel button (wrench icon)) */ + hideControls: boolean; + /** Hide individual icon buttons in the top-right corner of the canvas */ + hideCanvasControls: ("expand" | "selection" | "animation" | "controlToggle" | "controlInfo")[]; + /** Display Sequence panel */ + sequencePanel: boolean; + /** Display PDBe entry link in top right corner of the canvas */ + pdbeLink: boolean; + /** Show overlay with PDBe logo while the initial structure is being loaded */ + loadingOverlay: boolean; + /** Display full-screen by default on load */ + expanded: boolean; + /** Set landscape layout (control panels on the sides instead of above and under the canvas) */ + landscape: boolean; + /** Set reactive layout (switching between landscape and portrait based on the browser window size). Overrides `landscape`. */ + reactive: boolean; +} +/** Default values for `InitParams` */ +export declare const DefaultParams: InitParams; +/** Return `undefined` if `params` are valid, an error message otherwise. */ +export declare function validateInitParams(params: Partial): string | undefined; diff --git a/frontend/venome-molstar/lib/spec.js b/frontend/venome-molstar/lib/spec.js new file mode 100644 index 00000000..7dfefca8 --- /dev/null +++ b/frontend/venome-molstar/lib/spec.js @@ -0,0 +1,124 @@ +import { StateActions } from "molstar/lib/mol-plugin-state/actions"; +import { VolumeStreamingCustomControls } from "molstar/lib/mol-plugin-ui/custom/volume"; +import { PluginBehaviors } from "molstar/lib/mol-plugin/behavior"; +import { CreateVolumeStreamingBehavior } from "molstar/lib/mol-plugin/behavior/dynamic/volume-streaming/transformers"; +import { PluginConfig } from "molstar/lib/mol-plugin/config"; +import { PluginSpec } from "molstar/lib/mol-plugin/spec"; +import { PDBeLociLabelProvider } from "./labels"; +import { PDBeSIFTSMapping } from "./sifts-mappings-behaviour"; +export const DefaultPluginSpec = () => ({ + actions: [ + PluginSpec.Action(StateActions.Structure.EnableStructureCustomProps), + ], + behaviors: [ + PluginSpec.Behavior(PluginBehaviors.Representation.HighlightLoci), + PluginSpec.Behavior(PluginBehaviors.Representation.SelectLoci), + PluginSpec.Behavior(PDBeLociLabelProvider), + PluginSpec.Behavior(PluginBehaviors.Representation.FocusLoci), + PluginSpec.Behavior(PluginBehaviors.Camera.FocusLoci), + PluginSpec.Behavior(PluginBehaviors.Camera.CameraAxisHelper), + PluginSpec.Behavior(PluginBehaviors.CustomProps.StructureInfo), + PluginSpec.Behavior(PluginBehaviors.CustomProps.AccessibleSurfaceArea), + PluginSpec.Behavior(PDBeSIFTSMapping, { + autoAttach: true, + showTooltip: true, + }), + PluginSpec.Behavior(PluginBehaviors.CustomProps.Interactions), + PluginSpec.Behavior(PluginBehaviors.CustomProps.SecondaryStructure), + PluginSpec.Behavior(PluginBehaviors.CustomProps.ValenceModel), + PluginSpec.Behavior(PluginBehaviors.CustomProps.CrossLinkRestraint), + ], + // animations: [], + config: [ + [ + PluginConfig.VolumeStreaming.DefaultServer, + "https://www.ebi.ac.uk/pdbe/volume-server", + ], + [ + PluginConfig.VolumeStreaming.EmdbHeaderServer, + "https://files.wwpdb.org/pub/emdb/structures", + ], + ], +}); +export const DefaultPluginUISpec = () => ({ + ...DefaultPluginSpec(), + customParamEditors: [ + [CreateVolumeStreamingBehavior, VolumeStreamingCustomControls], + ], +}); +export const Preset = [ + "default", + "unitcell", + "all-models", + "supercell", +]; +export const Lighting = [ + "flat", + "matte", + "glossy", + "metallic", + "plastic", +]; +export const VisualStyle = [ + "cartoon", + "ball-and-stick", + "carbohydrate", + "ellipsoid", + "gaussian-surface", + "molecular-surface", + "point", + "putty", + "spacefill", +]; +export const Encoding = ["cif", "bcif"]; +/** Default values for `InitParams` */ +export const DefaultParams = { + moleculeId: undefined, + customData: undefined, + assemblyId: undefined, + defaultPreset: "default", + ligandView: undefined, + alphafoldView: false, + superposition: false, + superpositionParams: undefined, + selection: undefined, + visualStyle: undefined, + hideStructure: [], + loadMaps: false, + mapSettings: undefined, + bgColor: { r: 0, g: 0, b: 0 }, + highlightColor: undefined, + selectColor: undefined, + lighting: undefined, + validationAnnotation: false, + domainAnnotation: false, + symmetryAnnotation: false, + pdbeUrl: "https://www.ebi.ac.uk/pdbe/", + encoding: "bcif", + lowPrecisionCoords: false, + selectInteraction: true, + selectBindings: undefined, + focusBindings: undefined, + granularity: undefined, + subscribeEvents: false, + hideControls: false, + hideCanvasControls: [], + sequencePanel: false, + pdbeLink: true, + loadingOverlay: false, + expanded: false, + landscape: false, + reactive: false, +}; +/** Return `undefined` if `params` are valid, an error message otherwise. */ +export function validateInitParams(params) { + if (!params.moleculeId && !params.customData?.url) + return "Option `moleculeId` or `customData` must be defined"; + if (params.customData) { + if (!params.customData.url) + return "Option `customData.url` must be a non-empty string"; + if (!params.customData.format) + return "Option `customData.format` must be a non-empty string"; + } + return undefined; +} diff --git a/frontend/venome-molstar/lib/subscribe-events.d.ts b/frontend/venome-molstar/lib/subscribe-events.d.ts new file mode 100644 index 00000000..438ca9bc --- /dev/null +++ b/frontend/venome-molstar/lib/subscribe-events.d.ts @@ -0,0 +1 @@ +export declare function subscribeToComponentEvents(wrapperCtx: any): void; diff --git a/frontend/venome-molstar/lib/subscribe-events.js b/frontend/venome-molstar/lib/subscribe-events.js new file mode 100644 index 00000000..4637fbe7 --- /dev/null +++ b/frontend/venome-molstar/lib/subscribe-events.js @@ -0,0 +1,190 @@ +export function subscribeToComponentEvents(wrapperCtx) { + document.addEventListener('PDB.interactions.click', function (e) { + if (typeof e.detail !== 'undefined') { + const data = e.detail.interacting_nodes ? { data: e.detail.interacting_nodes } : { data: [e.detail.selected_node] }; + data.data[0]['focus'] = true; + wrapperCtx.visual.select(data); + } + }); + document.addEventListener('PDB.interactions.mouseover', function (e) { + if (typeof e.detail !== 'undefined') { + const data = e.detail.interacting_nodes ? { data: e.detail.interacting_nodes } : { data: [e.detail.selected_node] }; + wrapperCtx.visual.highlight(data); + } + }); + document.addEventListener('PDB.interactions.mouseout', function (e) { + wrapperCtx.visual.clearHighlight(); + }); + document.addEventListener('PDB.topologyViewer.click', function (e) { + if (typeof e.eventData !== 'undefined') { + // Create query object from event data + const highlightQuery = { + entity_id: e.eventData.entityId, + struct_asym_id: e.eventData.structAsymId, + start_residue_number: e.eventData.residueNumber, + end_residue_number: e.eventData.residueNumber, + sideChain: true, + focus: true + }; + // Call highlightAnnotation + wrapperCtx.visual.select({ data: [highlightQuery] }); + } + }); + document.addEventListener('PDB.topologyViewer.mouseover', function (e) { + if (typeof e.eventData !== 'undefined') { + // Abort if entryid do not match or viewer type is unipdb + // if(e.eventData.entryId != scope.pdbId) return; + // Create query object from event data + const highlightQuery = { + entity_id: e.eventData.entityId, + struct_asym_id: e.eventData.structAsymId, + start_residue_number: e.eventData.residueNumber, + end_residue_number: e.eventData.residueNumber + }; + // Call highlightAnnotation + wrapperCtx.visual.highlight({ data: [highlightQuery] }); + } + }); + document.addEventListener('PDB.topologyViewer.mouseout', function (e) { + wrapperCtx.visual.clearHighlight(); + }); + document.addEventListener('protvista-mouseover', function (e) { + if (typeof e.detail !== 'undefined') { + let highlightQuery = undefined; + // Create query object from event data + if (e.detail.start && e.detail.end) { + highlightQuery = { + start_residue_number: parseInt(e.detail.start), + end_residue_number: parseInt(e.detail.end) + }; + } + if (e.detail.feature && e.detail.feature.entityId) + highlightQuery['entity_id'] = e.detail.feature.entityId + ''; + if (e.detail.feature && e.detail.feature.bestChainId) + highlightQuery['struct_asym_id'] = e.detail.feature.bestChainId; + if (e.detail.feature && e.detail.feature.chainId) + highlightQuery['struct_asym_id'] = e.detail.feature.chainId; + if (highlightQuery) + wrapperCtx.visual.highlight({ data: [highlightQuery] }); + } + }); + document.addEventListener('protvista-mouseout', function (e) { + wrapperCtx.visual.clearHighlight(); + }); + document.addEventListener('protvista-click', function (e) { + if (typeof e.detail !== 'undefined') { + let showInteraction = false; + let highlightQuery = undefined; + // Create query object from event data + if (e.detail.start && e.detail.end) { + highlightQuery = { + start_residue_number: parseInt(e.detail.start), + end_residue_number: parseInt(e.detail.end) + }; + } + if (e.detail.feature && e.detail.feature.entityId) + highlightQuery['entity_id'] = e.detail.feature.entityId + ''; + if (e.detail.feature && e.detail.feature.bestChainId) + highlightQuery['struct_asym_id'] = e.detail.feature.bestChainId; + if (e.detail.feature && e.detail.feature.chainId) + highlightQuery['struct_asym_id'] = e.detail.feature.chainId; + if (e.detail.feature && e.detail.feature.accession && e.detail.feature.accession.split(' ')[0] === 'Chain' || e.detail.feature.tooltipContent === 'Ligand binding site') { + showInteraction = true; + } + if (e.detail.start === e.detail.end) + showInteraction = true; + if (highlightQuery) { + if (showInteraction) { + highlightQuery['sideChain'] = true; + } + else { + let selColor = undefined; + if (e.detail.trackIndex > -1 && e.detail.feature.locations && e.detail.feature.locations[0].fragments[e.detail.trackIndex].color) + selColor = e.detail.feature.locations[0].fragments[e.detail.trackIndex].color; + if (typeof selColor == 'undefined' && e.detail.feature.color) + selColor = e.detail.feature.color; + if (typeof selColor == 'undefined' && e.detail.color) + selColor = e.detail.color; + if (typeof selColor == 'undefined') { + selColor = { r: 65, g: 96, b: 91 }; + } + else { + const isRgb = /rgb/g; + if (isRgb.test(selColor)) { + const rgbArr = selColor.substring(4, selColor.length - 1).split(','); + selColor = { r: rgbArr[0], g: rgbArr[1], b: rgbArr[2] }; + } + } + highlightQuery['color'] = selColor; + } + highlightQuery['focus'] = true; + wrapperCtx.visual.select({ data: [highlightQuery] }); + } + } + }); + const elementTypeArrForRange = ['uniprot', 'pfam', 'cath', 'scop', 'strand', 'helice']; + const elementTypeArrForSingle = ['chain', 'quality', 'quality_outlier', 'binding site', 'alternate conformer']; + document.addEventListener('PDB.seqViewer.click', function (e) { + if (typeof e.eventData !== 'undefined') { + // Abort if entryid and entityid do not match or viewer type is unipdb + // if(e.eventData.entryId != scope.pdbId) return; + if (typeof e.eventData.elementData !== 'undefined' && elementTypeArrForSingle.indexOf(e.eventData.elementData.elementType) > -1) { + // Create query object from event data + const highlightQuery = { + entity_id: e.eventData.entityId, + struct_asym_id: e.eventData.elementData.pathData.struct_asym_id, + start_residue_number: e.eventData.residueNumber, + end_residue_number: e.eventData.residueNumber, + sideChain: true, + focus: true + }; + // Call highlightAnnotation + wrapperCtx.visual.select({ data: [highlightQuery] }); + } + else if (typeof e.eventData.elementData !== 'undefined' && elementTypeArrForRange.indexOf(e.eventData.elementData.elementType) > -1) { + const seqColorArray = e.eventData.elementData.color; + // Create query object from event data + const highlightQuery = { + entity_id: e.eventData.entityId, + struct_asym_id: e.eventData.elementData.pathData.struct_asym_id, + start_residue_number: e.eventData.elementData.pathData.start.residue_number, + end_residue_number: e.eventData.elementData.pathData.end.residue_number, + color: { r: seqColorArray[0], g: seqColorArray[1], b: seqColorArray[2] }, + focus: true + }; + wrapperCtx.visual.select({ data: [highlightQuery] }); + } + } + }); + document.addEventListener('PDB.seqViewer.mouseover', function (e) { + if (typeof e.eventData !== 'undefined') { + // Abort if entryid and entityid do not match or viewer type is unipdb + // if(e.eventData.entryId != scope.pdbId) return; + if (typeof e.eventData.elementData !== 'undefined' && elementTypeArrForSingle.indexOf(e.eventData.elementData.elementType) > -1) { + // Create query object from event data + const highlightQuery = { + entity_id: e.eventData.entityId, + struct_asym_id: e.eventData.elementData.pathData.struct_asym_id, + start_residue_number: e.eventData.residueNumber, + end_residue_number: e.eventData.residueNumber, + focus: true + }; + wrapperCtx.visual.select({ data: [highlightQuery] }); + } + else if (typeof e.eventData.elementData !== 'undefined' && elementTypeArrForRange.indexOf(e.eventData.elementData.elementType) > -1) { + // Create query object from event data + const highlightQuery = { + entity_id: e.eventData.entityId, + struct_asym_id: e.eventData.elementData.pathData.struct_asym_id, + start_residue_number: e.eventData.elementData.pathData.start.residue_number, + end_residue_number: e.eventData.elementData.pathData.end.residue_number + }; + // Call highlightAnnotation + wrapperCtx.visual.highlight({ data: [highlightQuery] }); + } + } + }); + document.addEventListener('PDB.seqViewer.mouseout', function (e) { + wrapperCtx.visual.clearHighlight(); + }); +} diff --git a/frontend/venome-molstar/lib/superposition-export.d.ts b/frontend/venome-molstar/lib/superposition-export.d.ts new file mode 100644 index 00000000..d8ae9240 --- /dev/null +++ b/frontend/venome-molstar/lib/superposition-export.d.ts @@ -0,0 +1,4 @@ +import { PluginContext } from "molstar/lib/mol-plugin/context"; +export declare function superpositionExportHierarchy(plugin: PluginContext, options?: { + format?: "cif" | "bcif"; +}): Promise; diff --git a/frontend/venome-molstar/lib/superposition-export.js b/frontend/venome-molstar/lib/superposition-export.js new file mode 100644 index 00000000..e708ee3e --- /dev/null +++ b/frontend/venome-molstar/lib/superposition-export.js @@ -0,0 +1,130 @@ +import { utf8ByteCount, utf8Write } from "molstar/lib/mol-io/common/utf8"; +import { to_mmCIF, Unit } from "molstar/lib/mol-model/structure"; +import { Task } from "molstar/lib/mol-task"; +import { getFormattedTime } from "molstar/lib/mol-util/date"; +import { download } from "molstar/lib/mol-util/download"; +import { zip } from "molstar/lib/mol-util/zip/zip"; +import { PluginCommands } from "molstar/lib/mol-plugin/commands"; +import { PluginCustomState } from "./plugin-custom-state"; +export async function superpositionExportHierarchy(plugin, options) { + try { + await plugin.runTask(_superpositionExportHierarchy(plugin, options), { + useOverlay: true, + }); + } + catch (e) { + console.error(e); + plugin.log.error(`Model export failed. See console for details.`); + } +} +function _superpositionExportHierarchy(plugin, options) { + return Task.create("Export", async (ctx) => { + await ctx.update({ + message: "Exporting...", + isIndeterminate: true, + canAbort: false, + }); + const format = options?.format ?? "cif"; + // const { structures } = plugin.managers.structure.hierarchy.current; + const customState = PluginCustomState(plugin); + if (!customState.initParams) + throw new Error("customState.initParams has not been initialized"); + if (!customState.superpositionState) + throw new Error("customState.superpositionState has not been initialized"); + const superpositionState = customState.superpositionState; + const segmentIndex = superpositionState.activeSegment - 1; + const files = []; + const entryMap = new Map(); + const structures = superpositionState.loadedStructs[segmentIndex].slice(); + if (!customState.initParams.moleculeId) + throw new Error("initParams.moleculeId is not defined"); + if (superpositionState.alphafold.ref) + structures.push(`AF-${customState.initParams.moleculeId}`); + for (const molId of structures) { + const modelRef = superpositionState.models[molId]; + if (!modelRef) + continue; + let isStrHidden = false; + const _s = plugin.managers.structure.hierarchy.current.refs.get(modelRef); + if (_s.cell.state.isHidden) + isStrHidden = true; + for (const strComp of _s.components) { + if (strComp.cell.state.isHidden) + isStrHidden = true; + } + if (isStrHidden) + continue; + const s = _s.transform?.cell.obj?.data ?? _s.cell.obj?.data; + if (!s) + continue; + if (s.models.length > 1) { + plugin.log.warn(`[Export] Skipping ${_s.cell.obj?.label}: Multimodel exports not supported.`); + continue; + } + if (s.units.some((u) => !Unit.isAtomic(u))) { + plugin.log.warn(`[Export] Skipping ${_s.cell.obj?.label}: Non-atomic model exports not supported.`); + continue; + } + const name = entryMap.has(s.model.entryId) + ? `${s.model.entryId}_${entryMap.get(s.model.entryId) + 1}.${format}` + : `${s.model.entryId}.${format}`; + entryMap.set(s.model.entryId, (entryMap.get(s.model.entryId) ?? 0) + 1); + await ctx.update({ + message: `Exporting ${s.model.entryId}...`, + isIndeterminate: true, + canAbort: false, + }); + if (s.elementCount > 100000) { + // Give UI chance to update, only needed for larger structures. + await new Promise((res) => setTimeout(res, 50)); + } + try { + files.push([ + name, + to_mmCIF(s.model.entryId, s, format === "bcif", { + copyAllCategories: true, + }), + ]); + } + catch (e) { + if (format === "cif" && s.elementCount > 2000000) { + plugin.log.warn(`[Export] The structure might be too big to be exported as Text CIF, consider using the BinaryCIF format instead.`); + } + throw e; + } + } + if (files.length === 0) { + PluginCommands.Toast.Show(plugin, { + title: "Export Models", + message: "No visible structure in the 3D view to export!", + key: "superposition-toast-1", + timeoutMs: 7000, + }); + return; + } + if (files.length === 1) { + download(new Blob([files[0][1]]), files[0][0]); + } + else if (files.length > 1) { + const zipData = {}; + for (const [fn, data] of files) { + if (data instanceof Uint8Array) { + zipData[fn] = data; + } + else { + const bytes = new Uint8Array(utf8ByteCount(data)); + utf8Write(bytes, 0, data); + zipData[fn] = bytes; + } + } + await ctx.update({ + message: `Compressing Data...`, + isIndeterminate: true, + canAbort: false, + }); + const buffer = await zip(ctx, zipData); + download(new Blob([new Uint8Array(buffer, 0, buffer.byteLength)]), `structures_${getFormattedTime()}.zip`); + } + plugin.log.info(`[Export] Done.`); + }); +} diff --git a/frontend/venome-molstar/lib/superposition-focus-representation.d.ts b/frontend/venome-molstar/lib/superposition-focus-representation.d.ts new file mode 100644 index 00000000..aa6d2e7a --- /dev/null +++ b/frontend/venome-molstar/lib/superposition-focus-representation.d.ts @@ -0,0 +1,16 @@ +import { PluginBehavior } from "molstar/lib/mol-plugin/behavior"; +import { ParamDefinition as PD } from "molstar/lib/mol-util/param-definition"; +import { PluginContext } from "molstar/lib/mol-plugin/context"; +declare const SuperpositionFocusRepresentationParams: (plugin: PluginContext) => { + expandRadius: PD.Numeric; + surroundingsParams: PD.Group>; +}; +type SuperpositionFocusRepresentationProps = PD.ValuesFor>; +export declare enum SuperpositionFocusRepresentationTags { + SurrSel = "superposition-focus-surr-sel", + SurrRepr = "superposition-focus-surr-repr" +} +export declare const SuperpositionFocusRepresentation: import("molstar/lib/mol-state/transformer").StateTransformer; +export {}; diff --git a/frontend/venome-molstar/lib/superposition-focus-representation.js b/frontend/venome-molstar/lib/superposition-focus-representation.js new file mode 100644 index 00000000..e4230bc2 --- /dev/null +++ b/frontend/venome-molstar/lib/superposition-focus-representation.js @@ -0,0 +1,148 @@ +import { StructureElement } from "molstar/lib/mol-model/structure"; +import { createStructureRepresentationParams } from "molstar/lib/mol-plugin-state/helpers/structure-representation-params"; +import { StateTransforms } from "molstar/lib/mol-plugin-state/transforms"; +import { PluginBehavior } from "molstar/lib/mol-plugin/behavior"; +import { MolScriptBuilder as MS } from "molstar/lib/mol-script/language/builder"; +import { StateSelection, StateTransform, } from "molstar/lib/mol-state"; +import { ParamDefinition as PD } from "molstar/lib/mol-util/param-definition"; +import { PluginCommands } from "molstar/lib/mol-plugin/commands"; +import { lociDetails } from "./loci-details"; +const SuperpositionFocusRepresentationParams = (plugin) => { + const reprParams = StateTransforms.Representation.StructureRepresentation3D + .definition.params(void 0, plugin); + return { + expandRadius: PD.Numeric(5, { min: 1, max: 10, step: 1 }), + surroundingsParams: PD.Group(reprParams, { + label: "Surroundings", + customDefault: createStructureRepresentationParams(plugin, void 0, { + type: "ball-and-stick", + size: "physical", + typeParams: { sizeFactor: 0.16 }, + sizeParams: { scale: 0.3 }, + }), + }), + }; +}; +export var SuperpositionFocusRepresentationTags; +(function (SuperpositionFocusRepresentationTags) { + SuperpositionFocusRepresentationTags["SurrSel"] = "superposition-focus-surr-sel"; + SuperpositionFocusRepresentationTags["SurrRepr"] = "superposition-focus-surr-repr"; +})(SuperpositionFocusRepresentationTags || (SuperpositionFocusRepresentationTags = {})); +const TagSet = new Set([ + SuperpositionFocusRepresentationTags.SurrSel, + SuperpositionFocusRepresentationTags.SurrRepr, +]); +class SuperpositionFocusRepresentationBehavior extends PluginBehavior.WithSubscribers { + get surrLabel() { + return `[Focus] Surroundings (${this.params.expandRadius} Ã…)`; + } + ensureShape(cell) { + const state = this.plugin.state.data, tree = state.tree; + const builder = state.build(); + const refs = StateSelection.findUniqueTagsInSubtree(tree, cell.transform.ref, TagSet); + // Selections + if (!refs[SuperpositionFocusRepresentationTags.SurrSel]) { + refs[SuperpositionFocusRepresentationTags.SurrSel] = builder + .to(cell) + .apply(StateTransforms.Model.StructureSelectionFromExpression, { + expression: MS.struct.generator.empty(), + label: this.surrLabel, + }, { tags: SuperpositionFocusRepresentationTags.SurrSel }).ref; + } + // Representations + if (!refs[SuperpositionFocusRepresentationTags.SurrRepr]) { + refs[SuperpositionFocusRepresentationTags.SurrRepr] = builder + .to(refs[SuperpositionFocusRepresentationTags.SurrSel]) + .apply(StateTransforms.Representation.StructureRepresentation3D, this.params.surroundingsParams, { tags: SuperpositionFocusRepresentationTags.SurrRepr }).ref; + } + return { state, builder, refs }; + } + clear(root) { + const state = this.plugin.state.data; + const surrs = state.select(StateSelection.Generators.byRef(root) + .subtree() + .withTag(SuperpositionFocusRepresentationTags.SurrSel)); + if (surrs.length === 0) + return; + const update = state.build(); + const expression = MS.struct.generator.empty(); + for (const s of surrs) { + update + .to(s) + .update(StateTransforms.Model.StructureSelectionFromExpression, (old) => ({ ...old, expression })); + } + return PluginCommands.State.Update(this.plugin, { + state, + tree: update, + options: { doNotLogTiming: true, doNotUpdateCurrent: true }, + }); + } + async focus(sourceLoci) { + const parent = this.plugin.helpers.substructureParent.get(sourceLoci.structure); + if (!parent || !parent.obj) + return; + const loci = StructureElement.Loci.remap(sourceLoci, parent.obj.data); + const residueLoci = StructureElement.Loci.extendToWholeResidues(loci); + const residueBundle = StructureElement.Bundle.fromLoci(residueLoci); + const target = StructureElement.Bundle.toExpression(residueBundle); + let surroundings = MS.struct.modifier.includeSurroundings({ + 0: target, + radius: this.params.expandRadius, + "as-whole-residues": true, + }); + const lociDeatils = lociDetails(sourceLoci); + if (!lociDeatils) { + surroundings = MS.struct.modifier.exceptBy({ + 0: surroundings, + by: target, + }); + } + const { state, builder, refs } = this.ensureShape(parent); + builder + .to(refs[SuperpositionFocusRepresentationTags.SurrSel]) + .update(StateTransforms.Model.StructureSelectionFromExpression, (old) => ({ + ...old, + expression: surroundings, + label: this.surrLabel, + })); + await PluginCommands.State.Update(this.plugin, { + state, + tree: builder, + options: { doNotLogTiming: true, doNotUpdateCurrent: true }, + }); + } + register(ref) { + this.subscribeObservable(this.plugin.managers.structure.focus.behaviors.current, (entry) => { + // if (entry) this.focus(entry.loci); + // else this.clear(StateTransform.RootRef); + this.clear(StateTransform.RootRef); + if (entry) + this.focus(entry.loci); + }); + } + async update(params) { + const old = this.params; + this.params = params; + const state = this.plugin.state.data; + const builder = state.build(); + const all = StateSelection.Generators.root.subtree(); + for (const repr of state.select(all.withTag(SuperpositionFocusRepresentationTags.SurrRepr))) { + builder.to(repr).update(this.params.surroundingsParams); + } + await PluginCommands.State.Update(this.plugin, { + state, + tree: builder, + options: { doNotLogTiming: true, doNotUpdateCurrent: true }, + }); + if (params.expandRadius !== old.expandRadius) + await this.clear(StateTransform.RootRef); + return true; + } +} +export const SuperpositionFocusRepresentation = PluginBehavior.create({ + name: "create-superposition-focus-representation", + display: { name: "Superposition Focus Representation" }, + category: "interaction", + ctor: SuperpositionFocusRepresentationBehavior, + params: (_, plugin) => SuperpositionFocusRepresentationParams(plugin), +}); diff --git a/frontend/venome-molstar/lib/superposition-sifts-mapping.d.ts b/frontend/venome-molstar/lib/superposition-sifts-mapping.d.ts new file mode 100644 index 00000000..4e166ec5 --- /dev/null +++ b/frontend/venome-molstar/lib/superposition-sifts-mapping.d.ts @@ -0,0 +1,22 @@ +import { MinimizeRmsd } from "molstar/lib/mol-math/linear-algebra/3d/minimize-rmsd"; +import { ElementIndex, ResidueIndex } from "molstar/lib/mol-model/structure/model/indexing"; +import { StructureElement } from "molstar/lib/mol-model/structure/structure/element"; +import { Structure } from "molstar/lib/mol-model/structure"; +import { Unit } from "molstar/lib/mol-model/structure/structure/unit"; +export interface AlignmentResultEntry { + transform: MinimizeRmsd.Result; + pivot: number; + other: number; +} +export interface AlignmentResult { + entries: AlignmentResultEntry[]; + zeroOverlapPairs: [number, number][]; + failedPairs: [number, number][]; +} +type IncludeResidueTest = (traceElementOrFirstAtom: StructureElement.Location, residueIndex: ResidueIndex, startIndex: ElementIndex, endIndex: ElementIndex) => boolean; +export declare function alignAndSuperposeWithSIFTSMapping(structures: Structure[], options?: { + traceOnly?: boolean; + includeResidueTest?: IncludeResidueTest; + applyTestIndex?: number[]; +}): AlignmentResult; +export {}; diff --git a/frontend/venome-molstar/lib/superposition-sifts-mapping.js b/frontend/venome-molstar/lib/superposition-sifts-mapping.js new file mode 100644 index 00000000..dfefc819 --- /dev/null +++ b/frontend/venome-molstar/lib/superposition-sifts-mapping.js @@ -0,0 +1,155 @@ +import { Segmentation } from "molstar/lib/mol-data/int"; +import { MinimizeRmsd } from "molstar/lib/mol-math/linear-algebra/3d/minimize-rmsd"; +import { SIFTSMapping } from "./sifts-mapping"; +import { StructureElement } from "molstar/lib/mol-model/structure/structure/element"; +export function alignAndSuperposeWithSIFTSMapping(structures, options) { + const indexMap = new Map(); + for (let i = 0; i < structures.length; i++) { + let includeResidueTest = options?.includeResidueTest ?? _includeAllResidues; + if (options?.applyTestIndex && !options.applyTestIndex.includes(i)) + includeResidueTest = _includeAllResidues; + buildIndex(structures[i], indexMap, i, options?.traceOnly ?? true, includeResidueTest); + } + const index = Array.from(indexMap.values()); + // TODO: support non-first structure pivots + const pairs = findPairs(structures.length, index); + const zeroOverlapPairs = []; + const failedPairs = []; + const entries = []; + for (const p of pairs) { + if (p.count === 0) { + zeroOverlapPairs.push([p.i, p.j]); + } + else { + const [a, b] = getPositionTables(index, p.i, p.j, p.count); + const transform = MinimizeRmsd.compute({ a, b }); + if (Number.isNaN(transform.rmsd)) { + failedPairs.push([p.i, p.j]); + } + else { + entries.push({ transform, pivot: p.i, other: p.j }); + } + } + } + return { entries, zeroOverlapPairs, failedPairs }; +} +function getPositionTables(index, pivot, other, N) { + const xs = MinimizeRmsd.Positions.empty(N); + const ys = MinimizeRmsd.Positions.empty(N); + let o = 0; + for (const { pivots } of index) { + const a = pivots[pivot]; + const b = pivots[other]; + if (!a || !b) + continue; + const l = Math.min(a[2] - a[1], b[2] - b[1]); + // TODO: check if residue types match? + for (let i = 0; i < l; i++) { + let eI = (a[1] + i); + xs.x[o] = a[0].conformation.x(eI); + xs.y[o] = a[0].conformation.y(eI); + xs.z[o] = a[0].conformation.z(eI); + eI = (b[1] + i); + ys.x[o] = b[0].conformation.x(eI); + ys.y[o] = b[0].conformation.y(eI); + ys.z[o] = b[0].conformation.z(eI); + o++; + } + } + return [xs, ys]; +} +function findPairs(N, index) { + const pairwiseCounts = []; + for (let i = 0; i < N; i++) { + pairwiseCounts[i] = []; + for (let j = 0; j < N; j++) + pairwiseCounts[i][j] = 0; + } + for (const { pivots } of index) { + for (let i = 0; i < N; i++) { + if (!pivots[i]) + continue; + const lI = pivots[i][2] - pivots[i][1]; + for (let j = i + 1; j < N; j++) { + if (!pivots[j]) + continue; + const lJ = pivots[j][2] - pivots[j][1]; + pairwiseCounts[i][j] = pairwiseCounts[i][j] + Math.min(lI, lJ); + } + } + } + const ret = []; + for (let j = 1; j < N; j++) { + ret[j - 1] = { i: 0, j, count: pairwiseCounts[0][j] }; + } + // TODO: support non-first structure pivots + // for (let i = 0; i < N - 1; i++) { + // let max = 0, maxJ = i; + // for (let j = i + 1; j < N; j++) { + // if (pairwiseCounts[i][j] > max) { + // maxJ = j; + // max = pairwiseCounts[i][j]; + // } + // } + // ret[i] = { i, j: maxJ, count: max }; + // } + return ret; +} +function _includeAllResidues() { + return true; +} +function buildIndex(structure, index, sI, traceOnly, includeTest) { + const loc = StructureElement.Location.create(structure); + for (const unit of structure.units) { + if (unit.kind !== 0 /* Unit.Kind.Atomic */) + continue; + const { elements, model } = unit; + loc.unit = unit; + const map = SIFTSMapping.Provider.get(model).value; + if (!map) + return; + const { dbName, accession, num } = map; + const chainsIt = Segmentation.transientSegments(unit.model.atomicHierarchy.chainAtomSegments, elements); + const residuesIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, elements); + const traceElementIndex = unit.model.atomicHierarchy.derived.residue.traceElementIndex; + while (chainsIt.hasNext) { + const chainSegment = chainsIt.move(); + residuesIt.setSegment(chainSegment); + while (residuesIt.hasNext) { + const residueSegment = residuesIt.move(); + const rI = residueSegment.index; + if (!dbName[rI]) + continue; + const traceElement = traceElementIndex[rI]; + let start, end; + if (traceOnly) { + start = traceElement; + if (start === -1) + continue; + end = (start + 1); + } + else { + start = elements[residueSegment.start]; + end = (elements[residueSegment.end - 1] + + 1); + } + loc.element = (traceElement >= 0 ? traceElement : start); + if (!includeTest(loc, rI, start, end)) + continue; + const key = `${dbName[rI]}-${accession[rI].split("-")[0]}-${num[rI]}`; + if (!index.has(key)) { + index.set(key, { + key, + pivots: { [sI]: [unit, start, end] }, + }); + } + else { + const entry = index.get(key); + if (!entry.pivots[sI]) { + entry.pivots[sI] = [unit, start, end]; + } + } + } + } + } +} diff --git a/frontend/venome-molstar/lib/superposition.d.ts b/frontend/venome-molstar/lib/superposition.d.ts new file mode 100644 index 00000000..7b100220 --- /dev/null +++ b/frontend/venome-molstar/lib/superposition.d.ts @@ -0,0 +1,7 @@ +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import { Subject } from "rxjs"; +import { ClusterMember } from "./plugin-custom-state"; +export declare function initSuperposition(plugin: PluginContext, completeSubject?: Subject): Promise; +export declare function loadAfStructure(plugin: PluginContext): Promise; +export declare function superposeAf(plugin: PluginContext, traceOnly: boolean, segmentIndex?: number): Promise; +export declare function renderSuperposition(plugin: PluginContext, segmentIndex: number, entryList: ClusterMember[]): Promise; diff --git a/frontend/venome-molstar/lib/superposition.js b/frontend/venome-molstar/lib/superposition.js new file mode 100644 index 00000000..78d21000 --- /dev/null +++ b/frontend/venome-molstar/lib/superposition.js @@ -0,0 +1,727 @@ +import { Mat4 } from "molstar/lib/mol-math/linear-algebra"; +import { StructureProperties } from "molstar/lib/mol-model/structure"; +import { StateTransforms } from "molstar/lib/mol-plugin-state/transforms"; +import { MolScriptBuilder as MS } from "molstar/lib/mol-script/language/builder"; +import { Script } from "molstar/lib/mol-script/script"; +import { StateObjectRef, } from "molstar/lib/mol-state"; +import { Task } from "molstar/lib/mol-task"; +import { Asset } from "molstar/lib/mol-util/assets"; +import { Color } from "molstar/lib/mol-util/color/color"; +import { ColorLists } from "molstar/lib/mol-util/color/lists"; +import { applyAFTransparency } from "./alphafold-transparency"; +import { ModelInfo, getStructureUrl } from "./helpers"; +import { PluginCustomState } from "./plugin-custom-state"; +import { alignAndSuperposeWithSIFTSMapping } from "./superposition-sifts-mapping"; +function getRandomColor(plugin, segmentIndex) { + const clList = ColorLists; + const spState = PluginCustomState(plugin).superpositionState; + if (!spState) + throw new Error("customState.superpositionState has not been initialized"); + let palleteIndex = spState.colorState[segmentIndex].palleteIndex; + let colorIndex = spState.colorState[segmentIndex].colorIndex; + if (clList[spState.colorPalette[palleteIndex]].list[colorIndex + 1]) { + colorIndex += 1; + } + else { + colorIndex = 0; + palleteIndex = spState.colorPalette[palleteIndex + 1] + ? palleteIndex + 1 + : 0; + } + const palleteName = spState.colorPalette[palleteIndex]; + spState.colorState[segmentIndex].palleteIndex = palleteIndex; + spState.colorState[segmentIndex].colorIndex = colorIndex; + return clList[palleteName].list[colorIndex]; +} +export async function initSuperposition(plugin, completeSubject) { + let success = false; + try { + await plugin.clear(); + const customState = PluginCustomState(plugin); + customState.superpositionState = { + models: {}, + entries: {}, + refMaps: {}, + segmentData: void 0, + matrixData: {}, + activeSegment: 0, + loadedStructs: [], + visibleRefs: [], + invalidStruct: [], + noMatrixStruct: [], + hets: {}, + colorPalette: [ + "dark-2", + "red-yellow-green", + "paired", + "set-1", + "accent", + "set-2", + "rainbow", + ], + colorState: [], + alphafold: { + apiData: { + cif: "", + pae: "", + length: 0, + }, + length: 0, + ref: "", + traceOnly: true, + visibility: [], + transforms: [], + rmsds: [], + coordinateSystems: [], + }, + }; + // Get segment and cluster information for the given uniprot accession + await getSegmentData(plugin); + const segmentData = customState.superpositionState.segmentData; + if (!segmentData) + return; + // Load Matrix Data + await getMatrixData(plugin); + if (!customState.superpositionState.segmentData) + return; + if (!customState.initParams.moleculeId) + throw new Error("initParams.moleculeId is not defined"); + const afStrUrls = await getAfUrl(plugin, customState.initParams.moleculeId); + if (afStrUrls) + customState.superpositionState.alphafold.apiData = afStrUrls; + segmentData.forEach(() => { + customState.superpositionState.loadedStructs.push([]); + customState.superpositionState.visibleRefs.push([]); + customState.superpositionState.colorState.push({ + palleteIndex: 0, + colorIndex: -1, + }); + }); + // Set segment and cluster details from superPositionParams + const superpositionParams = customState.initParams.superpositionParams; + const segmentIndex = superpositionParams?.segment + ? superpositionParams.segment - 1 + : 0; + customState.superpositionState.activeSegment = segmentIndex + 1; + const clusterIndexs = superpositionParams?.cluster + ? superpositionParams.cluster + : void 0; + // Emit segment API data load event + customState.events?.superpositionInit.next(true); + // Get entry list to load matrix data + let entryList = []; + const clusters = segmentData[segmentIndex].clusters; + clusters.forEach((cluster, clusterIndex) => { + // Validate for cluster index if provided in superPositionParams + if (clusterIndexs && clusterIndexs.indexOf(clusterIndex) === -1) + return; + // Add respresentative structure to the list + if (superpositionParams?.superposeAll) { + entryList = entryList.concat(cluster); + } + else { + entryList.push(cluster[0]); + } + }); + await renderSuperposition(plugin, segmentIndex, entryList); + success = true; + } + finally { + completeSubject?.next(success); + } +} +function createCarbVisLabel(carbLigNamesAndCount) { + const compList = []; + for (const carbCompId in carbLigNamesAndCount) { + compList.push(`${carbCompId} (${carbLigNamesAndCount[carbCompId]})`); + } + return compList.join(", "); +} +async function getAfUrl(plugin, accession) { + let apiResponse; + let apiData; + await plugin.runTask(Task.create("Get AlphaFold URL", async (ctx) => { + try { + apiResponse = await plugin + .fetch({ + url: `https://alphafold.ebi.ac.uk/api/prediction/${accession}`, + type: "json", + }) + .runInContext(ctx); + if (apiResponse && apiResponse?.[0].bcifUrl) { + apiData = { + cif: apiResponse?.[0].cifUrl, + pae: apiResponse?.[0].paeImageUrl, + length: apiResponse?.[0].uniprotEnd, + }; + } + } + catch (e) { + // console.warn(e); + } + })); + return apiData; +} +export async function loadAfStructure(plugin) { + const customState = PluginCustomState(plugin); + if (!customState.superpositionState) + throw new Error("customState.superpositionState has not been initialized"); + const { structure } = await loadStructure(plugin, customState.superpositionState.alphafold.apiData.cif, "mmcif", false); + const strInstance = structure; + if (!strInstance) + return false; + // Store Refs in state + const spState = customState.superpositionState; + spState.alphafold.ref = strInstance?.ref; + if (!customState.initParams?.moleculeId) + throw new Error("initParams.moleculeId is not defined"); + spState.models[`AF-${customState.initParams.moleculeId}`] = + strInstance?.ref; + const chainSel = await plugin.builders.structure.tryCreateComponentStatic(strInstance, "polymer", { + label: `AlphaFold Structure`, + tags: [`alphafold-chain`, `superposition-sel`], + }); + if (chainSel) { + await plugin.builders.structure.representation.addRepresentation(chainSel, { + type: "putty", + color: "plddt-confidence", + size: "uniform", + sizeParams: { value: 1.5 }, + }, { tag: `af-superposition-visual` }); + return strInstance?.ref; + } + return false; +} +export async function superposeAf(plugin, traceOnly, segmentIndex) { + const customState = PluginCustomState(plugin); + const spState = customState.superpositionState; + if (!spState?.segmentData) + return; + // Load AF structure + const afStrRef = spState.alphafold.ref || (await loadAfStructure(plugin)); + if (!afStrRef) + return; + const afStr = plugin.managers.structure.hierarchy.current.refs.get(afStrRef); + const segmentNum = segmentIndex ? segmentIndex : spState.activeSegment - 1; + if (!spState.alphafold.transforms[segmentNum]) { + // Create representative list + const mappingResult = []; + const coordinateSystems = []; + const failedPairsResult = []; + const zeroOverlapPairsResult = []; + let minRmsd = 0; + let minIndex = 0; + const rmsdList = []; + const segmentClusters = spState.segmentData[segmentNum].clusters; + segmentClusters.forEach((cluster) => { + const modelRef = spState.models[`${cluster[0].pdb_id}_${cluster[0].struct_asym_id}`]; + if (modelRef) { + const structHierarchy = plugin.managers.structure.hierarchy.current.refs.get(modelRef); + if (structHierarchy) { + const input = [structHierarchy.components[0], afStr]; + const structures = input.map((s) => s.cell.obj?.data); + let { entries, failedPairs, zeroOverlapPairs } = alignAndSuperposeWithSIFTSMapping(structures, { + traceOnly, + includeResidueTest: (loc) => StructureProperties.atom.B_iso_or_equiv(loc) > + 70, + applyTestIndex: [1], + }); + if (entries.length === 0 || + (entries && + entries[0] && + entries[0].transform.rmsd.toFixed(1) === "0.0")) { + const alignWithoutPlddt = alignAndSuperposeWithSIFTSMapping(structures, { + traceOnly, + }); + entries = alignWithoutPlddt.entries; + } + if (entries && entries[0]) { + mappingResult.push(entries[0]); + coordinateSystems.push(input[0]?.transform?.cell.obj?.data.coordinateSystem); + const totalMappings = mappingResult.length; + if (totalMappings === 1 || + entries[0].transform.rmsd < minRmsd) { + minRmsd = entries[0].transform.rmsd; + minIndex = + totalMappings === 1 + ? 0 + : mappingResult.length - 1; + } + rmsdList.push(`${cluster[0].pdb_id} chain ${cluster[0].struct_asym_id}:${entries[0].transform.rmsd.toFixed(2)}`); + } + else { + if (failedPairs.length > 0) + failedPairsResult.push(failedPairs); + if (zeroOverlapPairs.length > 0) + zeroOverlapPairsResult.push(zeroOverlapPairs); + // rmsdList.push(`${cluster[0].pdb_id} ${cluster[0].struct_asym_id}:-`) + } + } + } + }); + // console.log(failedPairsResult); + // console.log(zeroOverlapPairsResult); + if (mappingResult.length > 0) { + spState.alphafold.visibility[segmentNum] = true; + spState.alphafold.transforms[segmentNum] = + mappingResult[minIndex].transform.bTransform; + spState.alphafold.coordinateSystems[segmentNum] = + coordinateSystems[minIndex]; + spState.alphafold.rmsds[segmentNum] = rmsdList.sort((a, b) => parseFloat(a.split(":")[1]) - parseFloat(b.split(":")[1])); + } + } + await afTransform(plugin, afStr.cell, spState.alphafold.transforms[segmentNum], spState.alphafold.coordinateSystems[segmentNum]); + applyAFTransparency(plugin, afStr, 0.8, 70); + return true; +} +export async function renderSuperposition(plugin, segmentIndex, entryList) { + const customState = PluginCustomState(plugin); + const superpositionParams = customState.initParams.superpositionParams; + let busyFlagOn = false; + if (entryList.length > 1) { + busyFlagOn = true; + customState.events?.isBusy.next(true); + } + // Load Coordinates and render respresentations + return plugin.dataTransaction(async () => { + if (!customState.initParams) + throw new Error("customState.initParams has not been initialized"); + if (!customState.superpositionState) + throw new Error("customState.superpositionState has not been initialized"); + const spState = customState.superpositionState; + for await (const s of entryList) { + // validate matrix availability + if (!spState.matrixData[`${s.pdb_id}_${s.auth_asym_id}`]) { + spState.noMatrixStruct.push(`${s.pdb_id}_${s.struct_asym_id}`); + spState.invalidStruct.push(`${s.pdb_id}_${s.struct_asym_id}`); + continue; + } + spState.loadedStructs[segmentIndex].push(`${s.pdb_id}_${s.struct_asym_id}`); + // Set Coordinate server url + const request = superpositionParams && superpositionParams.ligandView + ? { pdbId: s.pdb_id, queryType: "full" } + : { + pdbId: s.pdb_id, + queryType: "atoms", + queryParams: { auth_asym_id: s.auth_asym_id }, + }; + const strUrl = getStructureUrl(customState.initParams, request); + // Load Data + let strInstance; + let modelRef; + let clearOnFail = true; + if (superpositionParams && + superpositionParams.ligandView && + spState.entries[s.pdb_id]) { + const polymerInstance = plugin.state.data.select(spState.entries[s.pdb_id])[0]; + modelRef = polymerInstance.transform.parent; + const modelInstance = plugin.state.data.select(modelRef)[0]; + strInstance = await plugin.builders.structure.createStructure(modelInstance, { name: "model", params: {} }); + clearOnFail = false; + } + else { + const isBinary = customState.initParams.encoding === "bcif" ? true : false; + const { model, structure } = await loadStructure(plugin, strUrl, "mmcif", isBinary); + strInstance = structure; + modelRef = model.ref; + } + if (!strInstance) + continue; + // Store Refs in state + if (!spState.models[`${s.pdb_id}_${s.struct_asym_id}`]) + spState.models[`${s.pdb_id}_${s.struct_asym_id}`] = + strInstance?.ref; + if (superpositionParams && + superpositionParams.ligandView && + !spState.entries[s.pdb_id]) + spState.entries[s.pdb_id] = strInstance?.ref; + // Apply tranform matrix + const matrix = Mat4.ofRows(customState.superpositionState.matrixData[`${s.pdb_id}_${s.auth_asym_id}`].matrix); + await transform(plugin, strInstance, matrix); + // Create representations + let chainSel; + if (superpositionParams && + superpositionParams.ligandView && + s.is_representative) { + const uniformColor1 = getRandomColor(plugin, segmentIndex); // random color + chainSel = + await plugin.builders.structure.tryCreateComponentFromExpression(strInstance, chainSelection(s.struct_asym_id), `Chain-${segmentIndex}`, { label: `Chain`, tags: [`superposition-sel`] }); + if (chainSel) { + await plugin.builders.structure.representation.addRepresentation(chainSel, { + type: "putty", + color: "uniform", + colorParams: { value: uniformColor1 }, + size: "uniform", + }, { tag: `superposition-visual` }); + spState.refMaps[chainSel.ref] = `${s.pdb_id}_${s.struct_asym_id}`; + } + } + else if (superpositionParams && + superpositionParams.ligandView && + !s.is_representative) { + // Do nothing + } + else { + const uniformColor2 = getRandomColor(plugin, segmentIndex); // random color + chainSel = + await plugin.builders.structure.tryCreateComponentStatic(strInstance, "polymer", { + label: `Chain`, + tags: [ + `Chain-${segmentIndex}`, + `superposition-sel`, + ], + }); + if (chainSel) { + await plugin.builders.structure.representation.addRepresentation(chainSel, { + type: "putty", + color: "uniform", + colorParams: { value: uniformColor2 }, + size: "uniform", + }, { tag: `superposition-visual` }); + spState.refMaps[chainSel.ref] = `${s.pdb_id}_${s.struct_asym_id}`; + } + // // const addTooltipUpdate = plugin.state.behaviors.build().to(BestDatabaseSequenceMapping.id).update(BestDatabaseSequenceMapping, (old: any) => { old.showTooltip = true; }); + // // await plugin.runTask(plugin.state.behaviors.updateTree(addTooltipUpdate)); + // BestDatabaseSequenceMapping + // console.log(plugin.state.data.select(modelRef)[0]) + } + let invalidStruct = chainSel ? false : true; + if (superpositionParams && superpositionParams.ligandView) { + const state = plugin.state.data; + const hetInfo = await getLigandNamesFromModelData(plugin, state, modelRef); + const hets = hetInfo ? hetInfo.hetNames : []; + // const interactingHets = []; + if (hets && hets.length > 0) { + for await (const het of hets) { + const ligand = MS.struct.generator.atomGroups({ + "chain-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_asym_id(), + s.auth_asym_id, + ]), + "residue-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.label_comp_id(), + het, + ]), + "group-by": MS.core.str.concat([ + MS.struct.atomProperty.core.operatorName(), + MS.struct.atomProperty.macromolecular.residueKey(), + ]), + }); + const labelTagParams = { + label: `${het}`, + tags: [`superposition-ligand-sel`], + }; + let hetColor = Color.fromRgb(253, 3, 253); + if (superpositionParams?.ligandColor) { + const { r, g, b } = superpositionParams.ligandColor; + hetColor = Color.fromRgb(r, g, b); + } + const ligandExp = await plugin.builders.structure.tryCreateComponentFromExpression(strInstance, ligand, `${het}-${segmentIndex}`, labelTagParams); + if (ligandExp) { + await plugin.builders.structure.representation.addRepresentation(ligandExp, { + type: "ball-and-stick", + color: "uniform", + colorParams: { value: hetColor }, + }, { tag: `superposition-ligand-visual` }); + spState.refMaps[ligandExp.ref] = `${s.pdb_id}_${s.struct_asym_id}`; + invalidStruct = false; + // interactingHets.push(het); + } + } + } + const carbEntityCount = hetInfo ? hetInfo.carbEntityCount : 0; + if (carbEntityCount > 0) { + // Get Carbohydrate Polymers details from PDBe API + const allCarbPolymers = await getCarbPolymerDetailsFromApi(plugin, s.pdb_id); + // Polymer chain + surroundings query + const polymerChainWithSurroundings = MS.struct.modifier.includeSurroundings({ + 0: MS.struct.generator.atomGroups({ + "entity-test": MS.core.rel.eq([ + MS.ammp("entityType"), + "polymer", + ]), + "chain-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_asym_id(), + s.auth_asym_id, + ]), + "group-by": MS.core.str.concat([ + MS.struct.atomProperty.core.operatorName(), + MS.struct.atomProperty.macromolecular.residueKey(), + ]), + }), + radius: 5, + "as-whole-residues": true, + }); + let i = 0; + for (const carbEntityChainId of allCarbPolymers.branchedChains) { + const carbEntityChain = MS.struct.generator.atomGroups({ + "entity-test": MS.core.rel.eq([ + MS.ammp("entityType"), + "branched", + ]), + "chain-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_asym_id(), + carbEntityChainId, + ]), + "group-by": MS.core.str.concat([ + MS.struct.atomProperty.core.operatorName(), + MS.struct.atomProperty.macromolecular.residueKey(), + ]), + }); + const carbEntityChainInVicinity = MS.struct.filter.intersectedBy({ + 0: polymerChainWithSurroundings, + by: carbEntityChain, + }); + const data = plugin.state.data.select(strInstance.ref)[0].obj.data; + const carbChainSel = Script.getStructureSelection(carbEntityChainInVicinity, data); + if (carbChainSel && carbChainSel.kind === "sequence") { + // console.log(carbEntityChainId + ' chain present in 5 A radius'); + const carbLigands = []; + const carbLigNamesAndCount = {}; + const carbLigList = []; + for (const carbLigs of allCarbPolymers + .branchedLigands[i]) { + const ligResDetails = carbLigs.split("-"); + carbLigands.push(MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_seq_id(), + +ligResDetails[1], + ])); + if (carbLigNamesAndCount[ligResDetails[0]]) { + carbLigNamesAndCount[ligResDetails[0]]++; + } + else { + carbLigNamesAndCount[ligResDetails[0]] = 1; + } + carbLigList.push(ligResDetails[0]); + } + const carbVisLabel = createCarbVisLabel(carbLigNamesAndCount); + const branchedEntity = MS.struct.generator.atomGroups({ + "entity-test": MS.core.rel.eq([ + MS.ammp("entityType"), + "branched", + ]), + "group-by": MS.core.str.concat([ + MS.struct.atomProperty.core.operatorName(), + MS.struct.atomProperty.macromolecular.residueKey(), + ]), + "chain-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_asym_id(), + carbEntityChainId, + ]), + "residue-test": MS.core.logic.or(carbLigands), + }); + const labelTagParams = { + label: `${carbVisLabel}`, + tags: [`superposition-carb-sel`], + }; + const ligandExp = await plugin.builders.structure.tryCreateComponentFromExpression(strInstance, branchedEntity, `${carbLigList.join("-")}-${segmentIndex}`, labelTagParams); + if (ligandExp) { + await plugin.builders.structure.representation.addRepresentation(ligandExp, { type: "carbohydrate" }, { tag: `superposition-carb-visual` }); + spState.refMaps[ligandExp.ref] = `${s.pdb_id}_${s.struct_asym_id}`; + invalidStruct = false; + } + } + i++; + } + } + if (invalidStruct) { + spState.invalidStruct.push(`${s.pdb_id}_${s.struct_asym_id}`); + const loadedStructIndex = spState.loadedStructs[segmentIndex].indexOf(`${s.pdb_id}_${s.struct_asym_id}`); + if (loadedStructIndex > -1) + spState.loadedStructs[segmentIndex].splice(loadedStructIndex, 1); + // remove downloaded data + if (clearOnFail) { + // const m = plugin.state.data.select(modelRef)[0]; + // const t = plugin.state.data.select(m.transform.parent)[0]; + // const d = plugin.state.data.select(t.transform.parent)[0]; + // PluginCommands.State.RemoveObject(plugin, { state: d.parent!, ref: d.transform.parent, removeParentGhosts: true }); + } + } + else { + // if(interactingHets.length > 0) spState.hets[`${s.pdb_id}_${s.struct_asym_id}`] = interactingHets; + } + } + } + if (busyFlagOn) { + busyFlagOn = false; + customState.events?.isBusy.next(false); + } + }); +} +async function getLigandNamesFromModelData(plugin, state, modelRef) { + const cell = state.select(modelRef)[0]; + if (!cell || !cell.obj) + return void 0; + const model = cell.obj.data; + if (!model) + return; + const structures = []; + for (const s of plugin.managers.structure.hierarchy.selection.structures) { + const structure = s.cell.obj?.data; + if (structure) + structures.push(structure); + } + const info = await ModelInfo.get(model, structures); + return info; +} +async function loadStructure(plugin, url, format, isBinary) { + try { + const data = await plugin.builders.data.download({ + url: Asset.Url(url), + isBinary: isBinary, + }); + const trajectory = await plugin.builders.structure.parseTrajectory(data, format); + const model = await plugin.builders.structure.createModel(trajectory); + const modelProperties = await plugin.builders.structure.insertModelProperties(model); + const structure = await plugin.builders.structure.createStructure(modelProperties || model, { name: "model", params: {} }); + await plugin.builders.structure.insertStructureProperties(structure); + return { data, trajectory, model, structure }; + } + catch (e) { + return { structure: void 0 }; + } +} +function chainSelection(struct_asym_id) { + return MS.struct.generator.atomGroups({ + "chain-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.label_asym_id(), + struct_asym_id, + ]), + }); +} +function transform(plugin, s, matrix) { + const b = plugin.state.data + .build() + .to(s) + .insert(StateTransforms.Model.TransformStructureConformation, { + transform: { + name: "matrix", + params: { data: matrix, transpose: false }, + }, + }); + return plugin.runTask(plugin.state.data.updateTree(b)); +} +async function afTransform(plugin, s, matrix, coordinateSystem) { + const r = StateObjectRef.resolveAndCheck(plugin.state.data, s); + if (!r) + return; + const o = plugin.state.data.selectQ((q) => q + .byRef(r.transform.ref) + .subtree() + .withTransformer(StateTransforms.Model.TransformStructureConformation))[0]; + const transform = coordinateSystem && !Mat4.isIdentity(coordinateSystem.matrix) + ? Mat4.mul(Mat4(), coordinateSystem.matrix, matrix) + : matrix; + const params = { + transform: { + name: "matrix", + params: { data: transform, transpose: false }, + }, + }; + const b = o + ? plugin.state.data.build().to(o).update(params) + : plugin.state.data + .build() + .to(s) + .insert(StateTransforms.Model.TransformStructureConformation, params, { tags: "SuperpositionTransform" }); + await plugin.runTask(plugin.state.data.updateTree(b)); +} +async function getMatrixData(plugin) { + const customState = PluginCustomState(plugin); + if (!customState.initParams) + throw new Error("customState.initParams has not been initialized"); + if (!customState.superpositionState) + throw new Error("customState.superpositionState has not been initialized"); + const matrixAccession = customState.initParams.superpositionParams?.matrixAccession ?? + customState.initParams.moleculeId; + const clusterRecUrlStr = `${customState.initParams.pdbeUrl}static/superpose/matrices/${matrixAccession}`; + const assetManager = plugin.managers.asset; + const clusterRecUrl = Asset.getUrlAsset(assetManager, clusterRecUrlStr); + try { + const clusterRecData = await plugin.runTask(assetManager.resolve(clusterRecUrl, "json", false)); + if (clusterRecData && clusterRecData.data) { + customState.superpositionState.matrixData = clusterRecData.data; + } + } + catch (e) { + customState.superpositionError = `Matrix data not available for ${matrixAccession}`; + customState.events?.superpositionInit.next(true); // Emit segment API data load event + } +} +async function getSegmentData(plugin) { + const customState = PluginCustomState(plugin); + if (!customState.initParams) + throw new Error("customState.initParams has not been initialized"); + if (!customState.superpositionState) + throw new Error("customState.superpositionState has not been initialized"); + // Get Data + const segmentsUrl = `${customState.initParams.pdbeUrl}graph-api/uniprot/superposition/${customState.initParams.moleculeId}`; + const assetManager = plugin.managers.asset; + const url = Asset.getUrlAsset(assetManager, segmentsUrl); + try { + const result = await plugin.runTask(assetManager.resolve(url, "json", false)); + if (result?.data) { + customState.superpositionState.segmentData = + result.data[customState.initParams.moleculeId]; + } + } + catch (e) { + customState.superpositionError = `Superposition data not available for ${customState.initParams.moleculeId}`; + customState.events?.superpositionInit.next(true); // Emit segment API data load event + } +} +function getChainLigands(carbEntity) { + const ligandChain = []; + const ligandLabels = []; + const ligands = []; + const labelValueArr = []; + let ligNameStr = ""; + for (const chemComp of carbEntity.chem_comp_list) { + labelValueArr.push(`${chemComp.chem_comp_id} (${chemComp.count})`); + } + ligNameStr = labelValueArr.join(", "); + for (const chain of carbEntity.chains) { + ligandChain.push(chain.chain_id); + ligandLabels.push(ligNameStr); + const chainLigands = []; + for (const residue of chain.residues) { + chainLigands.push(residue.chem_comp_id + "-" + residue.residue_number); + } + ligands.push(chainLigands); + } + return { + ligands, + ligandChain, + ligandLabels, + }; +} +async function getCarbPolymerDetailsFromApi(plugin, pdb_id) { + const customState = PluginCustomState(plugin); + if (!customState.initParams) + throw new Error("customState.initParams has not been initialized"); + // Get Data + const apiUrl = `${customState.initParams.pdbeUrl}api/pdb/entry/carbohydrate_polymer/${pdb_id}`; + const assetManager = plugin.managers.asset; + const url = Asset.getUrlAsset(assetManager, apiUrl); + let branchedLigands = []; + let branchedChains = []; + let branchedlabels = []; + try { + const result = await plugin.runTask(assetManager.resolve(url, "json", false)); + if (result && result.data) { + const carbEntities = result.data[pdb_id]; + for (const carbEntity of carbEntities) { + const carbLigData = getChainLigands(carbEntity); + branchedLigands = branchedLigands.concat(carbLigData.ligands); + branchedChains = branchedChains.concat(carbLigData.ligandChain); + branchedlabels = branchedlabels.concat(carbLigData.ligandLabels); + } + } + } + catch (e) { } + return { + branchedChains, + branchedLigands, + branchedlabels, + }; +} diff --git a/frontend/venome-molstar/lib/ui/alphafold-superposition.d.ts b/frontend/venome-molstar/lib/ui/alphafold-superposition.d.ts new file mode 100644 index 00000000..b5e60111 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/alphafold-superposition.d.ts @@ -0,0 +1,56 @@ +import { CollapsableControls, PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import { PluginCustomState } from '../plugin-custom-state'; +export declare function InfoIconSvg(): import("react/jsx-runtime").JSX.Element; +export declare class AlphafoldPaeControls extends CollapsableControls { + private axisBoxRef; + defaultState(): { + isCollapsed: boolean; + header: string; + brand: { + accent: "gray"; + svg: typeof import("molstar/lib/mol-plugin-ui/controls/icons").FlipToFrontSvg; + }; + isHidden: boolean; + }; + constructor(props: any, context: any); + componentDidMount(): void; + formatTicks(d: any): any; + renderControls(): import("react/jsx-runtime").JSX.Element | null; +} +export declare class AlphafoldSuperpositionControls extends CollapsableControls { + defaultState(): { + isCollapsed: boolean; + header: string; + brand: { + accent: "gray"; + svg: typeof import("molstar/lib/mol-plugin-ui/controls/icons").FlipToFrontSvg; + }; + isHidden: boolean; + }; + componentDidMount(): void; + rmsdTable(): import("react/jsx-runtime").JSX.Element; + renderControls(): import("react/jsx-runtime").JSX.Element; +} +export declare const AlphafoldSuperpositionParams: { + traceOnly: PD.BooleanParam; +}; +export type AlphafoldSuperpositionOptions = PD.ValuesFor; +type AfSuperpositionControlsState = { + isBusy: boolean; + action?: 'byChains' | 'byAtoms' | 'options'; + canUseDb?: boolean; + options: AlphafoldSuperpositionOptions; +}; +export declare class AfSuperpositionControls extends PurePluginUIComponent<{}, AfSuperpositionControlsState> { + state: AfSuperpositionControlsState; + componentDidMount(): void; + get selection(): import("molstar/lib/mol-plugin-state/manager/structure/selection").StructureSelectionManager; + get customState(): PluginCustomState; + superposeDb: () => Promise; + toggleOptions: () => void; + superposeByDbMapping(): import("react/jsx-runtime").JSX.Element; + private setOptions; + render(): import("react/jsx-runtime").JSX.Element; +} +export {}; diff --git a/frontend/venome-molstar/lib/ui/alphafold-superposition.js b/frontend/venome-molstar/lib/ui/alphafold-superposition.js new file mode 100644 index 00000000..2a78b283 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/alphafold-superposition.js @@ -0,0 +1,149 @@ +import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; +import React from 'react'; +import { CollapsableControls, PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { TuneSvg, SuperposeChainsSvg, SuperpositionSvg, Icon } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { Button, ToggleButton } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { superposeAf } from '../superposition'; +import { scaleLinear as d3ScaleLinear } from 'd3-scale'; +import { axisBottom as d3AxisBotom, axisLeft as d3AxisLeft } from 'd3-axis'; +import { select as d3Select } from 'd3-selection'; +import { PluginCustomState } from '../plugin-custom-state'; +const _InfoIcon = _jsx("svg", { width: '24px', height: '24px', viewBox: '0 0 24 24', strokeWidth: '0.1px', children: _jsx("path", { fill: "currentColor", d: "M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z" }) }); +export function InfoIconSvg() { return _InfoIcon; } +export class AlphafoldPaeControls extends CollapsableControls { + axisBoxRef; + defaultState() { + return { + isCollapsed: false, + header: 'AlphaFold PAE', + brand: { accent: 'gray', svg: SuperpositionSvg }, + isHidden: true + }; + } + constructor(props, context) { + super(props, context); + this.axisBoxRef = React.createRef(); + } + componentDidMount() { + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, sel => { + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (superpositionState && superpositionState.alphafold.ref && superpositionState.alphafold.apiData.pae && superpositionState.alphafold.apiData.pae !== '' && superpositionState.alphafold.apiData.pae !== '') { + this.setState({ isHidden: false }); + const domainMax = superpositionState.alphafold.apiData.length; + const x = d3ScaleLinear().domain([0, domainMax]).range([0, 200]); + const xAxis = d3AxisBotom(x).ticks(6).tickFormat(this.formatTicks).tickSizeOuter(0); + const yAxis = d3AxisLeft(x).ticks(6).tickFormat(this.formatTicks).tickSizeOuter(0); + const axisContainer = d3Select(this.axisBoxRef.current); + axisContainer.append('svg:svg') + .attr('width', 220) + .attr('height', 30) + .attr('class', 'pae-x-axis') + .style('z-index', '1') + .style('position', 'absolute') + .attr('transform', `translate(-93,202)`) + .append('g') + .attr('transform', `translate(6,0)`) + .call(xAxis); + axisContainer.append('svg:svg') + .attr('width', 50) + .attr('height', 220) + .attr('class', 'pae-y-axis') + .style('z-index', '1') + .style('position', 'absolute') + .attr('transform', `translate(-123,0)`) + .append('g') + .attr('transform', `translate(36,4)`) + .call(yAxis); + } + }); + } + formatTicks(d) { + return d > 999 ? d / 1000 + 'k' : d; + } + renderControls() { + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (!superpositionState || !superpositionState.alphafold) + return null; + const errorScale = [0, 5, 10, 15, 20, 25, 30]; + return _jsxs("div", { className: 'msp-flex-row', style: { height: 'auto', textAlign: 'center', justifyContent: 'center', padding: '15px 0', position: 'relative', fontSize: '12px' }, children: [_jsx("div", { ref: this.axisBoxRef, className: 'pae-axis-box', style: { position: 'absolute', width: '100%', height: '100%' } }), _jsx("span", { style: { transform: 'rotate(270deg)', position: 'absolute', transformOrigin: '0 0', left: '10px', top: '165px', fontWeight: 500 }, children: "Aligned residue" }), _jsxs("div", { className: 'msp-flex-row', style: { height: 'auto', flexDirection: 'column' }, children: [_jsx("div", { style: { width: '200px', height: '200px', border: '1px solid #6a635a', margin: '2px 0 25px 25px', position: 'relative' }, children: _jsx("img", { style: { width: '100%', height: '100%', position: 'absolute', left: 0, top: 0 }, src: `${superpositionState.alphafold.apiData.pae}`, alt: "PAE" }) }), _jsx("div", { style: { textAlign: 'center', paddingLeft: '30px', marginBottom: '20px', fontWeight: 500 }, children: "Scored residue" }), _jsx("img", { style: { width: '200px', height: '10px', border: '1px solid #6a635a', margin: '2px 0 25px 25px', transform: 'rotate(180deg)' }, src: 'https://alphafold.ebi.ac.uk/assets/img/horizontal_colorbar.png', alt: "PAE Scale" }), _jsx("ul", { style: { listStyleType: 'none', fontWeight: 500, margin: 0, display: 'inline-block', position: 'absolute', top: '292px', marginLeft: '24px' }, children: errorScale.map((errValue) => _jsx("li", { style: { float: 'left', marginRight: '18px' }, children: errValue }, errValue)) }), _jsx("div", { style: { textAlign: 'center', paddingLeft: '20px', fontWeight: 500 }, children: "Expected position error (\u00C5ngstr\u00F6ms)" })] })] }); + } +} +export class AlphafoldSuperpositionControls extends CollapsableControls { + defaultState() { + return { + isCollapsed: false, + header: 'AlphaFold Superposition', + brand: { accent: 'gray', svg: SuperpositionSvg }, + isHidden: true + }; + } + componentDidMount() { + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, sel => { + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (superpositionState && superpositionState.alphafold.apiData.cif && superpositionState.alphafold.apiData.cif !== '') { + this.setState({ isHidden: false }); + } + }); + } + rmsdTable() { + const spData = PluginCustomState(this.plugin).superpositionState; + if (!spData) + throw new Error('customState.superpositionState has not been initialized'); + const { activeSegment } = spData; + const { rmsds } = spData.alphafold; + return _jsxs("div", { className: 'msp-control-offset', children: [(rmsds.length === 0 || !rmsds[activeSegment - 1]) && _jsx("div", { className: 'msp-flex-row', style: { padding: '5px 0 0 10px' }, children: _jsx("strong", { children: "No overlap found!" }) }), rmsds[activeSegment - 1] && _jsxs("div", { className: 'msp-flex-row', children: [_jsx("div", { style: { width: '40%', borderRight: '1px solid rgb(213 206 196)', padding: '5px 0 0 5px' }, children: _jsx("strong", { children: "Entry" }) }), _jsx("div", { style: { padding: '5px 0 0 5px' }, children: _jsx("strong", { children: "RMSD (\u212B)" }) })] }), rmsds[activeSegment - 1] && rmsds[activeSegment - 1].map((d) => { + const details = d.split(':'); + return details[1] !== '-' ? _jsxs("div", { className: 'msp-flex-row', children: [_jsx("div", { className: 'msp-control-row-label', style: { width: '40%', borderRight: '1px solid rgb(213 206 196)', padding: '5px 0 0 5px' }, children: details[0] }), _jsx("div", { style: { padding: '5px 0 0 5px' }, children: details[1] })] }, d) : null; + })] }); + } + renderControls() { + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (!superpositionState) + throw new Error('customState.superpositionState has not been initialized'); + return _jsxs(_Fragment, { children: [superpositionState.alphafold.ref !== '' && this.rmsdTable(), superpositionState.alphafold.ref === '' && _jsx(AfSuperpositionControls, {})] }); + } +} +export const AlphafoldSuperpositionParams = { + // alignSequences: PD.Boolean(true, { isEssential: true, description: 'For Chain-based 3D superposition, perform a sequence alignment and use the aligned residue pairs to guide the 3D superposition.' }), + traceOnly: PD.Boolean(true, { description: 'For Chain- and Uniprot-based 3D superposition, base superposition only on CA (and equivalent) atoms.' }) +}; +const DefaultAlphafoldSuperpositionOptions = PD.getDefaultValues(AlphafoldSuperpositionParams); +export class AfSuperpositionControls extends PurePluginUIComponent { + state = { + isBusy: false, + canUseDb: true, + action: undefined, + options: DefaultAlphafoldSuperpositionOptions + }; + componentDidMount() { + this.subscribe(this.plugin.behaviors.state.isBusy, v => { + this.setState({ isBusy: v }); + }); + } + get selection() { + return this.plugin.managers.structure.selection; + } + get customState() { + return PluginCustomState(this.plugin); + } + superposeDb = async () => { + this.setState({ isBusy: true }); + const spData = this.customState.superpositionState; + if (!spData) + throw new Error('customState.superpositionState has not been initialized'); + spData.alphafold.traceOnly = this.state.options.traceOnly; + superposeAf(this.plugin, this.state.options.traceOnly); + }; + toggleOptions = () => this.setState({ action: this.state.action === 'options' ? void 0 : 'options' }); + superposeByDbMapping() { + return _jsx(_Fragment, { children: _jsx(Button, { icon: SuperposeChainsSvg, title: 'Superpose AlphaFold structure using intersection of residues from SIFTS UNIPROT mapping.', className: 'msp-btn msp-btn-block', onClick: this.superposeDb, style: { marginTop: '1px', textAlign: 'left' }, disabled: this.state.isBusy, children: "Load AlphaFold structure" }) }); + } + setOptions = (values) => { + this.setState({ options: values }); + }; + render() { + return _jsxs(_Fragment, { children: [_jsx("div", { style: { backgroundColor: '#dce54e', fontWeight: 500, padding: '5px 12px' }, children: "New Feature!" }), _jsx("div", { className: 'msp-help-text', style: { margin: '2px 0' }, children: _jsxs("div", { className: 'msp-help-description', children: [_jsx(Icon, { svg: InfoIconSvg, inline: true }), "Load and superpose AlphaFold structure against representative chains."] }) }), _jsxs("div", { className: 'msp-flex-row', children: [this.state.canUseDb && this.superposeByDbMapping(), _jsx(ToggleButton, { icon: TuneSvg, label: '', title: 'Options', toggle: this.toggleOptions, isSelected: this.state.action === 'options', disabled: this.state.isBusy, style: { flex: '0 0 40px', padding: 0 } })] }), this.state.action === 'options' && _jsx("div", { className: 'msp-control-offset', children: _jsx(ParameterControls, { params: AlphafoldSuperpositionParams, values: this.state.options, onChangeValues: this.setOptions, isDisabled: this.state.isBusy }) })] }); + } +} diff --git a/frontend/venome-molstar/lib/ui/alphafold-tranparency.d.ts b/frontend/venome-molstar/lib/ui/alphafold-tranparency.d.ts new file mode 100644 index 00000000..cb14b023 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/alphafold-tranparency.d.ts @@ -0,0 +1,21 @@ +import { CollapsableControls } from 'molstar/lib/mol-plugin-ui/base'; +export declare class AlphafoldTransparencyControls extends CollapsableControls<{}, { + transpareny: any; +}> { + defaultState(): { + isCollapsed: boolean; + header: string; + brand: { + accent: "gray"; + svg: typeof import("molstar/lib/mol-plugin-ui/controls/icons").FlipToFrontSvg; + }; + isHidden: boolean; + transpareny: { + score: number; + opacity: number; + }; + }; + componentDidMount(): void; + updateTransparency: (val: any) => Promise; + renderControls(): import("react/jsx-runtime").JSX.Element; +} diff --git a/frontend/venome-molstar/lib/ui/alphafold-tranparency.js b/frontend/venome-molstar/lib/ui/alphafold-tranparency.js new file mode 100644 index 00000000..c39892d8 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/alphafold-tranparency.js @@ -0,0 +1,45 @@ +import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime"; +import { CollapsableControls } from 'molstar/lib/mol-plugin-ui/base'; +import { SuperpositionSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import { applyAFTransparency, clearStructureTransparency } from '../alphafold-transparency'; +import { PluginCustomState } from '../plugin-custom-state'; +const TransparencyParams = { + score: PD.Numeric(70, { min: 0, max: 100, step: 1 }, { label: 'pLDDT less than', description: 'pLDDT score value in the range of 0 to 100' }), + opacity: PD.Numeric(0.2, { min: 0, max: 1, step: 0.01 }, { description: 'Opacity value in the range 0 to 1' }) +}; +export class AlphafoldTransparencyControls extends CollapsableControls { + defaultState() { + return { + isCollapsed: false, + header: 'AlphaFold Structure Opacity', + brand: { accent: 'gray', svg: SuperpositionSvg }, + isHidden: true, + transpareny: { + score: 70, + opacity: 0.2 + } + }; + } + componentDidMount() { + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, sel => { + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (superpositionState && superpositionState.alphafold.ref && superpositionState.alphafold.ref !== '') { + this.setState({ isHidden: false }); + } + }); + } + updateTransparency = async (val) => { + this.setState({ transpareny: val }); + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (!superpositionState) + throw new Error('customState.superpositionState has not been initialized'); + const afStr = this.plugin.managers.structure.hierarchy.current.refs.get(superpositionState.alphafold.ref); + await clearStructureTransparency(this.plugin, afStr.components); + await applyAFTransparency(this.plugin, afStr, 1 - val.opacity, val.score); + }; + renderControls() { + return _jsx(_Fragment, { children: _jsx(ParameterControls, { params: TransparencyParams, values: this.state.transpareny, onChangeValues: this.updateTransparency }) }); + } +} diff --git a/frontend/venome-molstar/lib/ui/annotation-controls.d.ts b/frontend/venome-molstar/lib/ui/annotation-controls.d.ts new file mode 100644 index 00000000..d27bc38f --- /dev/null +++ b/frontend/venome-molstar/lib/ui/annotation-controls.d.ts @@ -0,0 +1,27 @@ +import { PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +export declare function TextsmsOutlinedSvg(): import("react/jsx-runtime").JSX.Element; +type AnnotationType = 'validation' | 'domains' | 'symmetry'; +interface AnnotationsComponentControlsState { + isCollapsed: boolean; + validationApplied: boolean; + validationOptions: boolean; + validationParams: any; + domainsApplied: boolean; + domainsOptions: boolean; + domainsParams: any; + showSymmetryAnnotation: boolean; + description?: string; +} +export declare class AnnotationsComponentControls extends PurePluginUIComponent<{}, AnnotationsComponentControlsState> { + state: AnnotationsComponentControlsState; + componentDidMount(): void; + initOptionParams: () => void; + getStructure: () => import("molstar/lib/mol-state/object").StateObject> | undefined; + toggleCollapsed: () => void; + applyAnnotation: (type: 'validation' | 'domains', visibleState: boolean, params?: any) => void; + toggleAnnotation: (type: AnnotationType) => void; + updateValidationParams: (val: any) => void; + updateDomainParams: (val: any) => void; + render(): import("react/jsx-runtime").JSX.Element; +} +export {}; diff --git a/frontend/venome-molstar/lib/ui/annotation-controls.js b/frontend/venome-molstar/lib/ui/annotation-controls.js new file mode 100644 index 00000000..bd1dfe83 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/annotation-controls.js @@ -0,0 +1,151 @@ +import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; +import { PDBeStructureQualityReport } from 'molstar/lib/extensions/pdbe/structure-quality-report/behavior'; +import { StructureQualityReportColorThemeProvider } from 'molstar/lib/extensions/pdbe/structure-quality-report/color'; +import { StructureHierarchyManager } from 'molstar/lib/mol-plugin-state/manager/structure/hierarchy'; +import { PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { Button } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { ArrowDropDownSvg, ArrowRightSvg, Icon } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { StateSelection, StateTransform } from 'molstar/lib/mol-state'; +import { PDBeDomainAnnotations } from '../domain-annotations/behavior'; +import { DomainAnnotationsColorThemeProvider } from '../domain-annotations/color'; +import { PluginCustomState } from '../plugin-custom-state'; +import { AnnotationRowControls } from './annotation-row-controls'; +import { SymmetryAnnotationControls, isAssemblySymmetryAnnotationApplicable } from './symmetry-annotation-controls'; +const _TextsmsOutlined = _jsxs("svg", { width: '24px', height: '24px', viewBox: '0 0 24 24', children: [_jsx("path", { fill: "none", d: "M0 0h24v24H0V0z" }), _jsxs("g", { children: [_jsx("path", { d: "M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z" }), _jsx("path", { d: "M7 9h2v2H7zM11 9h2v2h-2zM15 9h2v2h-2z" })] })] }); +export function TextsmsOutlinedSvg() { return _TextsmsOutlined; } +export class AnnotationsComponentControls extends PurePluginUIComponent { + state = { + isCollapsed: false, + validationApplied: false, + validationOptions: false, + validationParams: undefined, + domainsApplied: false, + domainsOptions: false, + domainsParams: undefined, + showSymmetryAnnotation: false, + }; + componentDidMount() { + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, () => { + this.initOptionParams(); + this.forceUpdate(); + }); + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, c => this.setState({ + description: StructureHierarchyManager.getSelectedStructuresDescription(this.plugin) + })); + } + initOptionParams = () => { + const initParams = PluginCustomState(this.plugin).initParams; + const validationAnnotationCtrl = !!initParams?.validationAnnotation; + const domainAnnotationCtrl = !!initParams?.domainAnnotation; + const symmetryAnnotationCtrl = !!initParams?.symmetryAnnotation && isAssemblySymmetryAnnotationApplicable(this.plugin); + this.setState({ showSymmetryAnnotation: symmetryAnnotationCtrl }); + if ((validationAnnotationCtrl && !this.state.validationParams) || (domainAnnotationCtrl && !this.state.domainsParams)) { + const structure = this.getStructure()?.data; + if (structure) { + const themeDataCtx = { structure }; + if (validationAnnotationCtrl && !this.state.validationParams) { + const validationActionsParams = StructureQualityReportColorThemeProvider.getParams(themeDataCtx); + if (validationActionsParams) { + this.setState({ + validationParams: { + params: validationActionsParams, + values: { type: validationActionsParams.type.defaultValue } + } + }); + } + } + if (domainAnnotationCtrl && !this.state.domainsParams) { + const domainActionsParams = DomainAnnotationsColorThemeProvider.getParams(themeDataCtx); + if (domainActionsParams) { + this.setState({ + domainsParams: { + params: domainActionsParams, + values: { type: domainActionsParams.type.defaultValue } + } + }); + } + } + } + } + }; + getStructure = () => { + const groupRef = StateSelection.findTagInSubtree(this.plugin.state.data.tree, StateTransform.RootRef, 'structure-component-static-polymer'); + return groupRef ? this.plugin.state.data.select(groupRef)[0]?.obj : undefined; + }; + toggleCollapsed = () => { + this.setState({ isCollapsed: !this.state.isCollapsed }); + }; + applyAnnotation = (type, visibleState, params) => { + // Defaults + let themeName = 'chain-id'; + let themePropsToAdd = PDBeStructureQualityReport; + let themePropsToRemove = this.state.domainsParams ? PDBeDomainAnnotations : void 0; + // Set Theme Params + if (type === 'validation') { + if (visibleState) { + themeName = 'pdbe-structure-quality-report'; + } + this.setState({ validationApplied: visibleState }); + this.setState({ domainsApplied: false }); + } + else if (type === 'domains') { + themePropsToAdd = PDBeDomainAnnotations; + themePropsToRemove = this.state.validationParams ? PDBeStructureQualityReport : void 0; + if (visibleState) + themeName = 'pdbe-domain-annotations'; + this.setState({ domainsApplied: visibleState }); + this.setState({ validationApplied: false }); + } + // Update Tooltip + if (visibleState && themeName !== 'chain-id') { + const addTooltipUpdate = this.plugin.state.behaviors.build().to(themePropsToAdd.id).update(themePropsToAdd, (old) => { old.showTooltip = true; }); + this.plugin.runTask(this.plugin.state.behaviors.updateTree(addTooltipUpdate)); + if (themePropsToRemove) { + const removeTooltipUpdate = this.plugin.state.behaviors.build().to(themePropsToRemove.id).update(themePropsToRemove, (old) => { old.showTooltip = false; }); + this.plugin.runTask(this.plugin.state.behaviors.updateTree(removeTooltipUpdate)); + } + } + let polymerGroup; + const componentGroups = this.plugin.managers.structure.hierarchy.currentComponentGroups; + componentGroups.forEach((compGrp) => { + if (compGrp[0].key === 'structure-component-static-polymer') + polymerGroup = compGrp; + }); + if (polymerGroup) { + this.plugin.managers.structure.component.updateRepresentationsTheme(polymerGroup, { color: themeName, colorParams: params ? params : void 0 }); + } + }; + toggleAnnotation = (type) => { + if (type === 'validation') + this.applyAnnotation('validation', !this.state.validationApplied, this.state.validationParams.values); + if (type === 'domains') + this.applyAnnotation('domains', !this.state.domainsApplied, this.state.domainsParams.values); + }; + updateValidationParams = (val) => { + const updatedParams = { ...this.state.validationParams }; + updatedParams.values = val; + this.setState({ validationParams: updatedParams }); + if (this.state.validationApplied) + this.applyAnnotation('validation', this.state.validationApplied, val); + }; + updateDomainParams = (val) => { + const updatedParams = { ...this.state.domainsParams }; + updatedParams.values = val; + this.setState({ domainsParams: updatedParams }); + if (this.state.domainsApplied) + this.applyAnnotation('domains', this.state.domainsApplied, val); + }; + render() { + if (!this.state.validationParams && !this.state.domainsParams && !this.state.showSymmetryAnnotation) + return _jsx(_Fragment, {}); + const brand = { + accent: 'green', + svg: TextsmsOutlinedSvg + }; + const wrapClass = this.state.isCollapsed + ? 'msp-transform-wrapper msp-transform-wrapper-collapsed' + : 'msp-transform-wrapper'; + return _jsxs("div", { className: wrapClass, children: [_jsx("div", { className: 'msp-transform-header', children: _jsxs(Button, { icon: brand ? void 0 : this.state.isCollapsed ? ArrowRightSvg : ArrowDropDownSvg, noOverflow: true, onClick: this.toggleCollapsed, className: brand ? `msp-transform-header-brand msp-transform-header-brand-${brand.accent}` : void 0, title: `Click to ${this.state.isCollapsed ? 'expand' : 'collapse'}`, children: [_jsx(Icon, { svg: brand?.svg, inline: true }), "Annotations", _jsx("small", { style: { margin: '0 6px' }, children: this.state.isCollapsed ? '' : this.state.description })] }) }), !this.state.isCollapsed && _jsxs(_Fragment, { children: [_jsx(AnnotationRowControls, { title: 'Validation', params: this.state.validationParams?.params, values: this.state.validationParams?.values, onChangeValues: this.updateValidationParams, applied: this.state.validationApplied, onChangeApplied: () => this.toggleAnnotation('validation') }), _jsx(AnnotationRowControls, { title: 'Domain Annotations', shortTitle: 'Domains', params: this.state.domainsParams?.params, values: this.state.domainsParams?.values, onChangeValues: this.updateDomainParams, applied: this.state.domainsApplied, onChangeApplied: () => this.toggleAnnotation('domains') }), this.state.showSymmetryAnnotation && + _jsx(SymmetryAnnotationControls, {})] })] }); + } +} diff --git a/frontend/venome-molstar/lib/ui/annotation-row-controls.d.ts b/frontend/venome-molstar/lib/ui/annotation-row-controls.d.ts new file mode 100644 index 00000000..5ee97afc --- /dev/null +++ b/frontend/venome-molstar/lib/ui/annotation-row-controls.d.ts @@ -0,0 +1,26 @@ +import { ParameterControlsProps } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import React from 'react'; +type AnnotationRowControlsProps

= ParameterControlsProps

& { + shortTitle?: string; + title: string; + applied?: boolean; + onChangeApplied?: (applied: boolean) => void; +}; +type AnnotationRowControlsState = { + applied: boolean; + optionsExpanded: boolean; +}; +/** UI controls for a single annotation source (row) in Annotations section */ +export declare class AnnotationRowControls

extends React.PureComponent, AnnotationRowControlsState> { + state: { + applied: boolean; + optionsExpanded: boolean; + }; + isApplied(): boolean; + toggleApplied(applied?: boolean): void; + toggleOptions(): void; + render(): import("react/jsx-runtime").JSX.Element | null; + renderOptions(): import("react/jsx-runtime").JSX.Element; +} +export {}; diff --git a/frontend/venome-molstar/lib/ui/annotation-row-controls.js b/frontend/venome-molstar/lib/ui/annotation-row-controls.js new file mode 100644 index 00000000..536c54d2 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/annotation-row-controls.js @@ -0,0 +1,36 @@ +import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; +import { Button, IconButton } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { MoreHorizSvg, VisibilityOffOutlinedSvg, VisibilityOutlinedSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import React from 'react'; +/** UI controls for a single annotation source (row) in Annotations section */ +export class AnnotationRowControls extends React.PureComponent { + state = { applied: false, optionsExpanded: false }; + // componentDidMount() { + // this.subscribe(this.plugin.state.events.cell.stateUpdated, e => { + // if (State.ObjectEvent.isCell(e, this.pivot.cell)) this.forceUpdate(); + // }); + // } + isApplied() { + return this.props.applied ?? this.state.applied; + } + toggleApplied(applied) { + const newState = applied ?? !this.isApplied(); + if (this.props.applied === undefined) { + this.setState({ applied: newState }); + } + this.props.onChangeApplied?.(newState); + } + toggleOptions() { + this.setState(s => ({ optionsExpanded: !s.optionsExpanded })); + } + render() { + if (!this.props.params) + return null; + return _jsxs(_Fragment, { children: [_jsxs("div", { className: 'msp-flex-row', children: [_jsx(Button, { noOverflow: true, className: 'msp-control-button-label', title: this.props.title, style: { textAlign: 'left' }, children: this.props.shortTitle ?? this.props.title }), _jsx(IconButton, { onClick: () => this.toggleApplied(), toggleState: false, svg: !this.isApplied() ? VisibilityOffOutlinedSvg : VisibilityOutlinedSvg, title: `Click to ${this.isApplied() ? 'hide' : 'show'} ${this.props.title}`, small: true, className: 'msp-form-control', flex: true }), _jsx(IconButton, { onClick: () => this.toggleOptions(), svg: MoreHorizSvg, title: 'Options', toggleState: this.state.optionsExpanded, className: 'msp-form-control', flex: true })] }), this.state.optionsExpanded && + _jsx("div", { style: { marginBottom: '6px' }, children: _jsx("div", { className: "msp-accent-offset", children: _jsx("div", { className: 'msp-representation-entry', children: this.renderOptions() }) }) })] }); + } + renderOptions() { + return _jsx(ParameterControls, { params: this.props.params, onChange: this.props.onChange, values: this.props.values, onChangeValues: this.props.onChangeValues, onEnter: this.props.onEnter }); + } +} diff --git a/frontend/venome-molstar/lib/ui/export-superposition.d.ts b/frontend/venome-molstar/lib/ui/export-superposition.d.ts new file mode 100644 index 00000000..309fb5e9 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/export-superposition.d.ts @@ -0,0 +1,6 @@ +/// +import { CollapsableControls, CollapsableState } from 'molstar/lib/mol-plugin-ui/base'; +export declare class SuperpositionModelExportUI extends CollapsableControls<{}, {}> { + protected defaultState(): CollapsableState; + protected renderControls(): JSX.Element | null; +} diff --git a/frontend/venome-molstar/lib/ui/export-superposition.js b/frontend/venome-molstar/lib/ui/export-superposition.js new file mode 100644 index 00000000..bc3e1cf4 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/export-superposition.js @@ -0,0 +1,49 @@ +import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; +import { useState } from 'react'; +import { CollapsableControls } from 'molstar/lib/mol-plugin-ui/base'; +import { Button } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { GetAppSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { useBehavior } from 'molstar/lib/mol-plugin-ui/hooks/use-behavior'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import { superpositionExportHierarchy } from '../superposition-export'; +export class SuperpositionModelExportUI extends CollapsableControls { + defaultState() { + return { + header: 'Export Models', + isCollapsed: true, + brand: { accent: 'cyan', svg: GetAppSvg } + }; + } + renderControls() { + return _jsx(SuperpositionExportControls, { plugin: this.plugin }); + } +} +const Params = { + format: PD.Select('cif', [['cif', 'mmCIF'], ['bcif', 'Binary mmCIF']]) +}; +const DefaultParams = PD.getDefaultValues(Params); +function SuperpositionExportControls({ plugin }) { + const [params, setParams] = useState(DefaultParams); + const [exporting, setExporting] = useState(false); + useBehavior(plugin.managers.structure.hierarchy.behaviors.selection); // triggers UI update + const isBusy = useBehavior(plugin.behaviors.state.isBusy); + const hierarchy = plugin.managers.structure.hierarchy.current; + let label = 'Nothing to Export'; + if (hierarchy.structures.length === 1) { + label = 'Export'; + } + if (hierarchy.structures.length > 1) { + label = 'Export (as ZIP)'; + } + const onExport = async () => { + setExporting(true); + try { + await superpositionExportHierarchy(plugin, { format: params.format }); + } + finally { + setExporting(false); + } + }; + return _jsxs(_Fragment, { children: [_jsx(ParameterControls, { params: Params, values: params, onChangeValues: setParams, isDisabled: isBusy || exporting }), _jsx(Button, { onClick: onExport, style: { marginTop: 1 }, disabled: isBusy || hierarchy.structures.length === 0 || exporting, commit: hierarchy.structures.length > 0 ? 'on' : 'off', children: label })] }); +} diff --git a/frontend/venome-molstar/lib/ui/pdbe-left-panel.d.ts b/frontend/venome-molstar/lib/ui/pdbe-left-panel.d.ts new file mode 100644 index 00000000..c44cc3bf --- /dev/null +++ b/frontend/venome-molstar/lib/ui/pdbe-left-panel.d.ts @@ -0,0 +1,18 @@ +/// +import { PluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +export declare function WavesIconSvg(): import("react/jsx-runtime").JSX.Element; +type LeftPanelTabName = 'none' | 'root' | 'data' | 'states' | 'settings' | 'help' | 'segments'; +export declare class LeftPanelControls extends PluginUIComponent<{}, { + tab: LeftPanelTabName; +}> { + state: { + tab: LeftPanelTabName; + }; + componentDidMount(): void; + set: (tab: LeftPanelTabName) => void; + tabs: { + [K in LeftPanelTabName]: JSX.Element; + }; + render(): import("react/jsx-runtime").JSX.Element; +} +export {}; diff --git a/frontend/venome-molstar/lib/ui/pdbe-left-panel.js b/frontend/venome-molstar/lib/ui/pdbe-left-panel.js new file mode 100644 index 00000000..c1c55b74 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/pdbe-left-panel.js @@ -0,0 +1,129 @@ +import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; +import { Canvas3DParams } from 'molstar/lib/mol-canvas3d/canvas3d'; +import { PluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { IconButton, SectionHeader } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { AccountTreeOutlinedSvg, DeleteOutlinedSvg, HelpOutlineSvg, HomeOutlinedSvg, TuneSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { StateObjectActions } from 'molstar/lib/mol-plugin-ui/state/actions'; +import { RemoteStateSnapshots, StateSnapshots } from 'molstar/lib/mol-plugin-ui/state/snapshots'; +import { StateTree } from 'molstar/lib/mol-plugin-ui/state/tree'; +import { HelpContent, HelpGroup, HelpText } from 'molstar/lib/mol-plugin-ui/viewport/help'; +import { PluginCommands } from 'molstar/lib/mol-plugin/commands'; +import { StateTransform } from 'molstar/lib/mol-state'; +import { PluginCustomState } from '../plugin-custom-state'; +import { SegmentTree } from './segment-tree'; +const _WavesIcon = _jsx("svg", { width: '24px', height: '24px', viewBox: '0 0 24 24', children: _jsx("path", { d: "M17 16.99c-1.35 0-2.2.42-2.95.8-.65.33-1.18.6-2.05.6-.9 0-1.4-.25-2.05-.6-.75-.38-1.57-.8-2.95-.8s-2.2.42-2.95.8c-.65.33-1.17.6-2.05.6v1.95c1.35 0 2.2-.42 2.95-.8.65-.33 1.17-.6 2.05-.6s1.4.25 2.05.6c.75.38 1.57.8 2.95.8s2.2-.42 2.95-.8c.65-.33 1.18-.6 2.05-.6.9 0 1.4.25 2.05.6.75.38 1.58.8 2.95.8v-1.95c-.9 0-1.4-.25-2.05-.6-.75-.38-1.6-.8-2.95-.8zm0-4.45c-1.35 0-2.2.43-2.95.8-.65.32-1.18.6-2.05.6-.9 0-1.4-.25-2.05-.6-.75-.38-1.57-.8-2.95-.8s-2.2.43-2.95.8c-.65.32-1.17.6-2.05.6v1.95c1.35 0 2.2-.43 2.95-.8.65-.35 1.15-.6 2.05-.6s1.4.25 2.05.6c.75.38 1.57.8 2.95.8s2.2-.43 2.95-.8c.65-.35 1.15-.6 2.05-.6s1.4.25 2.05.6c.75.38 1.58.8 2.95.8v-1.95c-.9 0-1.4-.25-2.05-.6-.75-.38-1.6-.8-2.95-.8zm2.95-8.08c-.75-.38-1.58-.8-2.95-.8s-2.2.42-2.95.8c-.65.32-1.18.6-2.05.6-.9 0-1.4-.25-2.05-.6-.75-.37-1.57-.8-2.95-.8s-2.2.42-2.95.8c-.65.33-1.17.6-2.05.6v1.93c1.35 0 2.2-.43 2.95-.8.65-.33 1.17-.6 2.05-.6s1.4.25 2.05.6c.75.38 1.57.8 2.95.8s2.2-.43 2.95-.8c.65-.32 1.18-.6 2.05-.6.9 0 1.4.25 2.05.6.75.38 1.58.8 2.95.8V5.04c-.9 0-1.4-.25-2.05-.58zM17 8.09c-1.35 0-2.2.43-2.95.8-.65.35-1.15.6-2.05.6s-1.4-.25-2.05-.6c-.75-.38-1.57-.8-2.95-.8s-2.2.43-2.95.8c-.65.35-1.15.6-2.05.6v1.95c1.35 0 2.2-.43 2.95-.8.65-.32 1.18-.6 2.05-.6s1.4.25 2.05.6c.75.38 1.57.8 2.95.8s2.2-.43 2.95-.8c.65-.32 1.18-.6 2.05-.6.9 0 1.4.25 2.05.6.75.38 1.58.8 2.95.8V9.49c-.9 0-1.4-.25-2.05-.6-.75-.38-1.6-.8-2.95-.8z" }) }); +export function WavesIconSvg() { return _WavesIcon; } +export class LeftPanelControls extends PluginUIComponent { + state = { tab: this.plugin.behaviors.layout.leftPanelTabName.value }; + componentDidMount() { + this.subscribe(this.plugin.behaviors.layout.leftPanelTabName, tab => { + if (this.state.tab !== tab) + this.setState({ tab }); + if (tab === 'none' && this.plugin.layout.state.regionState.left !== 'collapsed') { + PluginCommands.Layout.Update(this.plugin, { state: { regionState: { ...this.plugin.layout.state.regionState, left: 'collapsed' } } }); + } + }); + this.subscribe(this.plugin.state.data.events.changed, ({ state }) => { + if (this.state.tab !== 'data') + return; + if (state.cells.size === 1) + this.set('root'); + }); + } + set = (tab) => { + if (this.state.tab === tab) { + this.setState({ tab: 'none' }, () => this.plugin.behaviors.layout.leftPanelTabName.next('none')); + PluginCommands.Layout.Update(this.plugin, { state: { regionState: { ...this.plugin.layout.state.regionState, left: 'collapsed' } } }); + return; + } + this.setState({ tab }, () => this.plugin.behaviors.layout.leftPanelTabName.next(tab)); + if (this.plugin.layout.state.regionState.left !== 'full') { + PluginCommands.Layout.Update(this.plugin, { state: { regionState: { ...this.plugin.layout.state.regionState, left: 'full' } } }); + } + }; + tabs = { + 'none': _jsx(_Fragment, {}), + 'root': _jsxs(_Fragment, { children: [_jsx(SectionHeader, { icon: HomeOutlinedSvg, title: 'Home' }), _jsx(StateObjectActions, { state: this.plugin.state.data, nodeRef: StateTransform.RootRef, hideHeader: true, initiallyCollapsed: true, alwaysExpandFirst: true }), this.plugin.spec.components?.remoteState !== 'none' && _jsx(RemoteStateSnapshots, { listOnly: true })] }), + 'data': _jsxs(_Fragment, { children: [_jsx(SectionHeader, { icon: AccountTreeOutlinedSvg, title: _jsxs(_Fragment, { children: [_jsx(RemoveAllButton, {}), " State Tree"] }) }), _jsx(StateTree, { state: this.plugin.state.data })] }), + 'segments': _jsx(_Fragment, { children: _jsx(SegmentTree, {}) }), + 'states': _jsx(StateSnapshots, {}), + 'settings': _jsxs(_Fragment, { children: [_jsx(SectionHeader, { icon: TuneSvg, title: 'Plugin Settings' }), _jsx(FullSettings, {})] }), + 'help': _jsxs(_Fragment, { children: [_jsx(SectionHeader, { icon: HelpOutlineSvg, title: 'Help' }), _jsx(HelpContent, {}), _jsx(SuperpositionHelpContent, {})] }) + }; + render() { + const tab = this.state.tab; + const customState = PluginCustomState(this.plugin); + return _jsxs("div", { className: 'msp-left-panel-controls', children: [_jsxs("div", { className: 'msp-left-panel-controls-buttons', children: [_jsx(IconButton, { svg: HelpOutlineSvg, toggleState: tab === 'help', transparent: true, onClick: () => this.set('help'), title: 'Help' }), customState && customState.initParams && customState.initParams.superposition && _jsx(IconButton, { svg: WavesIconSvg, toggleState: tab === 'segments', transparent: true, onClick: () => this.set('segments'), title: 'Superpose segments' }), _jsx("div", { className: 'msp-left-panel-controls-buttons-bottom', children: _jsx(IconButton, { svg: TuneSvg, toggleState: tab === 'settings', transparent: true, onClick: () => this.set('settings'), title: 'Settings' }) })] }), _jsx("div", { className: 'msp-scrollable-container', children: this.tabs[tab] })] }); + } +} +// class DataIcon extends PluginUIComponent<{ set: (tab: LeftPanelTabName) => void }, { changed: boolean }> { +// state = { changed: false }; +// get tab() { +// return this.plugin.behaviors.layout.leftPanelTabName.value; +// } +// componentDidMount() { +// this.subscribe(this.plugin.behaviors.layout.leftPanelTabName, tab => { +// if (this.tab === 'data') this.setState({ changed: false }); +// else this.forceUpdate(); +// }); +// this.subscribe(this.plugin.state.data.events.changed, state => { +// if (this.tab !== 'data') this.setState({ changed: true }); +// }); +// } +// render() { +// return this.props.set('data')} title='State Tree' +// style={{ position: 'relative' }} extraContent={this.state.changed ?

: void 0} />; +// } +// } +class FullSettings extends PluginUIComponent { + setSettings = (p) => { + PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { [p.name]: p.value } }); + }; + componentDidMount() { + this.subscribe(this.plugin.events.canvas3d.settingsUpdated, () => this.forceUpdate()); + this.subscribe(this.plugin.layout.events.updated, () => this.forceUpdate()); + this.subscribe(this.plugin.canvas3d.camera.stateChanged, state => { + if (state.radiusMax !== undefined || state.radius !== undefined) { + this.forceUpdate(); + } + }); + } + render() { + return _jsx(_Fragment, { children: this.plugin.canvas3d && _jsxs(_Fragment, { children: [_jsx(SectionHeader, { title: 'Viewport' }), _jsx(ParameterControls, { params: Canvas3DParams, values: this.plugin.canvas3d.props, onChange: this.setSettings })] }) }); + } +} +class RemoveAllButton extends PluginUIComponent { + componentDidMount() { + this.subscribe(this.plugin.state.events.cell.created, e => { + if (e.cell.transform.parent === StateTransform.RootRef) + this.forceUpdate(); + }); + this.subscribe(this.plugin.state.events.cell.removed, e => { + if (e.parent === StateTransform.RootRef) + this.forceUpdate(); + }); + } + remove = (e) => { + e.preventDefault(); + PluginCommands.State.RemoveObject(this.plugin, { state: this.plugin.state.data, ref: StateTransform.RootRef }); + }; + render() { + const count = this.plugin.state.data.tree.children.get(StateTransform.RootRef).size; + if (count === 0) + return null; + return _jsx(IconButton, { svg: DeleteOutlinedSvg, onClick: this.remove, title: 'Remove All', style: { display: 'inline-block' }, small: true, className: 'msp-no-hover-outline', transparent: true }); + } +} +function HelpSection(props) { + return _jsx("div", { className: 'msp-simple-help-section', children: props.header }); +} +class SuperpositionHelpContent extends PluginUIComponent { + componentDidMount() { + this.subscribe(this.plugin.events.canvas3d.settingsUpdated, () => this.forceUpdate()); + } + render() { + return _jsxs("div", { children: [_jsx(HelpSection, { header: 'Superposition' }), _jsx(HelpGroup, { header: 'Segment', children: _jsx(HelpText, { children: _jsx("p", { children: "Discrete UniProt sequence range mapped to the structure" }) }) }), _jsx(HelpGroup, { header: 'Cluster', children: _jsx(HelpText, { children: _jsx("p", { children: "Structural chains that possess significantly close superposition Q-score" }) }) }), _jsx(HelpGroup, { header: 'Representative chain', children: _jsx(HelpText, { children: _jsx("p", { children: "The best-ranked chain within a cluster chosen based on the model quality, resolution, observed residues ratio and UniProt sequence coverage" }) }) })] }); + } +} diff --git a/frontend/venome-molstar/lib/ui/pdbe-screenshot-controls.d.ts b/frontend/venome-molstar/lib/ui/pdbe-screenshot-controls.d.ts new file mode 100644 index 00000000..fb83b23b --- /dev/null +++ b/frontend/venome-molstar/lib/ui/pdbe-screenshot-controls.d.ts @@ -0,0 +1,20 @@ +import * as React from 'react'; +import { PluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +interface ImageControlsState { + showPreview: boolean; + isDisabled: boolean; + imageData?: string; +} +export declare class DownloadScreenshotControls extends PluginUIComponent<{ + close: () => void; +}, ImageControlsState> { + state: ImageControlsState; + private download; + private copy; + private copyImg; + componentDidMount(): void; + componentWillUnmount(): void; + open: (e: React.ChangeEvent) => void; + render(): import("react/jsx-runtime").JSX.Element; +} +export {}; diff --git a/frontend/venome-molstar/lib/ui/pdbe-screenshot-controls.js b/frontend/venome-molstar/lib/ui/pdbe-screenshot-controls.js new file mode 100644 index 00000000..1a67fc5c --- /dev/null +++ b/frontend/venome-molstar/lib/ui/pdbe-screenshot-controls.js @@ -0,0 +1,65 @@ +import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { PluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { ScreenshotPreview } from 'molstar/lib/mol-plugin-ui/controls/screenshot'; +import { Button, ToggleButton } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { PluginCommands } from 'molstar/lib/mol-plugin/commands'; +import { useBehavior } from 'molstar/lib/mol-plugin-ui/hooks/use-behavior'; +import { GetAppSvg, CopySvg, CropOrginalSvg, CropSvg, CropFreeSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +export class DownloadScreenshotControls extends PluginUIComponent { + state = { + showPreview: true, + isDisabled: false + }; + download = () => { + this.plugin.helpers.viewportScreenshot?.download(); + this.props.close(); + }; + copy = async () => { + try { + await this.plugin.helpers.viewportScreenshot?.copyToClipboard(); + PluginCommands.Toast.Show(this.plugin, { + message: 'Copied to clipboard.', + title: 'Screenshot', + timeoutMs: 1500 + }); + } + catch { + return this.copyImg(); + } + }; + copyImg = async () => { + const src = await this.plugin.helpers.viewportScreenshot?.getImageDataUri(); + this.setState({ imageData: src }); + }; + componentDidMount() { + this.subscribe(this.plugin.state.data.behaviors.isUpdating, v => { + this.setState({ isDisabled: v }); + }); + } + componentWillUnmount() { + this.setState({ imageData: void 0 }); + } + open = (e) => { + if (!e.target.files || !e.target.files[0]) + return; + PluginCommands.State.Snapshots.OpenFile(this.plugin, { file: e.target.files[0] }); + }; + render() { + const hasClipboardApi = !!navigator.clipboard?.write; + return _jsxs("div", { children: [this.state.showPreview && _jsxs("div", { className: 'msp-image-preview', children: [_jsx(ScreenshotPreview, { plugin: this.plugin }), _jsx(CropControls, { plugin: this.plugin })] }), _jsxs("div", { className: 'msp-flex-row', children: [!this.state.imageData && _jsx(Button, { icon: CopySvg, onClick: hasClipboardApi ? this.copy : this.copyImg, disabled: this.state.isDisabled, children: "Copy" }), this.state.imageData && _jsx(Button, { onClick: () => this.setState({ imageData: void 0 }), disabled: this.state.isDisabled, children: "Clear" }), _jsx(Button, { icon: GetAppSvg, onClick: this.download, disabled: this.state.isDisabled, children: "Download" })] }), this.state.imageData && _jsxs("div", { className: 'msp-row msp-copy-image-wrapper', children: [_jsx("div", { children: "Right click below + Copy Image" }), _jsx("img", { src: this.state.imageData, style: { width: '100%', height: 32, display: 'block' } })] }), _jsx(ScreenshotParams, { plugin: this.plugin, isDisabled: this.state.isDisabled })] }); + } +} +function ScreenshotParams({ plugin, isDisabled }) { + const helper = plugin.helpers.viewportScreenshot; + const values = useBehavior(helper.behaviors.values); + return _jsx(ParameterControls, { params: helper.params, values: values, onChangeValues: v => helper.behaviors.values.next(v), isDisabled: isDisabled }); +} +function CropControls({ plugin }) { + const helper = plugin.helpers.viewportScreenshot; + const cropParams = useBehavior(helper?.behaviors.cropParams); + useBehavior(helper?.behaviors.relativeCrop); + if (!helper) + return null; + return _jsxs("div", { style: { width: '100%', height: '24px', marginTop: '8px' }, children: [_jsx(ToggleButton, { icon: CropOrginalSvg, title: 'Auto-crop', inline: true, isSelected: cropParams.auto, style: { background: 'transparent', float: 'left', width: 'auto', height: '24px', lineHeight: '24px' }, toggle: () => helper.toggleAutocrop(), label: 'Auto-crop ' + (cropParams.auto ? 'On' : 'Off') }), !cropParams.auto && _jsx(Button, { icon: CropSvg, title: 'Crop', style: { background: 'transparent', float: 'right', height: '24px', lineHeight: '24px', width: '24px', padding: '0' }, onClick: () => helper.autocrop() }), !cropParams.auto && !helper.isFullFrame && _jsx(Button, { icon: CropFreeSvg, title: 'Reset Crop', style: { background: 'transparent', float: 'right', height: '24px', lineHeight: '24px', width: '24px', padding: '0' }, onClick: () => helper.resetCrop() })] }); +} diff --git a/frontend/venome-molstar/lib/ui/pdbe-structure-controls.d.ts b/frontend/venome-molstar/lib/ui/pdbe-structure-controls.d.ts new file mode 100644 index 00000000..d765c0bb --- /dev/null +++ b/frontend/venome-molstar/lib/ui/pdbe-structure-controls.d.ts @@ -0,0 +1,18 @@ +import { PluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +export declare class PDBeStructureTools extends PluginUIComponent { + render(): import("react/jsx-runtime").JSX.Element; +} +export declare class CustomStructureControls extends PluginUIComponent<{ + initiallyCollapsed?: boolean; + takeKeys?: string[]; + skipKeys?: string[]; +}> { + componentDidMount(): void; + render(): import("react/jsx-runtime").JSX.Element | null; +} +export declare class PDBeLigandViewStructureTools extends PluginUIComponent { + render(): import("react/jsx-runtime").JSX.Element; +} +export declare class PDBeSuperpositionStructureTools extends PluginUIComponent { + render(): import("react/jsx-runtime").JSX.Element; +} diff --git a/frontend/venome-molstar/lib/ui/pdbe-structure-controls.js b/frontend/venome-molstar/lib/ui/pdbe-structure-controls.js new file mode 100644 index 00000000..7a69d90e --- /dev/null +++ b/frontend/venome-molstar/lib/ui/pdbe-structure-controls.js @@ -0,0 +1,48 @@ +import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; +import { PluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { StructureComponentControls } from 'molstar/lib/mol-plugin-ui/structure/components'; +import { StructureMeasurementsControls } from 'molstar/lib/mol-plugin-ui/structure/measurements'; +import { StructureSourceControls } from 'molstar/lib/mol-plugin-ui/structure/source'; +import { VolumeStreamingControls, VolumeSourceControls } from 'molstar/lib/mol-plugin-ui/structure/volume'; +import { AnnotationsComponentControls } from './annotation-controls'; +import { Icon, BuildSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { SuperpositionComponentControls } from './superposition-components'; +import { StructureQuickStylesControls } from 'molstar/lib/mol-plugin-ui/structure/quick-styles'; +import { AlphafoldPaeControls, AlphafoldSuperpositionControls } from './alphafold-superposition'; +import { SuperpositionModelExportUI } from './export-superposition'; +import { AlphafoldTransparencyControls } from './alphafold-tranparency'; +import { AssemblySymmetry } from 'molstar/lib/extensions/rcsb/assembly-symmetry/prop'; +export class PDBeStructureTools extends PluginUIComponent { + render() { + const AssemblySymmetryKey = AssemblySymmetry.Tag.Representation; + return _jsxs(_Fragment, { children: [_jsxs("div", { className: 'msp-section-header', children: [_jsx(Icon, { svg: BuildSvg }), "Structure Tools"] }), _jsx(StructureSourceControls, {}), _jsx(AnnotationsComponentControls, {}), _jsx(StructureQuickStylesControls, {}), _jsx(StructureComponentControls, {}), _jsx(VolumeStreamingControls, {}), _jsx(VolumeSourceControls, {}), _jsx(StructureMeasurementsControls, {}), _jsx(CustomStructureControls, { skipKeys: [AssemblySymmetryKey] })] }); + } +} +export class CustomStructureControls extends PluginUIComponent { + componentDidMount() { + this.subscribe(this.plugin.state.behaviors.events.changed, () => this.forceUpdate()); + } + render() { + const takeKeys = this.props.takeKeys ?? Array.from(this.plugin.customStructureControls.keys()); + const result = []; + for (const key of takeKeys) { + if (this.props.skipKeys?.includes(key)) + continue; + const Controls = this.plugin.customStructureControls.get(key); + if (!Controls) + continue; + result.push(_jsx(Controls, { initiallyCollapsed: this.props.initiallyCollapsed }, key)); + } + return result.length > 0 ? _jsx(_Fragment, { children: result }) : null; + } +} +export class PDBeLigandViewStructureTools extends PluginUIComponent { + render() { + return _jsxs(_Fragment, { children: [_jsxs("div", { className: 'msp-section-header', children: [_jsx(Icon, { svg: BuildSvg }), "Structure Tools"] }), _jsx(StructureComponentControls, {}), _jsx(VolumeStreamingControls, {}), _jsx(StructureMeasurementsControls, {}), _jsx(CustomStructureControls, {})] }); + } +} +export class PDBeSuperpositionStructureTools extends PluginUIComponent { + render() { + return _jsxs(_Fragment, { children: [_jsxs("div", { className: 'msp-section-header', children: [_jsx(Icon, { svg: BuildSvg }), "Structure Tools"] }), _jsx(SuperpositionComponentControls, {}), _jsx(AlphafoldTransparencyControls, {}), _jsx(AlphafoldPaeControls, {}), _jsx(AlphafoldSuperpositionControls, {}), _jsx(StructureMeasurementsControls, {}), _jsx(SuperpositionModelExportUI, {}), _jsx(CustomStructureControls, {})] }); + } +} diff --git a/frontend/venome-molstar/lib/ui/pdbe-viewport-controls.d.ts b/frontend/venome-molstar/lib/ui/pdbe-viewport-controls.d.ts new file mode 100644 index 00000000..36b5ed19 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/pdbe-viewport-controls.d.ts @@ -0,0 +1,5 @@ +import { ViewportControls } from 'molstar/lib/mol-plugin-ui/viewport'; +export declare class PDBeViewportControls extends ViewportControls { + private isBlack; + render(): import("react/jsx-runtime").JSX.Element; +} diff --git a/frontend/venome-molstar/lib/ui/pdbe-viewport-controls.js b/frontend/venome-molstar/lib/ui/pdbe-viewport-controls.js new file mode 100644 index 00000000..a4d5e05d --- /dev/null +++ b/frontend/venome-molstar/lib/ui/pdbe-viewport-controls.js @@ -0,0 +1,26 @@ +import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; +import { ViewportControls } from 'molstar/lib/mol-plugin-ui/viewport'; +import { PluginCustomState } from '../plugin-custom-state'; +export class PDBeViewportControls extends ViewportControls { + isBlack() { + const bgColor = PluginCustomState(this.plugin).initParams?.bgColor; + return bgColor !== undefined && bgColor.r === 0 && bgColor.g === 0 && bgColor.b === 0; + } + render() { + const initParams = PluginCustomState(this.plugin).initParams; + const showPDBeLink = initParams?.moleculeId && initParams?.pdbeLink && !initParams?.superposition; + const pdbeLinkColor = this.isBlack() ? '#fff' : '#555'; + const pdbeLink = { + parentStyle: { width: 'auto' }, + bgStyle: { position: 'absolute', height: '27px', width: '54px', marginLeft: '-33px' }, + containerStyle: { position: 'absolute', right: '10px', top: '10px', padding: '3px 3px 3px 18px' }, + style: { display: 'inline-block', fontSize: '14px', color: pdbeLinkColor, borderBottom: 'none', cursor: 'pointer', textDecoration: 'none', position: 'absolute', right: '5px' }, + pdbeImg: { + src: 'https://www.ebi.ac.uk/pdbe/entry/static/images/logos/PDBe/logo_T_64.png', + alt: 'PDBe logo', + style: { height: '12px', width: '12px', border: 0, position: 'absolute', margin: '4px 0 0 -13px' } + } + }; + return _jsxs(_Fragment, { children: [showPDBeLink && _jsxs("div", { className: 'msp-viewport-controls-buttons', style: pdbeLink.containerStyle, children: [_jsx("div", { className: 'msp-semi-transparent-background', style: pdbeLink.bgStyle }), _jsxs("a", { className: 'msp-pdbe-link', style: pdbeLink.style, target: "_blank", href: `https://pdbe.org/${initParams.moleculeId}`, children: [_jsx("img", { src: pdbeLink.pdbeImg.src, alt: pdbeLink.pdbeImg.alt, style: pdbeLink.pdbeImg.style }), initParams.moleculeId] })] }), _jsx("div", { style: { position: 'absolute', top: showPDBeLink ? (27 + 4) : 0, right: 0 }, children: super.render() })] }); + } +} diff --git a/frontend/venome-molstar/lib/ui/segment-tree.d.ts b/frontend/venome-molstar/lib/ui/segment-tree.d.ts new file mode 100644 index 00000000..c4bfed66 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/segment-tree.d.ts @@ -0,0 +1,18 @@ +import { Mat4 } from 'molstar/lib/mol-math/linear-algebra'; +import { PluginStateObject } from 'molstar/lib/mol-plugin-state/objects'; +import { PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { StateObjectRef } from 'molstar/lib/mol-state'; +import { PluginCustomState } from '../plugin-custom-state'; +export declare class SegmentTree extends PurePluginUIComponent<{}, { + segment?: any; + isBusy: boolean; +}> { + componentDidMount(): void; + get customState(): PluginCustomState; + getSegmentParams: () => void; + updateSegment: (val: any) => Promise; + hideStructures: (segmentIndex: number) => void; + displayStructures: (segmentIndex: number) => Promise; + transform(s: StateObjectRef, matrix: Mat4): Promise; + render(): import("react/jsx-runtime").JSX.Element; +} diff --git a/frontend/venome-molstar/lib/ui/segment-tree.js b/frontend/venome-molstar/lib/ui/segment-tree.js new file mode 100644 index 00000000..c094ed56 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/segment-tree.js @@ -0,0 +1,652 @@ +import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; +import { StateTransforms } from 'molstar/lib/mol-plugin-state/transforms'; +import { PluginUIComponent, PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { Button, ExpandGroup, IconButton, SectionHeader } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { ArrowDropDownSvg, ArrowRightSvg, CheckSvg, CloseSvg, VisibilityOffOutlinedSvg, VisibilityOutlinedSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { UpdateTransformControl } from 'molstar/lib/mol-plugin-ui/state/update-transform'; +import { PluginCommands } from 'molstar/lib/mol-plugin/commands'; +import { MolScriptBuilder as MS } from 'molstar/lib/mol-script/language/builder'; +import { State, StateObjectRef, StateSelection } from 'molstar/lib/mol-state'; +import { Color } from 'molstar/lib/mol-util/color'; +import { ColorLists } from 'molstar/lib/mol-util/color/lists'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import { Subject } from 'rxjs'; +import { debounceTime, filter } from 'rxjs/operators'; +import { PluginCustomState } from '../plugin-custom-state'; +import { renderSuperposition, superposeAf } from '../superposition'; +const SuperpositionTag = 'SuperpositionTransform'; +export class SegmentTree extends PurePluginUIComponent { + componentDidMount() { + this.subscribe(PluginCustomState(this.plugin).events.superpositionInit, () => { + const customState = this.customState; + if (customState && !customState.superpositionError) { + this.getSegmentParams(); + } + this.forceUpdate(); + }); + this.subscribe(PluginCustomState(this.plugin).events.isBusy, (e) => { + this.setState({ isBusy: e }); + if (e) { + PluginCommands.Toast.Show(this.plugin, { + title: 'Process', + message: 'Loading / computing large dataset!', + key: 'is-busy-toast' + }); + } + else { + PluginCommands.Toast.Hide(this.plugin, { key: 'is-busy-toast' }); + } + }); + this.subscribe(this.plugin.behaviors.layout.leftPanelTabName, (e) => { + if (e !== 'segments') + return; + this.getSegmentParams(); + this.forceUpdate(); + }); + } + get customState() { + return PluginCustomState(this.plugin); + } + getSegmentParams = () => { + const customState = this.customState; + if (!customState.superpositionState || !customState.superpositionState.segmentData) + return; + const segmentData = customState.superpositionState.segmentData; + const segmentArr = segmentData.map((segment, i) => { + const segmentLabel = `${i + 1} ( ${segment.segment_start} - ${segment.segment_end} )`; + return [segmentLabel, segmentLabel]; + }); + const segmentOptions = { + segment: PD.Select('', segmentArr, { label: 'Select Segment', description: 'Select segment to view its clusters below' }) + }; + const segmentIndex = customState.superpositionState.activeSegment - 1; + this.setState({ + segment: { + params: segmentOptions, + value: { segment: segmentArr[segmentIndex][0] } + } + }); + this.setState({ isBusy: false }); + }; + updateSegment = async (val) => { + if (!this.state.segment) + return; + if (!this.state.segment) + return; + const customState = this.customState; + if (!customState.superpositionState) + throw new Error('customState.superpositionState has not been initialized'); + customState.events?.isBusy.next(true); + // Hide pervious segement structures + this.hideStructures(customState.superpositionState.activeSegment - 1); + // Set current segment params + const updatedParams = { ...this.state.segment }; + updatedParams.value = val; + this.setState({ segment: updatedParams }); + setTimeout(async () => { + const updatedSegmentIndex = parseInt(val.segment.split(' ')[0]); + customState.superpositionState.activeSegment = updatedSegmentIndex; + // Display current segment visible structures + await this.displayStructures(customState.superpositionState.activeSegment - 1); + customState.events?.isBusy.next(false); + customState.events?.segmentUpdate.next(true); + }, 100); + return false; + }; + hideStructures = (segmentIndex) => { + // clear selections + this.plugin.managers.interactivity.lociSelects.deselectAll(); + // clear Focus + this.plugin.managers.structure.focus.clear(); + // remove measurements + const measurements = this.plugin.managers.structure.measurement.state; + const measureTypes = ['labels', 'distances', 'angles', 'dihedrals']; + let measurementCell = void 0; + measureTypes.forEach((type) => { + if (measurementCell) + return; + if (measurements[type][0]) { + measurementCell = this.plugin.state.data.cells.get(measurements[type][0].transform.parent); + } + }); + if (measurementCell) { + PluginCommands.State.RemoveObject(this.plugin, { state: measurementCell.parent, ref: measurementCell.transform.parent, removeParentGhosts: true }); + } + // hide structures + const customState = this.customState; + if (!customState.superpositionState) + throw new Error('customState.superpositionState has not been initialized'); + customState.superpositionState.visibleRefs[segmentIndex] = []; + for (const struct of customState.superpositionState.loadedStructs[segmentIndex]) { + const structRef = customState.superpositionState.models[struct]; + if (structRef) { + const structHierarchy = this.plugin.managers.structure.hierarchy.current.refs.get(structRef); + if (structHierarchy && structHierarchy.components) { + for (const c of structHierarchy.components) { + if (c && c.cell && !c.cell.state.isHidden) { + customState.superpositionState.visibleRefs[segmentIndex].push(c.cell.transform.ref); + PluginCommands.State.ToggleVisibility(this.plugin, { state: c.cell.parent, ref: c.cell.transform.ref }); + } + } + } + } + } + if (customState.superpositionState.alphafold.ref) { + const afStr = this.plugin.managers.structure.hierarchy.current.refs.get(customState.superpositionState.alphafold.ref); + if (afStr && afStr.components) { + for (const c of afStr.components) { + if (c && c.cell && !c.cell.state.isHidden) { + PluginCommands.State.ToggleVisibility(this.plugin, { state: c.cell.parent, ref: c.cell.transform.ref }); + } + } + } + } + }; + displayStructures = async (segmentIndex) => { + const customState = this.customState; + const spState = customState.superpositionState; + if (!spState) + throw new Error('customState.superpositionState has not been initialized'); + if (spState.visibleRefs[segmentIndex].length === 0) { + const loadStrs = []; + spState.segmentData?.[segmentIndex].clusters.forEach(cluster => { + let entryList = [cluster[0]]; + if (customState.initParams?.superpositionParams?.superposeAll) { + entryList = cluster; + } + entryList.forEach((str) => { + const structStateId = `${str.pdb_id}_${str.struct_asym_id}`; + const structRef = spState.models[structStateId]; + if (structRef) { + const cell = this.plugin.state.data.cells.get(structRef); + const isHidden = cell.state.isHidden ? true : false; + if (isHidden) { + PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent, ref: structRef }); + // PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent!, ref: cell.transform.parent }); + } + } + else { + loadStrs.push(str); + } + }); + }); + PluginCommands.Camera.Reset(this.plugin); + if (loadStrs.length > 0) { + await renderSuperposition(this.plugin, segmentIndex, loadStrs); + PluginCommands.Camera.Reset(this.plugin); + } + } + else { + for (const ref of spState.visibleRefs[segmentIndex]) { + const cell = this.plugin.state.data.cells.get(ref); + if (cell && cell.state.isHidden) { + PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent, ref }); + } + } + PluginCommands.Camera.Reset(this.plugin); + } + if (spState.alphafold.ref) { + superposeAf(this.plugin, spState.alphafold.traceOnly); + PluginCommands.Camera.Reset(this.plugin); + } + if (spState.alphafold.ref && spState.alphafold.visibility[segmentIndex]) { + const afStr = this.plugin.managers.structure.hierarchy.current.refs.get(spState.alphafold.ref); + if (afStr && afStr.components) { + for (const c of afStr.components) { + if (c && c.cell && c.cell.state.isHidden) { + PluginCommands.State.ToggleVisibility(this.plugin, { state: c.cell.parent, ref: c.cell.transform.ref }); + } + } + } + } + }; + async transform(s, matrix) { + const r = StateObjectRef.resolveAndCheck(this.plugin.state.data, s); + if (!r) + return; + // TODO should find any TransformStructureConformation decorator instance + const o = StateSelection.findTagInSubtree(this.plugin.state.data.tree, r.transform.ref, SuperpositionTag); + const params = { + transform: { + name: 'matrix', + params: { data: matrix, transpose: false } + } + }; + // TODO add .insertOrUpdate to StateBuilder? + const b = o + ? this.plugin.state.data.build().to(o).update(params) + : this.plugin.state.data.build().to(s) + .insert(StateTransforms.Model.TransformStructureConformation, params, { tags: SuperpositionTag }); + await this.plugin.runTask(this.plugin.state.data.updateTree(b)); + } + render() { + let sectionHeader = _jsx(SectionHeader, { title: `Structure clusters` }); + const customState = this.customState; + if (customState && customState.initParams && !customState.initParams.superposition) { + return _jsxs(_Fragment, { children: [sectionHeader, _jsx("div", { children: "Functionality unavailable!" })] }); + } + else { + if (customState && customState.initParams && customState.initParams.superposition) { + sectionHeader = _jsx(SectionHeader, { title: `Structure clusters - ${customState.initParams.moleculeId}` }); + if (customState.superpositionError) { + return _jsxs(_Fragment, { children: [sectionHeader, _jsx("div", { style: { textAlign: 'center' }, children: customState.superpositionError })] }); + } + else if (!customState.superpositionState || !customState.superpositionState.segmentData) { + return _jsxs(_Fragment, { children: [sectionHeader, _jsx("div", { style: { textAlign: 'center' }, children: "Loading Segment Data!" })] }); + } + } + } + if (this.state) { + const segmentIndex = parseInt(this.state.segment.value.segment.split(' ')[0]) - 1; + if (!customState.superpositionState?.segmentData) + throw new Error('customState.superpositionState.segmentData has not been initialized'); + const segmentData = customState.superpositionState.segmentData; + const fullSegmentRange = `( ${segmentData[0].segment_start} - ${segmentData[segmentData.length - 1].segment_end} )`; + sectionHeader = _jsx(SectionHeader, { title: `Structure clusters ${customState.initParams.moleculeId}`, desc: fullSegmentRange }); + return _jsxs(_Fragment, { children: [sectionHeader, _jsx(ParameterControls, { params: this.state.segment.params, values: this.state.segment.value, onChangeValues: this.updateSegment, isDisabled: this.state.isBusy }), segmentData[segmentIndex].clusters.map((c, i) => _jsx(ClusterNode, { cluster: c, totalClusters: segmentData[segmentIndex].clusters.length, segmentIndex: segmentIndex, clusterIndex: i }, `cluster-${segmentIndex}-${i}`))] }); + } + return _jsx(_Fragment, {}); + } +} +class ClusterNode extends PluginUIComponent { + state = { + isCollapsed: false, + showAll: false, + showNone: false, + showSearch: false, + isBusy: false, + cluster: this.props.cluster, + searchText: '' + }; + inputStream = new Subject(); + handleInputStream = (inputStr) => { + this.setState({ searchText: inputStr }); + const filteredRes = this.props.cluster.filter((item) => { + return item.pdb_id.toLowerCase().indexOf(inputStr.toLowerCase()) >= 0; + }); + this.setState({ cluster: filteredRes }); + }; + componentDidMount() { + this.subscribe(PluginCustomState(this.plugin).events.isBusy, (e) => { + this.setState({ isBusy: e, showAll: false, showNone: false }); + }); + this.subscribe(this.inputStream.pipe(debounceTime(1000 / 24)), (e) => this.handleInputStream(e)); + } + get customState() { + return PluginCustomState(this.plugin); + } + toggleExpanded = (e) => { + e.preventDefault(); + this.setState({ isCollapsed: !this.state.isCollapsed }); + e.currentTarget.blur(); + }; + selectAll = (e) => { + e.preventDefault(); + this.setState({ showAll: !this.state.showAll, showNone: false }); + e.currentTarget.blur(); + }; + selectNone = (e) => { + e.preventDefault(); + this.setState({ showAll: false, showNone: !this.state.showNone }); + e.currentTarget.blur(); + }; + applyAction = async (e) => { + e.preventDefault(); + e.currentTarget.blur(); + const customState = this.customState; + customState.events?.isBusy.next(true); + const currentState = { ...this.state }; + this.setState({ showAll: false, showNone: false }); + setTimeout(async () => { + const loadStrs = []; + for await (const str of this.state.cluster) { + const structStateId = `${str.pdb_id}_${str.struct_asym_id}`; + let structRef = undefined; + if (customState && customState.superpositionState && customState.superpositionState.models[structStateId]) { + structRef = customState.superpositionState.models[structStateId]; + } + if (structRef) { + const cell = this.plugin.state.data.cells.get(structRef); + if (cell) { + const isHidden = cell.state.isHidden ? true : false; + if ((isHidden && currentState.showAll) || (!isHidden && currentState.showNone)) { + await PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent, ref: structRef }); + // await PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent!, ref: cell.transform.parent }); + } + } + } + else { + if (currentState.showAll) + loadStrs.push(str); + } + } + ; + PluginCommands.Camera.Reset(this.plugin); + if (loadStrs.length > 0) { + await renderSuperposition(this.plugin, this.props.segmentIndex, loadStrs); + } + customState.events?.isBusy.next(false); + }); + }; + cancelAction = (e) => { + e.preventDefault(); + this.setState({ showAll: false, showNone: false }); + e.currentTarget.blur(); + }; + clearSearch = (e) => { + e.preventDefault(); + this.setState({ searchText: '' }); + this.inputStream.next(''); + e.currentTarget.blur(); + }; + render() { + const customState = this.customState; + if (!customState.superpositionState || !customState.superpositionState.segmentData) + return _jsx(_Fragment, {}); + const expand = _jsx(IconButton, { svg: this.state.isCollapsed ? ArrowRightSvg : ArrowDropDownSvg, flex: '20px', onClick: this.toggleExpanded, transparent: true, disabled: this.state.isBusy, className: 'msp-no-hover-outline' }); + const title = `Segment ${customState.superpositionState.activeSegment} Cluster ${this.props.clusterIndex + 1}`; + const label = _jsxs(Button, { className: `msp-btn-tree-label`, noOverflow: true, title: title, disabled: this.state.isBusy, children: [_jsxs("span", { children: ["Cluster ", this.props.clusterIndex + 1] }), " ", _jsxs("small", { children: [this.state.cluster.length < this.props.cluster.length ? `${this.state.cluster.length} / ` : '', this.props.cluster.length, " chain", this.props.cluster.length > 1 ? 's' : ''] })] }); + const selectionControls = _jsxs(_Fragment, { children: [_jsx(Button, { icon: CheckSvg, flex: true, onClick: this.selectAll, style: { flex: '0 0 50px', textAlign: 'center', fontSize: '80%', color: '#9cacc3', padding: 0 }, disabled: this.state.isBusy, title: `Show all chains`, children: "All" }), _jsx(Button, { icon: CloseSvg, flex: true, onClick: this.selectNone, style: { flex: '0 0 50px', textAlign: 'center', fontSize: '80%', color: '#9cacc3', padding: 0 }, disabled: this.state.isBusy, title: `Hide all chains`, children: "None" })] }); + const mainRow = _jsxs("div", { className: `msp-flex-row msp-tree-row`, style: { marginTop: '10px' }, children: [expand, label, this.props.cluster.length > 1 && selectionControls] }); + const searchControls = _jsxs("div", { className: 'msp-mapped-parameter-group', style: { fontSize: '90%' }, children: [_jsxs("div", { className: 'msp-control-row msp-transform-header-brand-gray', style: { height: '33px', marginLeft: '30px' }, children: [_jsx("span", { className: 'msp-control-row-label', children: "Search PDB ID" }), _jsx("div", { className: 'msp-control-row-ctrl', children: _jsx("input", { type: 'text', placeholder: 'Enter PDB ID..', disabled: this.state.isBusy, onChange: e => this.inputStream.next(e.target.value), value: this.state.searchText, maxLength: 4 }) })] }), _jsx(IconButton, { svg: CloseSvg, flex: true, onClick: this.clearSearch, style: { flex: '0 0 24px', padding: 0 }, disabled: this.state.isBusy || this.state.searchText === '', toggleState: this.state.searchText !== '', title: 'Clear search input' })] }); + return _jsxs(_Fragment, { children: [mainRow, (this.state.showAll || this.state.showNone) && _jsx("div", { children: _jsxs("div", { className: `msp-control-row msp-transform-header-brand-${this.state.showAll ? 'green' : 'red'}`, style: { display: 'flex', marginLeft: '20px', height: '35px' }, children: [_jsxs("span", { className: 'msp-control-row-label', style: { flex: '1 1 auto', textAlign: 'left', fontSize: '85%' }, children: [this.state.showAll ? 'Display' : 'Hide', " ", this.state.cluster.length < this.props.cluster.length ? `${this.state.cluster.length} / ` : 'all ', this.props.cluster.length, " chains"] }), _jsx(Button, { icon: CheckSvg, flex: true, onClick: this.applyAction, style: { flex: '0 0 60px', textAlign: 'center', fontSize: '78%', color: '#9cacc3', padding: 0, margin: '0 1px' }, title: `Apply action`, children: "Apply" }), _jsx(Button, { icon: CloseSvg, flex: true, onClick: this.cancelAction, style: { flex: '0 0 60px', textAlign: 'center', fontSize: '78%', color: '#9cacc3', padding: 0, margin: '0 1px' }, title: `Cancel action`, children: "Cancel" })] }) }), (!this.state.isCollapsed && this.props.cluster.length > 5) && searchControls, !this.state.isCollapsed && _jsx("div", { className: 'msp-tree-updates-wrapper', style: { maxHeight: (this.props.totalClusters > 1) ? '330px' : '87%', overflowY: 'auto' }, children: this.state.cluster.map((s, i) => _jsx(StructureNode, { segmentIndex: this.props.segmentIndex, structure: s, isRep: i === 0 ? true : false }, `str-${s.pdb_id}${s.struct_asym_id}${i}`)) })] }); + } +} +class StructureNode extends PluginUIComponent { + state = { + showControls: false, + isBusy: false, + isProcessing: false, + isHidden: true, + }; + get customState() { + return PluginCustomState(this.plugin); + } + get ref() { + if (this.customState && this.customState.superpositionState && this.customState.superpositionState.models[`${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`]) { + return this.customState.superpositionState.models[`${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`]; + } + else { + return undefined; + } + } + get modelCell() { + if (this.ref) { + return this.plugin.state.data.cells.get(this.ref); + } + else { + return undefined; + } + } + get isAllHidden() { + let isHidden = true; + if (this.ref) { + const structHierarchy = this.plugin.managers.structure.hierarchy.current.refs.get(this.ref); + if (structHierarchy && structHierarchy.components) { + for (const c of structHierarchy.components) { + if (c && c.cell && !c.cell.state.isHidden) { + isHidden = false; + break; + } + } + } + else { + isHidden = false; + } + } + return isHidden; + } + checkRelation(ref) { + let isRelated = false; + const cell = this.plugin.state.data.cells.get(ref); + if (cell && cell.transform.parent) { + if (cell && cell.transform.parent === this.ref) { + isRelated = true; + } + else { + const pcell = this.plugin.state.data.cells.get(cell.transform.parent); + if (pcell && pcell.transform.parent === this.ref) + isRelated = true; + } + } + else { + const currentNodeCell = this.plugin.state.data.cells.get(this.ref); + if (currentNodeCell && currentNodeCell.transform.parent === cell.transform.parent) { + isRelated = true; + } + } + return isRelated; + } + is(e) { + if (!this.ref) + return false; + let isRelated = false; + if (this.ref && e.ref !== this.ref) { + isRelated = this.checkRelation(e.ref); + } + if (e.ref === this.ref || isRelated) { + return true; + } + else { + const id = `${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`; + const invalidStruct = this.customState.superpositionState?.invalidStruct.includes(id) ?? false; + return invalidStruct; + } + } + componentDidMount() { + this.setState({ isHidden: this.isAllHidden }); + this.subscribe(PluginCustomState(this.plugin).events.isBusy, (e) => { + this.setState({ isBusy: e, showControls: false }); + }); + this.subscribe(this.plugin.state.events.cell.stateUpdated.pipe(filter(e => this.is(e)), debounceTime(33)), e => { + this.setState({ isHidden: this.isAllHidden }); + // this.forceUpdate(); + }); + } + toggleVisible = async (e) => { + e.preventDefault(); + e.currentTarget.blur(); + this.setState({ isProcessing: true, showControls: false }); + if (this.ref) { + const structHierarchy = this.plugin.managers.structure.hierarchy.current.refs.get(this.ref); + if (structHierarchy && structHierarchy.components) { + for (const c of structHierarchy.components) { + const currentHiddenState = c.cell.state.isHidden ? true : false; + if (currentHiddenState === this.state.isHidden) { + PluginCommands.State.ToggleVisibility(this.plugin, { state: c.cell.parent, ref: c.cell.transform.ref }); + } + } + this.setState({ isHidden: !this.state.isHidden }); + } + } + else { + await renderSuperposition(this.plugin, this.props.segmentIndex, [this.props.structure]); + } + this.setState({ isProcessing: false }); + PluginCommands.Camera.Reset(this.plugin); + }; + selectAction = item => { + if (!item) + return; + this.setState({ showControls: false }); + (item?.value)(); + }; + getTagRefs(tags) { + const TagSet = new Set(tags); + const tree = this.plugin.state.data.tree; + return StateSelection.findUniqueTagsInSubtree(tree, this.modelCell.transform.ref, TagSet); + } + ; + getRandomColor() { + const clList = ColorLists; + const spState = PluginCustomState(this.plugin).superpositionState; + if (!spState) + throw new Error('customState.superpositionState has not been initialized'); + let palleteIndex = spState.colorState[this.props.segmentIndex].palleteIndex; + let colorIndex = spState.colorState[this.props.segmentIndex].colorIndex; + if (clList[spState.colorPalette[palleteIndex]].list[colorIndex + 1]) { + colorIndex += 1; + } + else { + colorIndex = 0; + palleteIndex = spState.colorPalette[palleteIndex + 1] ? palleteIndex + 1 : 0; + } + const palleteName = spState.colorPalette[palleteIndex]; + spState.colorState[this.props.segmentIndex].palleteIndex = palleteIndex; + spState.colorState[this.props.segmentIndex].colorIndex = colorIndex; + return clList[palleteName].list[colorIndex]; + } + async addChainRepr() { + const uniformColor1 = this.getRandomColor(); + const strInstance = this.plugin.state.data.select(this.ref)[0]; + const query = MS.struct.generator.atomGroups({ + 'chain-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_asym_id(), this.props.structure.struct_asym_id]) + }); + const chainSel = await this.plugin.builders.structure.tryCreateComponentFromExpression(strInstance, query, `Chain-${this.props.segmentIndex}`, { label: `Chain`, tags: [`superposition-sel`] }); + if (chainSel) { + await this.plugin.builders.structure.representation.addRepresentation(chainSel, { type: 'cartoon', color: 'uniform', colorParams: { value: uniformColor1 } }, { tag: `superposition-visual` }); + } + } + updates() { + const structHierarchy = this.plugin.managers.structure.hierarchy.current.refs.get(this.ref); + if (structHierarchy && structHierarchy.components) { + const representations = []; + let showAddChainBtn = true; + structHierarchy.components.forEach((comps) => { + const gKeys = comps.key.split(','); + const cId1Arr = gKeys[0].split('-'); + if (cId1Arr[2] === 'Chain') + showAddChainBtn = false; + if (comps.representations) { + comps.representations.forEach((repr) => { + representations.push(repr); + }); + } + }); + const customState = PluginCustomState(this.plugin); + if (customState.initParams?.superpositionParams && !customState.initParams.superpositionParams.ligandView) { + showAddChainBtn = false; + } + if (representations.length > 0) { + return _jsxs("div", { className: 'msp-accent-offset', style: { marginLeft: '40px' }, children: [representations.length > 0 && representations.map((r, i) => _jsx(StructureRepresentationEntry, { group: [structHierarchy], representation: r }, `${r.cell.transform.ref}-${i}`)), showAddChainBtn && _jsx("div", { className: 'msp-control-group-header', style: { marginTop: '1px' }, children: _jsxs(Button, { noOverflow: true, className: 'msp-control-button-label', title: `Click to add chain representaion`, onClick: () => this.addChainRepr(), children: ["\u00A0\u00A0Add Chain ", this.props.structure.struct_asym_id, " Representation"] }) })] }); + } + } + return _jsx(_Fragment, {}); + } + highlight = (e) => { + e.preventDefault(); + if (this.ref) { + const cell = this.plugin.state.data.cells.get(this.ref); + PluginCommands.Interactivity.Object.Highlight(this.plugin, { state: cell.parent, ref: this.ref }); + } + e.currentTarget.blur(); + }; + clearHighlight = (e) => { + e.preventDefault(); + PluginCommands.Interactivity.ClearHighlights(this.plugin); + e.currentTarget.blur(); + }; + toggleControls = (e) => { + e.preventDefault(); + this.setState({ showControls: !this.state.showControls }); + e.currentTarget.blur(); + }; + getSubtitle() { + if (!this.customState.superpositionState) + throw new Error('customState.superpositionState has not been initialized'); + const hetList = this.customState.superpositionState.hets[`${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`]; + let subtitle; + if (hetList) { + const hetLimit = this.props.structure.is_representative ? 1 : 4; + const totalHets = hetList.length; + let hetStr = hetList.join(', '); + if (totalHets > hetLimit) { + hetStr = hetList.slice(0, hetLimit).join(', '); + hetStr += ` + ${totalHets - hetLimit}`; + } + subtitle = ` ( ${hetStr} )`; + if (this.props.structure.is_representative) + subtitle = ` ${subtitle} ( Representative )`; + } + else if (this.props.structure.is_representative) { + subtitle = ' ( Representative )'; + } + return subtitle; + } + get panelColor() { + let panelColor = '#808080'; + if (!this.state.isHidden) { + if (this.modelCell) { + const refs = this.getTagRefs([`superposition-visual`, `superposition-ligand-visual`]); + const visualRef = refs[`superposition-ligand-visual`] ? refs[`superposition-ligand-visual`] : refs[`superposition-visual`] ? refs[`superposition-visual`] : undefined; + if (visualRef) { + const visualCell = this.plugin.state.data.cells.get(visualRef); + if (visualCell.params && visualCell.params.values && visualCell.params.values.colorTheme) { + const colorTheme = visualCell.params.values.colorTheme; + if (colorTheme.params && colorTheme.params.value) { + panelColor = `${Color.toStyle(colorTheme.params.value)}`; + } + else if (colorTheme.params && colorTheme.params.palette) { + const colorList1 = colorTheme.params.palette.params.list.colors; + panelColor = `${Color.toStyle(colorList1[0])}`; + } + else if (colorTheme.params && colorTheme.params.list) { + const colorList2 = colorTheme.params.list.colors; + panelColor = `${Color.toStyle(colorList2[0])}`; + } + } + } + } + } + return panelColor; + } + render() { + const superpositionParams = this.customState.initParams.superpositionParams; + const strutStateId = `${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`; + const invalidStruct = this.customState.superpositionState?.invalidStruct.includes(strutStateId); + const noMatrixStruct = this.customState.superpositionState?.noMatrixStruct.includes(strutStateId); + const subTitle = invalidStruct ? noMatrixStruct ? ` Matrix not available!` : ` No Ligand found!` : this.getSubtitle(); + let strTitle = `${this.props.structure.pdb_id} chain ${this.props.structure.auth_asym_id}`; + if (superpositionParams && superpositionParams.ligandView) { + strTitle = `${this.props.structure.pdb_id} ${this.props.structure.struct_asym_id}`; + } + const label = _jsxs(Button, { className: `msp-btn-tree-label`, style: { borderLeftColor: this.panelColor }, noOverflow: true, title: strTitle, disabled: (invalidStruct || this.state.isBusy || this.state.isProcessing) ? true : false, onMouseEnter: this.highlight, onMouseLeave: this.clearHighlight, children: [_jsx("span", { children: strTitle }), subTitle && _jsx("small", { children: subTitle })] }); + const expand = _jsx(IconButton, { svg: !this.state.showControls ? ArrowRightSvg : ArrowDropDownSvg, flex: '20px', onClick: this.toggleControls, transparent: true, className: 'msp-no-hover-outline', disabled: (invalidStruct || this.state.isBusy || this.state.isProcessing) ? true : false }); + const visibility = _jsx(IconButton, { svg: this.state.isHidden ? VisibilityOffOutlinedSvg : VisibilityOutlinedSvg, toggleState: false, small: true, onClick: this.toggleVisible, disabled: (invalidStruct || this.state.isBusy || this.state.isProcessing) ? true : false, title: this.state.isHidden ? `Show chain` : `Hide chain` }); + const row = _jsxs("div", { className: `msp-flex-row msp-tree-row`, style: { marginLeft: !this.state.isHidden ? '10px' : '31px' }, children: [!this.state.isHidden && expand, label, visibility] }); + return _jsxs("div", { style: { marginBottom: '1px' }, children: [row, this.state.showControls && this.updates()] }); + } +} +class StructureRepresentationEntry extends PurePluginUIComponent { + componentDidMount() { + this.subscribe(this.plugin.state.events.cell.stateUpdated, e => { + if (State.ObjectEvent.isCell(e, this.props.representation.cell)) + this.forceUpdate(); + }); + } + toggleVisible = (e) => { + e.preventDefault(); + e.currentTarget.blur(); + const cell = this.props.representation.cell; + PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent, ref: cell.transform.parent }); + }; + render() { + const repr = this.props.representation.cell; + let label = repr.obj?.label; + if (repr.obj?.data.repr && repr.obj?.data.repr.label) { + let sourceLabel = (repr.obj?.data.repr.label.indexOf('[Focus]') >= 0) ? '[Focus]' : repr.obj?.data.repr.label; + const isLargeLabel = sourceLabel.length > 10 ? true : false; + sourceLabel = `${isLargeLabel ? `${sourceLabel.substring(0, 28)}...` : sourceLabel}`; + if (isLargeLabel) { + label = sourceLabel; + } + else { + label = `${sourceLabel} ${(label && label.length < 21) ? ' - ' + label : ''}`; + } + } + if (repr.obj?.data.repr && repr.obj?.data.repr.label === 'Custom Selection') + label = 'Custom Selection'; + return _jsxs("div", { className: 'msp-representation-entry', children: [repr.parent && _jsx(ExpandGroup, { header: `${label || 'Representation'}`, noOffset: true, headerStyle: { overflow: 'hidden' }, children: _jsx(UpdateTransformControl, { state: repr.parent, transform: repr.transform, customHeader: 'none', noMargin: true }) }), _jsx(IconButton, { svg: this.props.representation.cell.state.isHidden ? VisibilityOffOutlinedSvg : VisibilityOutlinedSvg, toggleState: false, onClick: this.toggleVisible, title: this.props.representation.cell.state.isHidden ? `Show representation` : `Hide representation`, small: true, className: 'msp-default-bg', style: { position: 'absolute', top: 0, right: 0, lineHeight: '24px', height: '24px', textAlign: 'right', width: '32px', paddingRight: '6px', background: 'none' } })] }); + } +} diff --git a/frontend/venome-molstar/lib/ui/superposition-components.d.ts b/frontend/venome-molstar/lib/ui/superposition-components.d.ts new file mode 100644 index 00000000..6a43f431 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/superposition-components.d.ts @@ -0,0 +1,9 @@ +import { CollapsableControls, CollapsableState } from 'molstar/lib/mol-plugin-ui/base'; +interface StructureComponentControlState extends CollapsableState { + isDisabled: boolean; +} +export declare class SuperpositionComponentControls extends CollapsableControls<{}, StructureComponentControlState> { + protected defaultState(): StructureComponentControlState; + renderControls(): import("react/jsx-runtime").JSX.Element; +} +export {}; diff --git a/frontend/venome-molstar/lib/ui/superposition-components.js b/frontend/venome-molstar/lib/ui/superposition-components.js new file mode 100644 index 00000000..53d16d8e --- /dev/null +++ b/frontend/venome-molstar/lib/ui/superposition-components.js @@ -0,0 +1,364 @@ +import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; +import { PluginCommands } from 'molstar/lib/mol-plugin/commands'; +import { State } from 'molstar/lib/mol-state'; +import { ParamDefinition } from 'molstar/lib/mol-util/param-definition'; +import { CollapsableControls, PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { Button, IconButton } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { CubeOutlineSvg, VisibilityOffOutlinedSvg, VisibilityOutlinedSvg, MoreHorizSvg, CheckSvg, CloseSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { debounceTime } from 'rxjs/operators'; +import { Subject } from 'rxjs'; +import { PluginCustomState } from '../plugin-custom-state'; +export class SuperpositionComponentControls extends CollapsableControls { + defaultState() { + return { + header: 'Components', + isCollapsed: false, + isDisabled: false, + brand: { accent: 'blue', svg: CubeOutlineSvg } + }; + } + renderControls() { + return _jsx(_Fragment, { children: _jsx(ComponentListControls, {}) }); + } +} +; +class ComponentListControls extends PurePluginUIComponent { + state = { + segmentWatch: false, + ligSearchText: '', + carbSearchText: '', + componentGroups: { nonLigGroups: [], ligGroups: [], carbGroups: [], alphafold: [] }, + ligGroups: [], + isLigCollapsed: false, + carbGroups: [], + isCarbCollapsed: false, + isBusy: false + }; + ligInputStream = new Subject(); + handleLigInputStream = (inputStr) => { + this.setState({ ligSearchText: inputStr }); + const filteredRes = this.state.componentGroups.ligGroups.filter((g) => { + const gKeys = g[0].key.split(','); + const cId1Arr = gKeys[0].split('-'); + return cId1Arr[2].toLowerCase().indexOf(inputStr.toLowerCase()) >= 0; + }); + this.setState({ ligGroups: filteredRes }); + }; + carbInputStream = new Subject(); + handleCarbInputStream = (inputStr) => { + this.setState({ carbSearchText: inputStr }); + const filteredRes = this.state.componentGroups.carbGroups.filter((g) => { + const gKeys = g[0].key.split(','); + const cId1Arr = gKeys[0].split('-'); + cId1Arr.splice(0, 2); + cId1Arr.pop(); + return cId1Arr.join('-').toLowerCase().indexOf(inputStr.toLowerCase()) >= 0; + }); + this.setState({ carbGroups: filteredRes }); + }; + componentDidMount() { + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, () => { + this.categoriseGroups(); + this.forceUpdate(); + }); + this.subscribe(this.plugin.behaviors.state.isBusy, v => { + this.setState({ isBusy: v }); + }); + } + componentDidUpdate() { + const customState = PluginCustomState(this.plugin); + if (customState.events && !this.state.segmentWatch) { + this.setState({ segmentWatch: true }); + this.subscribe(customState.events.segmentUpdate, () => { + this.categoriseGroups(); + this.forceUpdate(); + }); + } + this.subscribe(this.ligInputStream.pipe(debounceTime(1000 / 24)), e => this.handleLigInputStream(e)); + this.subscribe(this.carbInputStream.pipe(debounceTime(1000 / 24)), e => this.handleCarbInputStream(e)); + } + categoriseGroups() { + const componentGroupsVal = { nonLigGroups: [], ligGroups: [], carbGroups: [], alphafold: [] }; + const componentGroups = this.plugin.managers.structure.hierarchy.currentComponentGroups; + const customState = PluginCustomState(this.plugin); + componentGroups.forEach((g) => { + const superpositionState = customState.superpositionState; + if (!superpositionState) + throw new Error('customState.superpositionState has not been initialized'); + let isLigandView = false; + if (customState.initParams && customState.initParams.superpositionParams && customState.initParams.superpositionParams.ligandView) { + isLigandView = true; + } + if (isLigandView) { + const gKeys = g[0].key.split(','); + const cId1Arr = gKeys[0].split('-'); + if (gKeys.indexOf('superposition-focus-surr-sel') === -1) { + if (cId1Arr[cId1Arr.length - 1] !== (superpositionState.activeSegment - 1) + '') + return; + if (gKeys.indexOf('superposition-ligand-sel') >= 0) { + componentGroupsVal.ligGroups.push(g); + } + else if (gKeys.indexOf('superposition-carb-sel') >= 0) { + componentGroupsVal.carbGroups.push(g); + } + else if (gKeys.indexOf('alphafold-chain') >= 0) { + componentGroupsVal.alphafold.push(g); + } + else { + componentGroupsVal.nonLigGroups.push(g); + } + } + else { + componentGroupsVal.nonLigGroups.push(g); + } + } + else { + const gKeys = g[0].key.split(','); + if (gKeys.indexOf('superposition-focus-surr-sel') >= 0 || gKeys.indexOf(`Chain-${superpositionState.activeSegment - 1}`) >= 0) { + componentGroupsVal.nonLigGroups.push(g); + } + else if (gKeys.indexOf('alphafold-chain') >= 0) { + componentGroupsVal.alphafold.push(g); + } + } + }); + this.setState({ componentGroups: componentGroupsVal, ligGroups: componentGroupsVal.ligGroups, carbGroups: componentGroupsVal.carbGroups, ligSearchText: '', carbSearchText: '' }); + } + toggleVisible = (e, action, type) => { + e.preventDefault(); + e.currentTarget.blur(); + const customState = PluginCustomState(this.plugin); + customState.events?.isBusy.next(true); + const visualEntites = (type === 'ligands') ? this.state.ligGroups : this.state.carbGroups; + setTimeout(async () => { + for await (const visualEntity of visualEntites) { + this.plugin.managers.structure.hierarchy.toggleVisibility(visualEntity, action); + } + ; + customState.events?.isBusy.next(false); + }); + }; + showHideAllControls = (type) => { + return _jsxs(_Fragment, { children: [_jsx(Button, { icon: CheckSvg, flex: true, onClick: (e) => this.toggleVisible(e, 'show', type), style: { flex: '0 0 50px', textAlign: 'center', fontSize: '80%', color: '#9cacc3', padding: 0 }, title: `Show all ${type}`, disabled: false, children: "All" }), _jsx(Button, { icon: CloseSvg, flex: true, onClick: (e) => this.toggleVisible(e, 'hide', type), style: { flex: '0 0 50px', textAlign: 'center', fontSize: '80%', color: '#9cacc3', padding: 0 }, title: `Hide all ${type}`, disabled: false, children: "None" })] }); + }; + clearLigSearch = (e) => { + e.preventDefault(); + this.setState({ ligSearchText: '' }); + this.ligInputStream.next(''); + e.currentTarget.blur(); + }; + clearCarbSearch = (e) => { + e.preventDefault(); + this.setState({ carbSearchText: '' }); + this.carbInputStream.next(''); + e.currentTarget.blur(); + }; + collapseSection = (e, type) => { + e.preventDefault(); + e.currentTarget.blur(); + if (type === 'ligands') { + this.setState({ isLigCollapsed: !this.state.isLigCollapsed }); + } + else { + this.setState({ isCarbCollapsed: !this.state.isCarbCollapsed }); + } + }; + sectionHeader = (type) => { + const showHideAllControls = (type === 'ligands') ? this.showHideAllControls('ligands') : this.showHideAllControls('carbohydrates'); + const title = (type === 'ligands') ? 'Ligand' : 'Carbohydrates'; + const visibleVisuals = (type === 'ligands') ? this.state.ligGroups.length : this.state.carbGroups.length; + const totalVisuals = (type === 'ligands') ? this.state.componentGroups.ligGroups.length : this.state.componentGroups.carbGroups.length; + return _jsxs("div", { className: 'msp-flex-row', style: { marginTop: '6px' }, children: [_jsxs("button", { className: 'msp-form-control msp-control-button-label msp-transform-header-brand-gray', style: { textAlign: 'left' }, onClick: (e) => this.collapseSection(e, type), children: [_jsx("span", { children: _jsx("strong", { children: title }) }), _jsxs("small", { style: { color: '#7d91b0' }, children: [" ( ", visibleVisuals, visibleVisuals < totalVisuals ? ` / ${totalVisuals}` : '', " )"] })] }), visibleVisuals > 1 && showHideAllControls] }); + }; + render() { + const ligSearchControls = _jsxs("div", { className: 'msp-mapped-parameter-group', style: { fontSize: '90%' }, children: [_jsxs("div", { className: 'msp-control-row msp-transform-header-brand-gray', style: { height: '33px' }, children: [_jsx("span", { className: 'msp-control-row-label', children: "Search Ligand" }), _jsx("div", { className: 'msp-control-row-ctrl', children: _jsx("input", { type: 'text', placeholder: 'Enter HET code', disabled: this.state.isBusy, onChange: e => this.ligInputStream.next(e.target.value), value: this.state.ligSearchText, maxLength: 3 }) })] }), _jsx(IconButton, { svg: CloseSvg, flex: true, onClick: this.clearLigSearch, style: { flex: '0 0 24px', padding: 0 }, disabled: this.state.ligSearchText === '' || this.state.isBusy, toggleState: this.state.ligSearchText !== '', title: 'Clear search input' })] }); + const carbSearchControls = _jsxs("div", { className: 'msp-mapped-parameter-group', style: { fontSize: '90%' }, children: [_jsxs("div", { className: 'msp-control-row msp-transform-header-brand-gray', style: { height: '33px' }, children: [_jsx("span", { className: 'msp-control-row-label', children: "Search Carbohydrate" }), _jsx("div", { className: 'msp-control-row-ctrl', children: _jsx("input", { type: 'text', placeholder: 'Enter HET code', disabled: this.state.isBusy, onChange: e => this.carbInputStream.next(e.target.value), value: this.state.carbSearchText, maxLength: 3 }) })] }), _jsx(IconButton, { svg: CloseSvg, flex: true, onClick: this.clearCarbSearch, style: { flex: '0 0 24px', padding: 0 }, disabled: this.state.carbSearchText === '' || this.state.isBusy, toggleState: this.state.carbSearchText !== '', title: 'Clear search input' })] }); + const ligSectionHeader = this.sectionHeader('ligands'); + const carbSectionHeader = this.sectionHeader('carbohydrates'); + return _jsxs(_Fragment, { children: [(this.state.componentGroups.nonLigGroups.length > 0) && _jsx("div", { children: this.state.componentGroups.nonLigGroups.map((g) => _jsx(StructureComponentGroup, { group: g, boldHeader: true }, g[0].cell.transform.ref)) }), (this.state.componentGroups.alphafold.length > 0) && _jsx("div", { children: this.state.componentGroups.alphafold.map((g) => _jsx(StructureComponentGroup, { group: g, boldHeader: true, type: 'alphafold' }, g[0].cell.transform.ref)) }), (this.state.componentGroups.ligGroups.length > 0) && ligSectionHeader, (!this.state.isLigCollapsed && this.state.componentGroups.ligGroups.length > 5) && ligSearchControls, (this.state.componentGroups.ligGroups.length > 0) && _jsx("div", { className: 'msp-control-offset', style: { maxHeight: '800px', overflowY: 'auto' }, children: !this.state.isLigCollapsed && this.state.ligGroups.map((g) => _jsx(StructureComponentGroup, { group: g, boldHeader: false }, g[0].cell.transform.ref)) }), (this.state.componentGroups.carbGroups.length > 0) && carbSectionHeader, (!this.state.isCarbCollapsed && this.state.componentGroups.carbGroups.length > 5) && carbSearchControls, (this.state.componentGroups.carbGroups.length > 0) && _jsx("div", { className: 'msp-control-offset', style: { maxHeight: '800px', overflowY: 'auto' }, children: !this.state.isCarbCollapsed && this.state.carbGroups.map((g) => _jsx(StructureComponentGroup, { group: g, boldHeader: false }, g[0].cell.transform.ref)) })] }); + } +} +class StructureComponentGroup extends PurePluginUIComponent { + state = { + action: void 0, + isHidden: false, + isBusy: false + }; + get pivot() { + return this.props.group[0]; + } + checkAllHidden = async () => { + let allHidden = true; + for (const c of this.props.group) { + if (!c.cell.state.isHidden) { + allHidden = false; + break; + } + } + if (allHidden) + this.setState({ isHidden: true }); + }; + componentDidMount() { + this.checkAllHidden(); + this.subscribe(this.plugin.state.events.cell.stateUpdated, e => { + // if (State.ObjectEvent.isCell(e, this.pivot.cell)) this.forceUpdate(); + if (this.pivot.cell.obj?.label === e.cell.obj?.label) { + if (!e.cell.state.isHidden) { + this.setState({ isHidden: false }); + } + else { + this.checkAllHidden(); + } + } + }); + this.subscribe(this.plugin.behaviors.state.isBusy, v => { + this.setState({ isBusy: v }); + }); + this.subscribe(PluginCustomState(this.plugin).events.isBusy, (e) => { + this.setState({ isBusy: e }); + }); + } + toggleVisible = (e) => { + e.preventDefault(); + e.currentTarget.blur(); + this.plugin.managers.structure.component.toggleVisibility(this.props.group); + this.setState({ isHidden: !this.state.isHidden }); + if (this.props.type === 'alphafold') { + const spState = PluginCustomState(this.plugin).superpositionState; + if (!spState) + throw new Error('customState.superpositionState has not been initialized'); + spState.alphafold.visibility[spState.activeSegment - 1] = this.state.isHidden; + } + }; + toggleAction = () => this.setState({ action: this.state.action === 'action' ? void 0 : 'action' }); + highlight = (e) => { + e.preventDefault(); + if (!this.props.group[0].cell.parent) + return; + PluginCommands.Interactivity.Object.Highlight(this.plugin, { state: this.props.group[0].cell.parent, ref: this.props.group.map(c => c.cell.transform.ref) }); + }; + clearHighlight = (e) => { + e.preventDefault(); + PluginCommands.Interactivity.ClearHighlights(this.plugin); + }; + focus = () => { + let allHidden = true; + for (const c of this.props.group) { + if (!c.cell.state.isHidden) { + allHidden = false; + break; + } + } + if (allHidden) { + this.plugin.managers.structure.hierarchy.toggleVisibility(this.props.group, 'show'); + } + this.plugin.managers.camera.focusSpheres(this.props.group, e => { + if (e.cell.state.isHidden) + return; + return e.cell.obj?.data.boundary.sphere; + }); + }; + render() { + const component = this.pivot; + const cell = component.cell; + const label = cell.obj?.label; + const labelEle = this.props.boldHeader ? _jsx("strong", { children: label }) : label; + return _jsxs(_Fragment, { children: [_jsxs("div", { className: 'msp-flex-row', children: [_jsx(Button, { noOverflow: true, className: 'msp-control-button-label', title: `${label} - Click to focus.`, onClick: this.focus, style: { textAlign: 'left' }, disabled: this.state.isBusy, children: labelEle }), _jsx(IconButton, { disabled: this.state.isBusy, svg: this.state.isHidden ? VisibilityOffOutlinedSvg : VisibilityOutlinedSvg, toggleState: false, onClick: this.toggleVisible, title: `${this.state.isHidden ? 'Show' : 'Hide'} component`, small: true, className: 'msp-form-control', flex: true }), _jsx(IconButton, { disabled: this.state.isBusy, svg: MoreHorizSvg, onClick: this.toggleAction, title: 'Actions', toggleState: this.state.action === 'action', className: 'msp-form-control', flex: true })] }), this.state.action === 'action' && _jsx("div", { className: 'msp-accent-offset', children: _jsx("div", { style: { marginBottom: '6px' }, children: component.representations.map(r => _jsx(StructureRepresentationEntry, { group: this.props.group, representation: r }, r.cell.transform.ref)) }) })] }); + } +} +class StructureRepresentationEntry extends PurePluginUIComponent { + state = { + isBusy: false, + clusterVal: { cluster: 'All' } + }; + remove = () => this.plugin.managers.structure.component.removeRepresentations(this.props.group, this.props.representation); + toggleVisible = (e) => { + e.preventDefault(); + e.currentTarget.blur(); + this.plugin.managers.structure.component.toggleVisibility(this.props.group, this.props.representation); + }; + componentDidMount() { + this.subscribe(this.plugin.state.events.cell.stateUpdated, e => { + if (State.ObjectEvent.isCell(e, this.props.representation.cell)) + this.forceUpdate(); + }); + this.subscribe(this.plugin.behaviors.state.isBusy, v => { + this.setState({ isBusy: v }); + }); + this.subscribe(PluginCustomState(this.plugin).events.isBusy, (e) => { + this.setState({ isBusy: e }); + }); + } + updateRepresentations(components, pivot, params) { + if (components.length === 0) + return Promise.resolve(); + const index = components[0].representations.indexOf(pivot); + if (index < 0) + return Promise.resolve(); + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (!superpositionState) + throw new Error('customState.superpositionState has not been initialized'); + let filteredComps = []; + if (this.state.clusterVal.cluster !== 'All') { + if (!superpositionState.segmentData) + throw new Error('customState.superpositionState.segmentData has not been initialized'); + const clusterData = superpositionState.segmentData[superpositionState.activeSegment - 1].clusters[parseInt(this.state.clusterVal.cluster) - 1]; + filteredComps = clusterData.map((s) => { + return `${s.pdb_id}_${s.struct_asym_id}`; + }); + if (filteredComps.length === 0) + return; + } + const update = this.plugin.state.data.build(); + for (const c of components) { + // TODO: is it ok to use just the index here? Could possible lead to ugly edge cases, but perhaps not worth the trouble to "fix". + const repr = c.representations[index]; + if (!repr) + continue; + if (repr.cell.transform.transformer !== pivot.cell.transform.transformer) + continue; + if (this.state.clusterVal.cluster !== 'All') { + const rmIndex = filteredComps.indexOf(superpositionState.refMaps[repr.cell.transform.parent]); + if (rmIndex === -1) + continue; + } + const updatedParams = { + type: params.type ? params.type : repr.cell.params?.values.type, + colorTheme: params.colorTheme ? params.colorTheme : repr.cell.params?.values.colorTheme, + sizeTheme: params.sizeTheme ? params.sizeTheme : repr.cell.params?.values.sizeTheme + }; + update.to(repr.cell).update(updatedParams); + } + return update.commit({ canUndo: 'Update Representation' }); + } + update = (params) => { + return this.updateRepresentations(this.props.group, this.props.representation, params); + }; + selectCluster = (params) => { + this.setState({ clusterVal: { cluster: params.cluster } }); + }; + render() { + const repr = this.props.representation.cell; + const superpositionState = PluginCustomState(this.plugin).superpositionState; + const clusterSelectArr = [['All', 'All']]; + if (!superpositionState?.segmentData) + throw new Error('customState.superpositionState.segmentData has not been initialized'); + superpositionState.segmentData[superpositionState.activeSegment - 1].clusters.forEach((c, i) => { + clusterSelectArr.push([(i + 1) + '', (i + 1) + '']); + }); + const clusterOptions = { + cluster: ParamDefinition.Select('All', clusterSelectArr, { label: 'Select Cluster' }) + }; + let isSurrVisual = false; + let isAlphafold = false; + if (repr && repr.obj) { + const reprObj = repr.obj; + if (reprObj.tags && reprObj.tags.indexOf('superposition-focus-surr-repr') >= 0) + isSurrVisual = true; + if (reprObj.tags && reprObj.tags.indexOf('af-superposition-visual') >= 0) + isAlphafold = true; + } + return _jsx("div", { className: 'msp-representation-entry', children: repr.parent && _jsxs("div", { children: [(clusterSelectArr.length > 2 && !isSurrVisual && !isAlphafold) && _jsx("div", { className: 'msp-representation-entry', children: _jsx(ParameterControls, { params: clusterOptions, values: this.state.clusterVal, onChangeValues: this.selectCluster, isDisabled: this.state.isBusy }) }), _jsx("div", { className: 'msp-representation-entry', children: _jsx(ParameterControls, { params: { type: repr.params?.definition.type }, values: { type: repr.params?.values.type }, onChangeValues: this.update, isDisabled: this.state.isBusy }) }), _jsx("div", { className: 'msp-representation-entry', children: _jsx(ParameterControls, { params: { colorTheme: repr.params?.definition.colorTheme }, values: { colorTheme: repr.params?.values.colorTheme }, onChangeValues: this.update, isDisabled: this.state.isBusy }) }), _jsx("div", { className: 'msp-representation-entry', children: _jsx(ParameterControls, { params: { sizeTheme: repr.params?.definition.sizeTheme }, values: { sizeTheme: repr.params?.values.sizeTheme }, onChangeValues: this.update, isDisabled: this.state.isBusy }) })] }) }); + } +} diff --git a/frontend/venome-molstar/lib/ui/superposition-viewport.d.ts b/frontend/venome-molstar/lib/ui/superposition-viewport.d.ts new file mode 100644 index 00000000..44faa1bf --- /dev/null +++ b/frontend/venome-molstar/lib/ui/superposition-viewport.d.ts @@ -0,0 +1,4 @@ +import { PluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +export declare class SuperpostionViewport extends PluginUIComponent { + render(): import("react/jsx-runtime").JSX.Element; +} diff --git a/frontend/venome-molstar/lib/ui/superposition-viewport.js b/frontend/venome-molstar/lib/ui/superposition-viewport.js new file mode 100644 index 00000000..d5e761da --- /dev/null +++ b/frontend/venome-molstar/lib/ui/superposition-viewport.js @@ -0,0 +1,12 @@ +import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; +import { PluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { LociLabels, StateSnapshotViewportControls, SelectionViewportControls } from 'molstar/lib/mol-plugin-ui/controls'; +import { BackgroundTaskProgress } from 'molstar/lib/mol-plugin-ui/task'; +import { Toasts } from 'molstar/lib/mol-plugin-ui/toast'; +import { Viewport, ViewportControls } from 'molstar/lib/mol-plugin-ui/viewport'; +export class SuperpostionViewport extends PluginUIComponent { + render() { + const VPControls = this.plugin.spec.components?.viewport?.controls || ViewportControls; + return _jsxs(_Fragment, { children: [_jsx(Viewport, {}), _jsx("div", { className: 'msp-viewport-top-left-controls', children: _jsx(StateSnapshotViewportControls, {}) }), _jsx(SelectionViewportControls, {}), _jsx(VPControls, {}), _jsx(BackgroundTaskProgress, {}), _jsxs("div", { className: 'msp-highlight-toast-wrapper', children: [_jsx(LociLabels, {}), _jsx(Toasts, {})] })] }); + } +} diff --git a/frontend/venome-molstar/lib/ui/symmetry-annotation-controls.d.ts b/frontend/venome-molstar/lib/ui/symmetry-annotation-controls.d.ts new file mode 100644 index 00000000..e934934a --- /dev/null +++ b/frontend/venome-molstar/lib/ui/symmetry-annotation-controls.d.ts @@ -0,0 +1,46 @@ +import { AssemblySymmetryParams, AssemblySymmetryProps } from 'molstar/lib/extensions/rcsb/assembly-symmetry/prop'; +import { StructureRef } from 'molstar/lib/mol-plugin-state/manager/structure/hierarchy-state'; +import { PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { PluginContext } from 'molstar/lib/mol-plugin/context'; +import { UUID } from 'molstar/lib/mol-util'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +type SymmetryParams = { + /** State of the visibility button */ + on: PD.BooleanParam; + /** Index of the currently selected symmetry (in case there a more symmetries for an assembly), regardless of whether visibility is on of off */ + symmetryIndex: PD.Select; + /** `true` if symmetry data have been retrieved but do not contain any non-trivial symmetry */ + noSymmetries: PD.BooleanParam; +}; +type SymmetryParamValues = PD.ValuesFor; +interface SymmetryControlsState { + params: SymmetryParams; + values: SymmetryParamValues; +} +/** UI controls for showing Assembly Symmetry annotations (a row within Annotations section) */ +export declare class SymmetryAnnotationControls extends PurePluginUIComponent<{}, SymmetryControlsState> { + state: SymmetryControlsState; + currentStructureId: UUID | undefined; + componentDidMount(): void; + /** Synchronize parameters and values in UI with real parameters currently applied in `AssemblySymmetryProvider` */ + syncParams(): void; + /** Return `true` if symmetry data have been retrieved and do not contain any non-trivial symmetry. */ + noSymmetriesAvailable(): boolean; + /** Get the first loaded structure, if any. */ + getPivotStructure(): StructureRef | undefined; + /** Get parameters currently applied in `AssemblySymmetryProvider` */ + getRealParams(): AssemblySymmetryParams; + /** Get parameter values currently applied in `AssemblySymmetryProvider` */ + getRealValues(): AssemblySymmetryProps; + /** Return `true` if an `AssemblySymmetry3D` node existing in the */ + hasAssemblySymmetry3D(): boolean; + /** Run changes needed to set visibility on or off, and set UI accordingly */ + apply(applied: boolean): Promise; + /** Run changes needed to change parameter values, and set UI accordingly*/ + changeParamValues(values: SymmetryParamValues): Promise; + /** Try to retrieve symmetry data and create `AssemblySymmetry3D` representation */ + initSymmetry(initialSymmetryIndex?: number): Promise; + render(): import("react/jsx-runtime").JSX.Element; +} +export declare function isAssemblySymmetryAnnotationApplicable(plugin: PluginContext): boolean; +export {}; diff --git a/frontend/venome-molstar/lib/ui/symmetry-annotation-controls.js b/frontend/venome-molstar/lib/ui/symmetry-annotation-controls.js new file mode 100644 index 00000000..3ec66757 --- /dev/null +++ b/frontend/venome-molstar/lib/ui/symmetry-annotation-controls.js @@ -0,0 +1,213 @@ +import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime"; +import { AssemblySymmetry3D, getRCSBAssemblySymmetryConfig, tryCreateAssemblySymmetry } from 'molstar/lib/extensions/rcsb/assembly-symmetry/behavior'; +import { AssemblySymmetry, AssemblySymmetryDataProvider, AssemblySymmetryProvider } from 'molstar/lib/extensions/rcsb/assembly-symmetry/prop'; +import { PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { StateSelection } from 'molstar/lib/mol-state'; +import { Task } from 'molstar/lib/mol-task'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import { AnnotationRowControls } from './annotation-row-controls'; +const DefaultSymmetryControlsState = { + params: { + on: PD.Boolean(false, { isHidden: true }), + symmetryIndex: PD.Select(0, [[0, 'Auto']]), + noSymmetries: PD.Boolean(false, { isHidden: true }), + }, + values: { + on: false, + symmetryIndex: 0, + noSymmetries: false, + }, +}; +/** UI controls for showing Assembly Symmetry annotations (a row within Annotations section) */ +export class SymmetryAnnotationControls extends PurePluginUIComponent { + state = DefaultSymmetryControlsState; + currentStructureId = undefined; + componentDidMount() { + // Reset state when the pivot structure changes + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, c => { + const structureObj = c.structures[0]?.cell.obj; + const structureId = structureObj?.id; + if (structureId !== this.currentStructureId) { + this.currentStructureId = structureId; + this.syncParams(); + } + }); + // Synchronize params when AssemblySymmetry3D changes + this.subscribe(this.plugin.state.events.cell.stateUpdated, e => { + if (e.cell.transform.transformer === AssemblySymmetry3D) { + this.syncParams(); + } + }); + // Synchronize params when AssemblySymmetry3D is removed + this.subscribe(this.plugin.state.events.cell.removed, e => { + this.syncParams(); + }); + } + /** Synchronize parameters and values in UI with real parameters currently applied in `AssemblySymmetryProvider` */ + syncParams() { + if (this.hasAssemblySymmetry3D()) { + const noSymmetries = this.noSymmetriesAvailable(); + const realParams = this.getRealParams(); + const realValues = this.getRealValues(); + const options = noSymmetries ? + [[0, 'None']] + : realParams.symmetryIndex.options.filter(([index, label]) => index >= 0); // Removing the 'off' option (having index -1) + const params = { + ...this.state.params, + symmetryIndex: PD.Select(0, options), + }; + const values = (realValues.symmetryIndex >= 0) ? { + on: true, + symmetryIndex: realValues.symmetryIndex, + noSymmetries: noSymmetries, + } : { + on: false, + symmetryIndex: this.state.values.symmetryIndex, + noSymmetries: noSymmetries, + }; + this.setState({ params, values }); + } + else { + this.setState({ + params: DefaultSymmetryControlsState.params, + values: DefaultSymmetryControlsState.values, + }); + } + } + /** Return `true` if symmetry data have been retrieved and do not contain any non-trivial symmetry. */ + noSymmetriesAvailable() { + const structure = this.getPivotStructure()?.cell.obj?.data; + const symmetryData = structure && AssemblySymmetryDataProvider.get(structure).value; + return symmetryData !== undefined && symmetryData.filter(sym => sym.symbol !== 'C1').length === 0; + } + /** Get the first loaded structure, if any. */ + getPivotStructure() { + return getPivotStructure(this.plugin); + } + /** Get parameters currently applied in `AssemblySymmetryProvider` */ + getRealParams() { + const structure = this.getPivotStructure()?.cell.obj?.data; + let params; + if (structure) { + params = AssemblySymmetryProvider.getParams(structure); + } + else { + params = AssemblySymmetryProvider.defaultParams; + } + return params; + } + /** Get parameter values currently applied in `AssemblySymmetryProvider` */ + getRealValues() { + const structure = this.getPivotStructure()?.cell.obj?.data; + if (structure) { + return AssemblySymmetryProvider.props(structure); + } + else { + return { ...PD.getDefaultValues(AssemblySymmetryProvider.defaultParams), symmetryIndex: -1 }; + } + } + /** Return `true` if an `AssemblySymmetry3D` node existing in the */ + hasAssemblySymmetry3D() { + const struct = this.getPivotStructure(); + const state = struct?.cell.parent; + return state !== undefined && !!StateSelection.findTagInSubtree(state.tree, struct.cell.transform.ref, AssemblySymmetry.Tag.Representation); + } + /** Run changes needed to set visibility on or off, and set UI accordingly */ + async apply(applied) { + if (applied) { + if (this.hasAssemblySymmetry3D()) { + await this.changeParamValues({ ...this.state.values, on: true }); + } + else { + await this.initSymmetry(); + } + this.setState(old => ({ values: { ...old.values, on: true } })); + } + else { + if (this.hasAssemblySymmetry3D()) { + await this.changeParamValues({ ...this.state.values, on: false }); + } + else { + // no action needed + } + this.setState(old => ({ values: { ...old.values, on: false } })); + } + } + /** Run changes needed to change parameter values, and set UI accordingly*/ + async changeParamValues(values) { + const struct = this.getPivotStructure(); + if (!struct) + return; + const currValues = this.getRealValues(); + const newValues = { ...currValues, symmetryIndex: values.on ? values.symmetryIndex : -1 }; + if (struct.properties) { + const b = this.plugin.state.data.build(); + b.to(struct.properties.cell).update(old => { + old.properties[AssemblySymmetryProvider.descriptor.name] = newValues; + }); + await b.commit(); + } + else { + const pd = this.plugin.customStructureProperties.getParams(struct.cell.obj?.data); + const params = PD.getDefaultValues(pd); + params.properties[AssemblySymmetryProvider.descriptor.name] = newValues; + await this.plugin.builders.structure.insertStructureProperties(struct.cell, params); + } + if (!values.on) { // if values.on, parameters will be updated via subscription + this.setState({ values }); + } + } + /** Try to retrieve symmetry data and create `AssemblySymmetry3D` representation */ + async initSymmetry(initialSymmetryIndex) { + await Task.create('Initialize Assembly Symmetry', async (ctx) => { + const struct = this.getPivotStructure(); + const data = struct?.cell.obj?.data; + if (!data) + return; + try { + const propCtx = { runtime: ctx, assetManager: this.plugin.managers.asset }; + const config = getRCSBAssemblySymmetryConfig(this.plugin); + const symmetryDataProps = { + serverType: config.DefaultServerType, + serverUrl: config.DefaultServerUrl, + }; + await AssemblySymmetryDataProvider.attach(propCtx, data, symmetryDataProps); + const assemblySymmetryData = AssemblySymmetryDataProvider.get(data).value; + const symmetryIndex = initialSymmetryIndex ?? (assemblySymmetryData ? AssemblySymmetry.firstNonC1(assemblySymmetryData) : -1); + const symmetryProps = { ...symmetryDataProps, symmetryIndex }; + await AssemblySymmetryProvider.attach(propCtx, data, symmetryProps); + } + catch (e) { + this.plugin.log.error(`Assembly Symmetry: ${e}`); + return; + } + await tryCreateAssemblySymmetry(this.plugin, struct.cell); + }).run(); + } + render() { + const shortTitle = 'Assembly Symmetry' + (this.state.values.noSymmetries ? ' [Not Available]' : ''); + const title = 'Assembly Symmetry' + (this.state.values.noSymmetries ? ' [Not Available]\nSymmetry information for this assembly is not available' : ''); + return _jsx(_Fragment, { children: _jsx(SymmetryAnnotationRowControls, { shortTitle: shortTitle, title: title, applied: this.state.values.on, onChangeApplied: applied => this.apply(applied), params: this.state.params, values: this.state.values, onChangeValues: v => this.changeParamValues(v) }) }); + } +} +class SymmetryAnnotationRowControls extends AnnotationRowControls { + renderOptions() { + if (this.props.values.noSymmetries) { + return _jsx("div", { className: 'msp-row-text', children: _jsx("div", { title: 'Symmetry information for this assembly is not available', children: "Symmetry information not available" }) }); + } + return super.renderOptions(); + } +} +/** Get the first loaded structure, if any. */ +function getPivotStructure(plugin) { + return plugin.managers.structure.hierarchy.selection.structures[0]; +} +export function isAssemblySymmetryAnnotationApplicable(plugin) { + const struct = getPivotStructure(plugin); + const isAssembly = struct?.cell.obj?.data?.units[0].conformation.operator.assembly !== undefined; + return isAssembly && AssemblySymmetry.isApplicable(struct?.cell.obj?.data); + // It would be nice to disable the default `AssemblySymmetry.isApplicable` behavior + // (i.e. hiding Assembly Symmetry controls for non-biological assemblies, e.g. 1smv assembly 3) + // by `AssemblySymmetry.isApplicable = struct => struct?.units[0].conformation.operator.assembly !== undefined;` + // But we cannot easily override the `fetch` function which calls the original `isApplicable`. +} diff --git a/frontend/venome-molstar/package-lock.json b/frontend/venome-molstar/package-lock.json new file mode 100644 index 00000000..de37a0df --- /dev/null +++ b/frontend/venome-molstar/package-lock.json @@ -0,0 +1,11725 @@ +{ + "name": "venome-molstar", + "version": "3.1.3", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "venome-molstar", + "version": "3.1.3", + "license": "Apache-2.0", + "dependencies": { + "crypto-browserify": "^3.12.0", + "d3-axis": "^3.0.0", + "d3-brush": "^3.0.0", + "d3-scale": "^4.0.2", + "d3-selection": "^3.0.0", + "lit": "^3.1.1", + "molstar": "3.44.0", + "path-browserify": "^1.0.1", + "stream-browserify": "^3.0.0" + }, + "devDependencies": { + "@babel/core": "^7.17.10", + "@babel/plugin-transform-runtime": "^7.17.10", + "@babel/preset-env": "^7.17.10", + "@babel/runtime": "^7.17.9", + "@types/d3": "^7.4.0", + "@types/react": "^18.0.17", + "@types/react-dom": "^18.0.6", + "@typescript-eslint/eslint-plugin": "^6.10.0", + "@typescript-eslint/parser": "^6.10.0", + "babel-loader": "^8.2.5", + "concurrently": "^7.3.0", + "cpx2": "^4.2.0", + "css-loader": "^6.7.1", + "eslint": "^8.53.0", + "extra-watch-webpack-plugin": "^1.0.3", + "file-loader": "^6.2.0", + "http-server": "^14.1.0", + "mini-css-extract-plugin": "^2.6.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.51.0", + "sass-loader": "^12.6.0", + "style-loader": "^3.3.1", + "typescript": "^4.6.4", + "webpack": "^5.89.0", + "webpack-cli": "^5.1.4" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", + "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.7.tgz", + "integrity": "sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz", + "integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.7.tgz", + "integrity": "sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.7.tgz", + "integrity": "sha512-PdxEpL71bJp1byMG0va5gwQcXHxuEYC/BgI/e88mGTtohbZN28O5Yit0Plkkm/dBzCF/BxmbNcses1RH1T+urA==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", + "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz", + "integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", + "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", + "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", + "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", + "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", + "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", + "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", + "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", + "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", + "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", + "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", + "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.7.tgz", + "integrity": "sha512-fa0hnfmiXc9fq/weK34MUV0drz2pOL/vfKWvN7Qw127hiUPabFCUMgAbYWcchRzMJit4o5ARsK/s+5h0249pLw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.7", + "babel-plugin-polyfill-corejs3": "^0.8.7", + "babel-plugin-polyfill-regenerator": "^0.5.4", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.8.tgz", + "integrity": "sha512-lFlpmkApLkEP6woIKprO6DO60RImpatTQKtz4sUcDjVcK8M8mQ4sZsuxaTMNOZf0sqAq/ReYW1ZBHnOQwKpLWA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.7", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.8", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.6", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.3", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.23.4", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.7", + "babel-plugin-polyfill-corejs3": "^0.8.7", + "babel-plugin-polyfill-regenerator": "^0.5.4", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", + "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", + "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "optional": true + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz", + "integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz", + "integrity": "sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g==" + }, + "node_modules/@lit/reactive-element": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.3.tgz", + "integrity": "sha512-e067EuTNNgOHm1tZcc0Ia7TCzD/9ZpoPegHKgesrGK6pSDRGkGDAQbYuQclqLPIoJ9eC8Kb9mYtGryWcM5AywA==", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.1.2" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "optional": true, + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/fs/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/fs/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "optional": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "optional": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/argparse": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-2.0.14.tgz", + "integrity": "sha512-jJ6NMs9rXQ0rsqNt3TL4Elcwhd6wygo3lJOVoiHzURD34vsCcAlw443uGu4PXTtEmMF7sYKoadTCLXNmuJuQGw==" + }, + "node_modules/@types/benchmark": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/benchmark/-/benchmark-2.1.5.tgz", + "integrity": "sha512-cKio2eFB3v7qmKcvIHLUMw/dIx/8bhWPuzpzRT4unCPRTD8VdA9Zb0afxpcxOqR4PixRS7yT42FqGS8BYL8g1w==" + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "dev": true, + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", + "dev": true + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "dev": true + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "dev": true + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "dev": true, + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "dev": true + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz", + "integrity": "sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==", + "dev": true + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "dev": true + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "dev": true + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "dev": true, + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.9.tgz", + "integrity": "sha512-IKtvyFdb4Q0LWna6ymywQsEYjK/94SGhPrMfEr1TIc5OBeziTi+1jcCvttts8e0UWZIxpasjnQk9MNk/3iS+kA==", + "dev": true + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "dev": true + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "dev": true, + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.6.tgz", + "integrity": "sha512-qlmD/8aMk5xGorUvTUWHCiumvgaUXYldYjNVOWtYoTYY/L+WwIEAmJxUmTgr9LoGNG0PPAOmqMDJVDPc7DOpPw==", + "dev": true + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dev": true, + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.2.tgz", + "integrity": "sha512-WAIEVlOCdd/NKRYTsqCpOMHQHemKBEINf8YXMYOtXH0GA7SY0dqMB78P3Uhgfy+4X+/Mlw2wDtlETkN6kQUCMA==", + "dev": true + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "dev": true + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "dev": true + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "dev": true + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "dev": true, + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.3.tgz", + "integrity": "sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==", + "dev": true + }, + "node_modules/@types/d3-selection": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.10.tgz", + "integrity": "sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==", + "dev": true + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "dev": true, + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==", + "dev": true + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "dev": true + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "dev": true + }, + "node_modules/@types/d3-transition": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.8.tgz", + "integrity": "sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "dev": true, + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", + "integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.3.tgz", + "integrity": "sha512-pvQ+TKeRHeiUGRhvYwRrQ/ISnohKkSJR14fT2yqyZ4e9K5vqc7hrtY2Y1Dw0ZwAzQ6DQsxsaCUuSIIi8v0Cq6w==", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.41", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", + "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.13", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.13.tgz", + "integrity": "sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ==", + "dev": true + }, + "node_modules/@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/mdast": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", + "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, + "node_modules/@types/node": { + "version": "16.18.72", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.72.tgz", + "integrity": "sha512-Kck1Du/zQyLbq5YlBKCtrUlyyP02lYjREjKKYImtf6MZgXrLoRVjexMv0wxiDzIJPnk86i+HrvGNyI03qoewEg==" + }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" + }, + "node_modules/@types/qs": { + "version": "6.9.11", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", + "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" + }, + "node_modules/@types/react": { + "version": "18.2.48", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.48.tgz", + "integrity": "sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.18", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz", + "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" + }, + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/swagger-ui-dist": { + "version": "3.30.4", + "resolved": "https://registry.npmjs.org/@types/swagger-ui-dist/-/swagger-ui-dist-3.30.4.tgz", + "integrity": "sha512-FeOBc7uj4/lAIh4jkBzorvmNoUU9JgSccyDIRo0E9MJw9KQfSxlwpHCyKGnU9kfV5N5dEdfpY8wm7to3nSwTmA==" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==" + }, + "node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.0.tgz", + "integrity": "sha512-DUCUkQNklCQYnrBSSikjVChdc84/vMPDQSgJTHBZ64G9bA9w0Crc0rd2diujKbTdp6w2J47qkeHQLoi0rpLCdg==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.19.0", + "@typescript-eslint/type-utils": "6.19.0", + "@typescript-eslint/utils": "6.19.0", + "@typescript-eslint/visitor-keys": "6.19.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.0.tgz", + "integrity": "sha512-1DyBLG5SH7PYCd00QlroiW60YJ4rWMuUGa/JBV0iZuqi4l4IK3twKPq5ZkEebmGqRjXWVgsUzfd3+nZveewgow==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.19.0", + "@typescript-eslint/types": "6.19.0", + "@typescript-eslint/typescript-estree": "6.19.0", + "@typescript-eslint/visitor-keys": "6.19.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.0.tgz", + "integrity": "sha512-dO1XMhV2ehBI6QN8Ufi7I10wmUovmLU0Oru3n5LVlM2JuzB4M+dVphCPLkVpKvGij2j/pHBWuJ9piuXx+BhzxQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.19.0", + "@typescript-eslint/visitor-keys": "6.19.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.0.tgz", + "integrity": "sha512-mcvS6WSWbjiSxKCwBcXtOM5pRkPQ6kcDds/juxcy/727IQr3xMEcwr/YLHW2A2+Fp5ql6khjbKBzOyjuPqGi/w==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.19.0", + "@typescript-eslint/utils": "6.19.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.0.tgz", + "integrity": "sha512-lFviGV/vYhOy3m8BJ/nAKoAyNhInTdXpftonhWle66XHAtT1ouBlkjL496b5H5hb8dWXHwtypTqgtb/DEa+j5A==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.0.tgz", + "integrity": "sha512-o/zefXIbbLBZ8YJ51NlkSAt2BamrK6XOmuxSR3hynMIzzyMY33KuJ9vuMdFSXW+H0tVvdF9qBPTHA91HDb4BIQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.19.0", + "@typescript-eslint/visitor-keys": "6.19.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.0.tgz", + "integrity": "sha512-QR41YXySiuN++/dC9UArYOg4X86OAYP83OWTewpVx5ct1IZhjjgTLocj7QNxGhWoTqknsgpl7L+hGygCO+sdYw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.19.0", + "@typescript-eslint/types": "6.19.0", + "@typescript-eslint/typescript-estree": "6.19.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.0.tgz", + "integrity": "sha512-hZaUCORLgubBvtGpp1JEFEazcuEdfxta9j4iUwdSAr7mEsYYAp3EAUyCZk3VEEqGj6W+AV4uWyrDGtrlawAsgQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.19.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "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" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "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" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "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" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "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" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "optional": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "optional": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "devOptional": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.reduce": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.6.tgz", + "integrity": "sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-loader": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz", + "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.8.tgz", + "integrity": "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.5.0", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz", + "integrity": "sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.4", + "core-js-compat": "^3.33.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz", + "integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", + "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "devOptional": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dev": true, + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bit-twiddle": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bit-twiddle/-/bit-twiddle-1.0.2.tgz", + "integrity": "sha512-B9UhK0DKFZhoTFcfvAzhqsjStvGJp9vYWf3+6SNTtdSQnvIgfkHbgHrg/e4+TH71N2GDu8tpmCVoyfrL1d7ntA==", + "optional": true + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "optional": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "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.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "devOptional": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", + "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", + "dependencies": { + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.4", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.6", + "readable-stream": "^3.6.2", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "optional": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "optional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "optional": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001579", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz", + "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "devOptional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clone-deep/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "devOptional": true + }, + "node_modules/concurrently": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.6.0.tgz", + "integrity": "sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "date-fns": "^2.29.1", + "lodash": "^4.17.21", + "rxjs": "^7.0.0", + "shell-quote": "^1.7.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^17.3.1" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/concurrently/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concurrently/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "optional": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-js-compat": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.0.tgz", + "integrity": "sha512-5blwFAddknKeNgsjBzilkdQ0+YK8L1PfqPYq40NOYMYFSS38qj+hpTcLLWwpIwA2A5bje/x5jmVn2tzUMg9IVw==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "optional": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/cpx2": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/cpx2/-/cpx2-4.2.3.tgz", + "integrity": "sha512-UM7Iza+OM8FZ2ntTml/mdb3RmSLK5I2DqFqDdMihlGyKZCAAnDP++H973Oyc/2TQpEMtg5JHeRNfewclE330EA==", + "dev": true, + "dependencies": { + "debounce": "^1.2.0", + "debug": "^4.1.1", + "duplexer": "^0.1.1", + "fs-extra": "^11.1.0", + "glob-gitignore": "^1.0.14", + "glob2base": "0.0.12", + "ignore": "^5.1.8", + "minimatch": "^8.0.2", + "p-map": "^4.0.0", + "resolve": "^1.12.0", + "safe-buffer": "^5.2.0", + "shell-quote": "^1.8.0", + "subarg": "^1.0.0" + }, + "bin": { + "cpx": "bin/index.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/cpx2/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/css-loader": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.9.1.tgz", + "integrity": "sha512-OzABOh0+26JKFdMzlK6PY1u5Zx8+Ck7CVRlcGNZoY9qwJjdfu2VWFuprTIpPW+Av5TZTVViYWcFQaEEQURLknQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.4", + "postcss-modules-scope": "^3.1.1", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-loader/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-loader/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "optional": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.639", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.639.tgz", + "integrity": "sha512-CkKf3ZUVZchr+zDpAlNLEEy2NJJ9T64ULWaDgy3THXXlPVPkLu3VOs9Bac44nebVtdwl2geSj6AxTtGDOxoXhg==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "devOptional": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "optional": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/envinfo": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", + "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "optional": true + }, + "node_modules/es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "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" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "optional": true + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "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" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "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" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extra-watch-webpack-plugin": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/extra-watch-webpack-plugin/-/extra-watch-webpack-plugin-1.0.3.tgz", + "integrity": "sha512-ZScQdMH6hNofRRN6QMQFg+aa5vqimfBgnPXmRDhdaLpttT6hrzpY9Oyren3Gh/FySPrgsvKCNbx/NFA7XNdIsg==", + "dev": true, + "dependencies": { + "glob": "^7.1.2", + "is-glob": "^4.0.0", + "lodash.uniq": "^4.5.0", + "schema-utils": "^0.4.0" + } + }, + "node_modules/extra-watch-webpack-plugin/node_modules/schema-utils": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", + "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-index": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", + "integrity": "sha512-uJ5vWrfBKMcE6y2Z8834dwEZj9mNGxYa3t3I53OwFeuZ8D9oc2E5zcsrkuhX6h4iYrjhiv0T3szQmxlAV9uxDg==", + "dev": true + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fp-ts": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.2.tgz", + "integrity": "sha512-CkqAjnIKFqvo3sCyoBTqgJvF+bHrSik584S9nhTjtBESLx26cbtVMR/T9a6ApChOcSDAaM3JydDmWDUn4EEXng==", + "peer": true + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "optional": true + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "devOptional": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "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" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "optional": true + }, + "node_modules/gl": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/gl/-/gl-6.0.2.tgz", + "integrity": "sha512-yBbfpChOtFvg5D+KtMaBFvj6yt3vUnheNAH+UrQH2TfDB8kr0tERdL0Tjhe0W7xJ6jR6ftQBluTZR9jXUnKe8g==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "bindings": "^1.5.0", + "bit-twiddle": "^1.0.2", + "glsl-tokenizer": "^2.1.5", + "nan": "^2.17.0", + "node-abi": "^3.26.0", + "node-gyp": "^9.2.0", + "prebuild-install": "^7.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "devOptional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-gitignore": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/glob-gitignore/-/glob-gitignore-1.0.14.tgz", + "integrity": "sha512-YuAEPqL58bOQDqDF2kMv009rIjSAtPs+WPzyGbwRWK+wD0UWQVRoP34Pz6yJ6ivco65C9tZnaIt0I3JCuQ8NZQ==", + "dev": true, + "dependencies": { + "glob": "^7.1.3", + "ignore": "^5.0.5", + "lodash.difference": "^4.5.0", + "lodash.union": "^4.6.0", + "make-array": "^1.0.5", + "util.inherits": "^1.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "devOptional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "devOptional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/glob2base": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", + "integrity": "sha512-ZyqlgowMbfj2NPjxaZZ/EtsXlOch28FRXgMd64vqZWk1bT9+wvSRLYD1om9M7QfQru51zJPAT17qXm4/zd+9QA==", + "dev": true, + "dependencies": { + "find-index": "^0.1.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glsl-tokenizer": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/glsl-tokenizer/-/glsl-tokenizer-2.1.5.tgz", + "integrity": "sha512-XSZEJ/i4dmz3Pmbnpsy3cKh7cotvFlBiZnDOwnj/05EwNp2XrhQ4XKJxT7/pDt4kp4YcpRSKz8eTV7S+mwV6MA==", + "optional": true, + "dependencies": { + "through2": "^0.6.3" + } + }, + "node_modules/glsl-tokenizer/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "optional": true + }, + "node_modules/glsl-tokenizer/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "optional": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/glsl-tokenizer/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "optional": true + }, + "node_modules/glsl-tokenizer/node_modules/through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==", + "optional": true, + "dependencies": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "devOptional": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/h264-mp4-encoder": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/h264-mp4-encoder/-/h264-mp4-encoder-1.0.12.tgz", + "integrity": "sha512-xih3J+Go0o1RqGjhOt6TwXLWWGqLONRPyS8yoMu/RoS/S8WyEv4HuHp1KBsDDl8srZQ3gw9f95JYkCSjCuZbHQ==" + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "optional": true + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", + "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-url-attributes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.0.tgz", + "integrity": "sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "optional": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "optional": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-server": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz", + "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==", + "dev": true, + "dependencies": { + "basic-auth": "^2.0.1", + "chalk": "^4.1.2", + "corser": "^2.0.1", + "he": "^1.2.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy": "^1.18.1", + "mime": "^1.6.0", + "minimist": "^1.2.6", + "opener": "^1.5.1", + "portfinder": "^1.0.28", + "secure-compare": "3.0.1", + "union": "~0.5.0", + "url-join": "^4.0.1" + }, + "bin": { + "http-server": "bin/http-server" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/http-server/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/http-server/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/http-server/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/http-server/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/http-server/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/http-server/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "optional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "devOptional": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "optional": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "devOptional": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "optional": true + }, + "node_modules/inline-style-parser": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.2.tgz", + "integrity": "sha512-EcKzdTHVe8wFVOGEYXiW9WmJXPjqi1T+234YpJr98RiFYKHV3cdy1+3mkTE+KHTHxFFLH51SfaGOoUdW+v7ViQ==" + }, + "node_modules/internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "dependencies": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/io-ts": { + "version": "2.2.21", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.21.tgz", + "integrity": "sha512-zz2Z69v9ZIC3mMLYWIeoUcwWD6f+O7yP92FMVVaXEOSZH1jnVBmET/urd/uoarD1WGBY4rCj8TAyMPzsGNzMFQ==", + "peerDependencies": { + "fp-ts": "^2.5.0" + } + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "optional": true + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "optional": true + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "devOptional": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jpeg-js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", + "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", + "optional": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lit": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.1.tgz", + "integrity": "sha512-hF1y4K58+Gqrz+aAPS0DNBwPqPrg6P04DuWK52eMkt/SM9Qe9keWLcFgRcEKOLuDlRZlDsDbNL37Vr7ew1VCuw==", + "dependencies": { + "@lit/reactive-element": "^2.0.0", + "lit-element": "^4.0.0", + "lit-html": "^3.1.0" + } + }, + "node_modules/lit-element": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.3.tgz", + "integrity": "sha512-2vhidmC7gGLfnVx41P8UZpzyS0Fb8wYhS5RCm16cMW3oERO0Khd3EsKwtRpOnttuByI5rURjT2dfoA7NlInCNw==", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.1.2", + "@lit/reactive-element": "^2.0.0", + "lit-html": "^3.1.0" + } + }, + "node_modules/lit-html": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.1.1.tgz", + "integrity": "sha512-x/EwfGk2D/f4odSFM40hcGumzqoKv0/SUh6fBO+1Ragez81APrcAMPo1jIrCDd9Sn+Z4CT867HWKViByvkDZUA==", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-array": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/make-array/-/make-array-1.0.5.tgz", + "integrity": "sha512-sgK2SAzxT19rWU+qxKUcn6PAh/swiIiz2F8C2cZjLc1z4iwYIfdoihqFIDQ8BDzAGtWPYJ6Sr13K1j/DXynDLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "devOptional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "optional": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "optional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz", + "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", + "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.0.0.tgz", + "integrity": "sha512-XZuPPzQNBPAlaqsTTgRrcJnyFbSOBovSadFgbFu8SnuNgm+6Bdx1K+IWoitsmj6Lq6MNtI+ytOqwN70n//NaBA==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-remove-position": "^5.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.0.0.tgz", + "integrity": "sha512-xadSsJayQIucJ9n053dfQwVu1kuXg7jCTdYsMK8rqzKZh52nLfSH/k0sAxE0u+pj/zKZX+o5wB+ML5mRayOxFA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.1.0.tgz", + "integrity": "sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", + "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz", + "integrity": "sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", + "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", + "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz", + "integrity": "sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/micromatch/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/micromatch/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/micromatch/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.7.7", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.7.tgz", + "integrity": "sha512-+0n11YGyRavUR3IlaOzJ0/4Il1avMvJ1VJfhWfCn24ITQXhRr1gghbhhrda6tgtNcpZaWKdSuwKq20Jb7fnlyw==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "devOptional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "optional": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "optional": true + }, + "node_modules/molstar": { + "version": "3.44.0", + "resolved": "https://registry.npmjs.org/molstar/lib/-/molstar-3.44.0.tgz", + "integrity": "sha512-lalV/MiYvB9+5prYaLpGdHknO3Nvn+G265MvMFNviqyueacvKS7sXnQ2wDnOkdOPKBlJktLNKyrgGcwLTNGEUw==", + "dependencies": { + "@types/argparse": "^2.0.14", + "@types/benchmark": "^2.1.5", + "@types/compression": "1.7.5", + "@types/express": "^4.17.21", + "@types/node": "^16.18.69", + "@types/node-fetch": "^2.6.10", + "@types/swagger-ui-dist": "3.30.4", + "argparse": "^2.0.1", + "body-parser": "^1.20.2", + "compression": "^1.7.4", + "cors": "^2.8.5", + "express": "^4.18.2", + "h264-mp4-encoder": "^1.0.12", + "immer": "^9.0.21", + "immutable": "^4.3.4", + "io-ts": "^2.2.21", + "node-fetch": "^2.7.0", + "react-markdown": "^9.0.1", + "rxjs": "^7.8.1", + "swagger-ui-dist": "^5.10.5", + "tslib": "^2.6.2", + "util.promisify": "^1.1.2", + "xhr2": "^0.2.1" + }, + "bin": { + "cif2bcif": "lib/commonjs/cli/cif2bcif/index.js", + "cifschema": "lib/commonjs/cli/cifschema/index.js", + "model-server": "lib/commonjs/servers/model/server.js", + "model-server-preprocess": "lib/commonjs/servers/model/preprocess.js", + "model-server-query": "lib/commonjs/servers/model/query.js", + "mvs-print-schema": "lib/commonjs/cli/mvs/mvs-print-schema.js", + "mvs-render": "lib/commonjs/cli/mvs/mvs-render.js", + "mvs-validate": "lib/commonjs/cli/mvs/mvs-validate.js", + "volume-server": "lib/commonjs/servers/volume/server.js", + "volume-server-pack": "lib/commonjs/servers/volume/pack.js", + "volume-server-query": "lib/commonjs/servers/volume/query.js" + }, + "optionalDependencies": { + "canvas": "^2.11.2", + "gl": "^6.0.2", + "jpeg-js": "^0.4.4", + "pngjs": "^6.0.0" + }, + "peerDependencies": { + "react": "^18.1.0 || ^17.0.2 || ^16.14.0", + "react-dom": "^18.1.0 || ^17.0.2 || ^16.14.0" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nan": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", + "optional": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "optional": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-abi": { + "version": "3.54.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz", + "integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==", + "optional": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", + "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", + "optional": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp/node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp/node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "optional": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "optional": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "optional": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.7.tgz", + "integrity": "sha512-PrJz0C2xJ58FNn11XV2lr4Jt5Gzl94qpy9Lu0JlfEj14z88sqbSBJCBEzdlNUCzY2gburhbrwOZ5BHCmuNUy0g==", + "dependencies": { + "array.prototype.reduce": "^1.0.6", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "safe-array-concat": "^1.0.0" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "devOptional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "devOptional": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/parse-entities": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", + "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "optional": true, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/portfinder": { + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz", + "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==", + "dev": true, + "dependencies": { + "async": "^2.6.4", + "debug": "^3.2.7", + "mkdirp": "^0.5.6" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/portfinder/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/portfinder/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/postcss": { + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.4.tgz", + "integrity": "sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.1.tgz", + "integrity": "sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "optional": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prebuild-install/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prebuild-install/node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "optional": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "optional": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/property-information": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.0.tgz", + "integrity": "sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-markdown": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.1.tgz", + "integrity": "sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg==", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.0.tgz", + "integrity": "sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "optional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "devOptional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", + "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "dependencies": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", + "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", + "dependencies": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sass": { + "version": "1.70.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.70.0.tgz", + "integrity": "sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-loader": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "dev": true, + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/sass/node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/sass/node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/sass/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/sass/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sass/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/sass/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", + "dev": true + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "devOptional": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "optional": true + }, + "node_modules/set-function-length": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", + "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "dependencies": { + "define-data-property": "^1.1.1", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.2", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shallow-clone/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "optional": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "optional": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "optional": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", + "dev": true + }, + "node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "optional": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "devOptional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz", + "integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "devOptional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", + "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/style-to-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.5.tgz", + "integrity": "sha512-rDRwHtoDD3UMMrmZ6BzOW0naTjMsVZLIjsGleSKS/0Oz+cgCfAPRspaqJuE8rDzpKha/nEvnM0IF4seEAZUTKQ==", + "dependencies": { + "inline-style-parser": "0.2.2" + } + }, + "node_modules/subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==", + "dev": true, + "dependencies": { + "minimist": "^1.1.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/swagger-ui-dist": { + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.11.0.tgz", + "integrity": "sha512-j0PIATqQSEFGOLmiJOJZj1X1Jt6bFIur3JpY7+ghliUnfZs0fpWDdHEkn9q7QUlBtKbkn6TepvSxTqnE8l3s0A==" + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "optional": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "optional": true + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "optional": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/terser": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz", + "integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "dependencies": { + "qs": "^6.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "optional": true, + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "optional": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/util.inherits": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/util.inherits/-/util.inherits-1.0.3.tgz", + "integrity": "sha512-gMirHcfcq5D87nXDwbZqf5vl65S0mpMZBsHXJsXOO3Hc3G+JoQLwgaJa1h+PL7h3WhocnuLqoe8CuvMlztkyCA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/util.promisify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.1.2.tgz", + "integrity": "sha512-PBdZ03m1kBnQ5cjjO0ZvJMJS+QsbyIcFwi4hY4U76OQsCO9JrOYjbCFgIF76ccFg9xnJo7ZHPkqyj1GqmdS7MA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "object.getownpropertydescriptors": "^2.1.6", + "safe-array-concat": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/webpack": { + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "dev": true, + "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" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^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" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-cli/node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-cli/node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "devOptional": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "devOptional": true + }, + "node_modules/xhr2": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.2.1.tgz", + "integrity": "sha512-sID0rrVCqkVNUn8t6xuv9+6FViXjUVXq8H5rWOH2rz9fDNQEd4g0EA2XlcEdJXRz5BMEn4O1pJFdT+z4YHhoWw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "optional": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/frontend/venome-molstar/package.json b/frontend/venome-molstar/package.json new file mode 100644 index 00000000..32c341a6 --- /dev/null +++ b/frontend/venome-molstar/package.json @@ -0,0 +1,82 @@ +{ + "name": "venome-molstar", + "version": "3.1.3", + "description": "Molstar implementation for venome forked from PDBe Molstar", + "main": "lib/", + "scripts": { + "test": "echo \"Error: no test specified\"", + "lint": "eslint src", + "build": "npm run build-tsc && npm run build-extra && node scripts.js light-skin && npm run build-webpack && node scripts.js clean-rubbish && npm run bundle-webcomponent", + "rebuild": "npm run clean && npm run build", + "clean": "node scripts.js clean-all", + "build-tsc": "tsc --incremental", + "build-extra": "cpx 'src/**/*.{scss,html,ico}' lib/", + "build-webpack": "webpack --mode production --config ./webpack.config.production.js", + "watch": "concurrently -c 'green,gray,blue' --names 'tsc,ext,wpc' --kill-others 'npm:watch-tsc' 'npm:watch-extra' 'npm:watch-webpack'", + "watch-tsc": "tsc --watch --incremental", + "watch-extra": "cpx 'src/**/*.{scss,html,ico}' lib/ --watch", + "watch-webpack": "webpack -w --mode development --stats minimal --config ./webpack.config.development.js", + "serve": "http-server -p 1338 -g", + "bundle-webcomponent": "node scripts.js bundle-webcomponent", + "ts:build": "tsc && cp src/*.scss lib/" + }, + "files": [ + "lib/", + "build/" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/PDBeurope/pdbe-molstar.git" + }, + "keywords": [ + "Molstar", + "3D viewer", + "PDBe", + "biojs" + ], + "author": "Mandar Deshpande ", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/PDBeurope/pdbe-molstar/lib/issues" + }, + "homepage": "https://github.com/PDBeurope/pdbe-molstar#readme", + "devDependencies": { + "@babel/core": "^7.17.10", + "@babel/plugin-transform-runtime": "^7.17.10", + "@babel/preset-env": "^7.17.10", + "@babel/runtime": "^7.17.9", + "@types/d3": "^7.4.0", + "@types/react": "^18.0.17", + "@types/react-dom": "^18.0.6", + "@typescript-eslint/eslint-plugin": "^6.10.0", + "@typescript-eslint/parser": "^6.10.0", + "babel-loader": "^8.2.5", + "concurrently": "^7.3.0", + "cpx2": "^4.2.0", + "css-loader": "^6.7.1", + "eslint": "^8.53.0", + "extra-watch-webpack-plugin": "^1.0.3", + "file-loader": "^6.2.0", + "http-server": "^14.1.0", + "mini-css-extract-plugin": "^2.6.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.51.0", + "sass-loader": "^12.6.0", + "style-loader": "^3.3.1", + "typescript": "^4.6.4", + "webpack": "^5.89.0", + "webpack-cli": "^5.1.4" + }, + "dependencies": { + "crypto-browserify": "^3.12.0", + "d3-axis": "^3.0.0", + "d3-brush": "^3.0.0", + "d3-scale": "^4.0.2", + "d3-selection": "^3.0.0", + "lit": "^3.1.1", + "molstar": "3.44.0", + "path-browserify": "^1.0.1", + "stream-browserify": "^3.0.0" + } +} diff --git a/frontend/venome-molstar/portfolio.html b/frontend/venome-molstar/portfolio.html new file mode 100644 index 00000000..da91a49c --- /dev/null +++ b/frontend/venome-molstar/portfolio.html @@ -0,0 +1,415 @@ + + + + + + + PDBe Molstar + + + + + +
+
+
+
+ +

+ Frame URL: + +

+
+
+
+ + + + + + + \ No newline at end of file diff --git a/frontend/venome-molstar/scripts.js b/frontend/venome-molstar/scripts.js new file mode 100644 index 00000000..43b1b4c4 --- /dev/null +++ b/frontend/venome-molstar/scripts.js @@ -0,0 +1,91 @@ +const fs = require('fs'); +const path = require('path'); +var argparse = require('argparse'); + +const PACKAGE_ROOT_PATH = process.cwd(); +const PACKAGE = require(path.join(PACKAGE_ROOT_PATH, 'package.json')); + +const banner = [ + '/**', + ` * ${PACKAGE.name}`, + ` * @version ${PACKAGE.version}`, + ' * @link https://github.com/PDBeurope/pdbe-molstar', + ' * @license Apache 2.0', + ' */', +].join('\n'); + +const license = [ + '/**', + ' * Copyright 2019-2023 Mandar Deshpande , Adam Midlik ', + ' * European Bioinformatics Institute (EBI, http://www.ebi.ac.uk/)', + ' * European Molecular Biology Laboratory (EMBL, http://www.embl.de/)', + ' * 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.', + ' */', +].join('\n'); + +function removeFiles(...paths) { + for (const path of paths) { + fs.rmSync(path, { recursive: true, force: true }); + } +} + +function replaceSkin(srcFile, skin, destFile) { + let text = fs.readFileSync(srcFile, { encoding: 'utf8' }); + text = text.replaceAll('mol-plugin-ui/skin/dark.scss', `mol-plugin-ui/skin/${skin}.scss`); + fs.writeFileSync(destFile, text, { encoding: 'utf8' }); +} + +const scripts = { + /** Remove any files produced by the build process */ + 'clean-all': () => { + removeFiles('lib', 'build', 'tsconfig.tsbuildinfo'); + }, + + /** Build web component */ + 'bundle-webcomponent': () => { + const outputFile = `build/${PACKAGE.name}-component-${PACKAGE.version}.js`; + removeFiles(outputFile); + const contents = [ + banner, + license, + fs.readFileSync(`build/${PACKAGE.name}-plugin-${PACKAGE.version}.js`), + fs.readFileSync(`lib/${PACKAGE.name}-component-build-${PACKAGE.version}.js`), + ]; + fs.writeFileSync(outputFile, contents.join('\n\n'), { encoding: 'utf8' }); + }, + + /** Prepare module files for light skin */ + 'light-skin': () => { + replaceSkin('lib/index.js', 'light', 'lib/index(light).js'); + replaceSkin('lib/index.d.ts', 'light', 'lib/index(light).d.ts'); + }, + + /** Remove unnecessary files produced by the build process */ + 'clean-rubbish': () => { + removeFiles( + `build/${PACKAGE.name}-light-plugin-${PACKAGE.version}.js`, + `build/${PACKAGE.name}-light-plugin-${PACKAGE.version}.js.LICENSE.txt` + ); + }, +}; + +// scripts['clean-rubbish'](); + +// console.log(process.argv) + +const parser = new argparse.ArgumentParser({ description: '' }); +parser.add_argument('script_name', { choices: Object.keys(scripts) }); +const args = parser.parse_args(); + +console.log('Running script', args.script_name); + +scripts[args.script_name](); diff --git a/frontend/venome-molstar/src/app/alphafold-transparency.ts b/frontend/venome-molstar/src/app/alphafold-transparency.ts new file mode 100644 index 00000000..fe41a809 --- /dev/null +++ b/frontend/venome-molstar/src/app/alphafold-transparency.ts @@ -0,0 +1,191 @@ +import { Structure, StructureElement } from "molstar/lib/mol-model/structure"; +import { PluginStateObject } from "molstar/lib/mol-plugin-state/objects"; +import { StateTransforms } from "molstar/lib/mol-plugin-state/transforms"; +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import { + StateBuilder, + StateObjectCell, + StateSelection, + StateTransform, +} from "molstar/lib/mol-state"; +import { + StructureComponentRef, + StructureRef, +} from "molstar/lib/mol-plugin-state/manager/structure/hierarchy-state"; +import { isEmptyLoci, Loci } from "molstar/lib/mol-model/loci"; +import { Transparency } from "molstar/lib/mol-theme/transparency"; +import { MolScriptBuilder as MS } from "molstar/lib/mol-script/language/builder"; +import { QualityAssessment } from "molstar/lib/extensions/model-archive/quality-assessment/prop"; +import { compile } from "molstar/lib/mol-script/runtime/query/compiler"; +import { + StructureSelection, + QueryContext, +} from "molstar/lib/mol-model/structure"; + +type TransparencyEachReprCallback = ( + update: StateBuilder.Root, + repr: StateObjectCell< + PluginStateObject.Molecule.Structure.Representation3D, + StateTransform< + typeof StateTransforms.Representation.StructureRepresentation3D + > + >, + transparency?: StateObjectCell< + any, + StateTransform< + typeof StateTransforms.Representation.TransparencyStructureRepresentation3DFromBundle + > + > +) => Promise; +const TransparencyManagerTag = "transparency-controls"; + +function getLociByPLDDT(score: number, contextData: Structure) { + const queryExp = MS.struct.modifier.union([ + MS.struct.modifier.wholeResidues([ + MS.struct.modifier.union([ + MS.struct.generator.atomGroups({ + "chain-test": MS.core.rel.eq([ + MS.ammp("objectPrimitive"), + "atomistic", + ]), + "residue-test": MS.core.rel.lte([ + QualityAssessment.symbols.pLDDT.symbol(), + score, + ]), + }), + ]), + ]), + ]); + + const query = compile(queryExp); + const sel = query(new QueryContext(contextData)); + return StructureSelection.toLociWithSourceUnits(sel); +} + +export async function applyAFTransparency( + plugin: PluginContext, + structure: Readonly, + transparency: number, + pLDDT = 70 +) { + return plugin.dataTransaction( + async (ctx) => { + const loci = getLociByPLDDT(pLDDT, structure.cell.obj!.data); + await setStructureTransparency( + plugin, + structure.components, + transparency, + loci + ); + }, + { canUndo: "Apply Transparency" } + ); +} + +export async function setStructureTransparency( + plugin: PluginContext, + components: StructureComponentRef[], + value: number, + loci: StructureElement.Loci, + types?: string[] +) { + await eachRepr( + plugin, + components, + async (update, repr, transparencyCell) => { + if ( + types && + types.length > 0 && + !types.includes(repr.params!.values.type.name) + ) + return; + + const structure = repr.obj!.data.sourceData; + if (Loci.isEmpty(loci) || isEmptyLoci(loci)) return; + + const layer = { + bundle: StructureElement.Bundle.fromLoci(loci), + value, + }; + + if (transparencyCell) { + const bundleLayers = [ + ...transparencyCell.params!.values.layers, + layer, + ]; + const filtered = getFilteredBundle(bundleLayers, structure); + update + .to(transparencyCell) + .update(Transparency.toBundle(filtered)); + } else { + const filtered = getFilteredBundle([layer], structure); + update + .to(repr.transform.ref) + .apply( + StateTransforms.Representation + .TransparencyStructureRepresentation3DFromBundle, + Transparency.toBundle(filtered), + { tags: TransparencyManagerTag } + ); + } + } + ); +} + +export async function clearStructureTransparency( + plugin: PluginContext, + components: StructureComponentRef[], + types?: string[] +) { + await eachRepr( + plugin, + components, + async (update, repr, transparencyCell) => { + if ( + types && + types.length > 0 && + !types.includes(repr.params!.values.type.name) + ) + return; + if (transparencyCell) { + update.delete(transparencyCell.transform.ref); + } + } + ); +} + +async function eachRepr( + plugin: PluginContext, + components: StructureComponentRef[], + callback: TransparencyEachReprCallback +) { + const state = plugin.state.data; + const update = state.build(); + for (const c of components) { + for (const r of c.representations) { + const transparency = state.select( + StateSelection.Generators.ofTransformer( + StateTransforms.Representation + .TransparencyStructureRepresentation3DFromBundle, + r.cell.transform.ref + ).withTag(TransparencyManagerTag) + ); + await callback(update, r.cell, transparency[0]); + } + } + + return update.commit({ doNotUpdateCurrent: true }); +} + +/** filter transparency layers for given structure */ +function getFilteredBundle( + layers: Transparency.BundleLayer[], + structure: Structure +) { + const transparency = Transparency.ofBundle(layers, structure.root); + const merged = Transparency.merge(transparency); + return Transparency.filter( + merged, + structure + ) as Transparency; +} diff --git a/frontend/venome-molstar/src/app/custom-events.ts b/frontend/venome-molstar/src/app/custom-events.ts new file mode 100644 index 00000000..82cdaa34 --- /dev/null +++ b/frontend/venome-molstar/src/app/custom-events.ts @@ -0,0 +1,99 @@ +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import { lociDetails, EventDetail } from "./loci-details"; +import { InteractivityManager } from "molstar/lib/mol-plugin-state/manager/interactivity"; +import { debounceTime } from "rxjs/operators"; + +export namespace CustomEvents { + function create(eventTypeArr: string[]) { + const eventObj = {} as any; + for (let ei = 0, el = eventTypeArr.length; ei < el; ei++) { + const eventType = eventTypeArr[ei]; + let event; + if (typeof MouseEvent == "function") { + // current standard + event = new MouseEvent(eventType, { + view: window, + bubbles: true, + cancelable: true, + }); + } else if (typeof document.createEvent == "function") { + // older standard + event = document.createEvent("MouseEvents"); + event.initEvent( + eventType, + true /* bubbles */, + true /* cancelable */ + ); + } + eventObj[eventType] = event; + } + return eventObj; + } + + function dispatchCustomEvent( + event: any, + eventData: EventDetail, + targetElement: HTMLElement + ) { + if (typeof eventData !== "undefined") { + (eventData as any)["residueNumber"] = eventData.seq_id; + event["eventData"] = eventData; + event.eventData.residueNumber = eventData.seq_id; + targetElement.dispatchEvent(event); + } + } + + export function add(plugin: PluginContext, targetElement: HTMLElement) { + const pdbevents = create([ + "PDB.molstar.click", + "PDB.molstar.mouseover", + "PDB.molstar.mouseout", + ]); + plugin.behaviors.interaction.click.subscribe( + (e: InteractivityManager.ClickEvent) => { + if ( + e.button === 1 && + e.current && + e.current.loci.kind !== "empty-loci" + ) { + const evData = lociDetails(e.current.loci); + if (evData) + dispatchCustomEvent( + pdbevents["PDB.molstar.click"], + evData, + targetElement + ); + } + } + ); + plugin.behaviors.interaction.hover + .pipe(debounceTime(100)) + .subscribe((e: InteractivityManager.HoverEvent) => { + if ( + e.current && + e.current.loci && + e.current.loci.kind !== "empty-loci" + ) { + const evData = lociDetails(e.current.loci); + if (evData) + dispatchCustomEvent( + pdbevents["PDB.molstar.mouseover"], + evData, + targetElement + ); + } + + if ( + e.current && + e.current.loci && + e.current.loci.kind === "empty-loci" + ) { + dispatchCustomEvent( + pdbevents["PDB.molstar.mouseout"], + {}, + targetElement + ); + } + }); + } +} diff --git a/frontend/venome-molstar/src/app/domain-annotations/behavior.ts b/frontend/venome-molstar/src/app/domain-annotations/behavior.ts new file mode 100644 index 00000000..c9cdb7e8 --- /dev/null +++ b/frontend/venome-molstar/src/app/domain-annotations/behavior.ts @@ -0,0 +1,68 @@ +import { DomainAnnotationsProvider } from "./prop"; +import { DomainAnnotationsColorThemeProvider } from "./color"; +import { Loci } from "molstar/lib/mol-model/loci"; +import { ParamDefinition as PD } from "molstar/lib/mol-util/param-definition"; +import { PluginBehavior } from "molstar/lib/mol-plugin/behavior"; + +export const PDBeDomainAnnotations = PluginBehavior.create<{ + autoAttach: boolean; + showTooltip: boolean; +}>({ + name: "pdbe-domain-annotations-prop", + category: "custom-props", + display: { + name: "Domain annotations", + description: "Data for domain annotations, obtained via PDBe.", + }, + ctor: class extends PluginBehavior.Handler<{ + autoAttach: boolean; + showTooltip: boolean; + }> { + private provider = DomainAnnotationsProvider; + + private labelDomainAnnotations = { + label: (loci: Loci): string | undefined => void 0, + }; + + register(): void { + this.ctx.customModelProperties.register( + this.provider, + this.params.autoAttach + ); + this.ctx.managers.lociLabels.addProvider( + this.labelDomainAnnotations + ); + + this.ctx.representation.structure.themes.colorThemeRegistry.add( + DomainAnnotationsColorThemeProvider + ); + } + + update(p: { autoAttach: boolean; showTooltip: boolean }) { + const updated = this.params.autoAttach !== p.autoAttach; + this.params.autoAttach = p.autoAttach; + this.params.showTooltip = p.showTooltip; + this.ctx.customModelProperties.setDefaultAutoAttach( + this.provider.descriptor.name, + this.params.autoAttach + ); + return updated; + } + + unregister() { + this.ctx.customModelProperties.unregister( + DomainAnnotationsProvider.descriptor.name + ); + this.ctx.managers.lociLabels.removeProvider( + this.labelDomainAnnotations + ); + this.ctx.representation.structure.themes.colorThemeRegistry.remove( + DomainAnnotationsColorThemeProvider + ); + } + }, + params: () => ({ + autoAttach: PD.Boolean(false), + showTooltip: PD.Boolean(true), + }), +}); diff --git a/frontend/venome-molstar/src/app/domain-annotations/color.ts b/frontend/venome-molstar/src/app/domain-annotations/color.ts new file mode 100644 index 00000000..c2d3ff55 --- /dev/null +++ b/frontend/venome-molstar/src/app/domain-annotations/color.ts @@ -0,0 +1,122 @@ +import { DomainAnnotations, DomainAnnotationsProvider } from "./prop"; +import { Location } from "molstar/lib/mol-model/location"; +import { StructureElement } from "molstar/lib/mol-model/structure"; +import { ColorTheme, LocationColor } from "molstar/lib/mol-theme/color"; +import { ThemeDataContext } from "molstar/lib/mol-theme/theme"; +import { Color } from "molstar/lib/mol-util/color"; +import { ParamDefinition as PD } from "molstar/lib/mol-util/param-definition"; +import { CustomProperty } from "molstar/lib/mol-model-props/common/custom-property"; + +const DomainColors = [ + Color.fromRgb(170, 170, 170), // not applicable + Color.fromRgb(255, 112, 3), +]; + +export const DomainAnnotationsColorThemeParams = { + type: PD.MappedStatic("", { + "": PD.EmptyGroup(), + }), +}; + +type Params = any; // typeof DomainAnnotationsColorThemeParams + +export function DomainAnnotationsColorTheme( + ctx: ThemeDataContext, + props: PD.Values +): ColorTheme { + let color: LocationColor; + + if ( + ctx.structure && + !ctx.structure.isEmpty && + ctx.structure.models[0].customProperties.has( + DomainAnnotationsProvider.descriptor + ) + ) { + const getDomains = DomainAnnotations.getDomains; + + const issue = props.type.params.kind; + color = (location: Location) => { + if ( + StructureElement.Location.is(location) && + getDomains(location).indexOf(issue) >= 0 + ) { + return DomainColors[1]; + } + return DomainColors[0]; + }; + } else { + color = () => DomainColors[0]; + } + + return { + factory: DomainAnnotationsColorTheme, + granularity: "group", + color: color, + props: props, + description: + "Highlights Sequnece and Structure Domain Annotations. Data obtained via PDBe.", + }; +} + +export const DomainAnnotationsColorThemeProvider: ColorTheme.Provider< + Params, + "pdbe-domain-annotations" +> = { + name: "pdbe-domain-annotations", + label: "Domain annotations", + category: ColorTheme.Category.Misc, + factory: DomainAnnotationsColorTheme, + getParams: (ctx) => { + const domainNames = DomainAnnotations.getDomainNames(ctx.structure); + const domainTypes = DomainAnnotations.getDomainTypes(ctx.structure); + + const optionObj: any = {}; + domainTypes.forEach((tp, index) => { + if (domainNames[index].length > 0) { + optionObj[tp as string] = PD.Group( + { + kind: PD.Select( + domainNames[index][0] as string, + PD.arrayToOptions(domainNames[index] as string[]) + ), + }, + { isFlat: true } + ); + } + }); + + if (Object.keys(optionObj).length > 0) { + return { + type: PD.MappedStatic(optionObj[0], optionObj), + }; + } else { + return { + type: PD.MappedStatic("", { + "": PD.EmptyGroup(), + }), + }; + } + }, + defaultValues: PD.getDefaultValues(DomainAnnotationsColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => + DomainAnnotations.isApplicable(ctx.structure?.models[0]), + ensureCustomProperties: { + attach: (ctx: CustomProperty.Context, data: ThemeDataContext) => { + return data.structure + ? DomainAnnotationsProvider.attach( + ctx, + data.structure.models[0], + void 0, + true + ) + : Promise.resolve(); + }, + detach: (data) => + data.structure && + data.structure.models[0].customProperties.reference( + DomainAnnotationsProvider.descriptor, + false + ), + }, +}; diff --git a/frontend/venome-molstar/src/app/domain-annotations/prop.ts b/frontend/venome-molstar/src/app/domain-annotations/prop.ts new file mode 100644 index 00000000..05eed54e --- /dev/null +++ b/frontend/venome-molstar/src/app/domain-annotations/prop.ts @@ -0,0 +1,198 @@ +import { + Model, + ResidueIndex, + Unit, + IndexedCustomProperty, +} from "molstar/lib/mol-model/structure"; +import { + StructureElement, + Structure, +} from "molstar/lib/mol-model/structure/structure"; +import { PropertyWrapper } from "molstar/lib/mol-model-props/common/wrapper"; +import { CustomModelProperty } from "molstar/lib/mol-model-props/common/custom-model-property"; +import { ParamDefinition as PD } from "molstar/lib/mol-util/param-definition"; +import { CustomProperty } from "molstar/lib/mol-model-props/common/custom-property"; +import { arraySetAdd } from "molstar/lib/mol-util/array"; +import { Asset } from "molstar/lib/mol-util/assets"; +import { CustomPropertyDescriptor } from "molstar/lib/mol-model/custom-property"; +import { ChainIndex } from "molstar/lib/mol-model/structure/model/indexing"; + +export { DomainAnnotations }; +type DomainAnnotations = PropertyWrapper< + | { + domains: IndexedCustomProperty.Residue; + domainNames: string[][]; + domainTypes: string[]; + } + | undefined +>; + +namespace DomainAnnotations { + export const DefaultServerUrl = "https://www.ebi.ac.uk/pdbe/api/mappings"; + export function getEntryUrl(pdbId: string, serverUrl: string) { + return `${serverUrl}/${pdbId.toLowerCase()}`; + } + + export function isApplicable(model?: Model): boolean { + return !!model && Model.hasPdbId(model); + } + + export function fromJson(model: Model, data: any) { + const info = PropertyWrapper.createInfo(); + const domainMap = createdomainMapFromJson(model, data); + return { info, data: domainMap }; + } + + export async function fromServer( + ctx: CustomProperty.Context, + model: Model, + props: DomainAnnotationsProps + ): Promise> { + const url = Asset.getUrlAsset( + ctx.assetManager, + getEntryUrl(model.entryId, props.serverUrl) + ); + const json = await ctx.assetManager + .resolve(url, "json") + .runInContext(ctx.runtime); + const data = json.data[model.entryId.toLowerCase()]; + if (!data) throw new Error("missing data"); + return { value: fromJson(model, data), assets: [json] }; + } + + const _emptyArray: string[] = []; + export function getDomains(e: StructureElement.Location) { + if (!Unit.isAtomic(e.unit)) return _emptyArray; + const prop = DomainAnnotationsProvider.get(e.unit.model).value; + if (!prop || !prop.data) return _emptyArray; + const rI = e.unit.residueIndex[e.element]; + return prop.data.domains.has(rI) + ? prop.data.domains.get(rI)! + : _emptyArray; + } + + export function getDomainTypes(structure?: Structure) { + if (!structure) return _emptyArray; + const prop = DomainAnnotationsProvider.get(structure.models[0]).value; + if (!prop || !prop.data) return _emptyArray; + return prop.data.domainTypes; + } + + export function getDomainNames(structure?: Structure) { + if (!structure) return _emptyArray; + const prop = DomainAnnotationsProvider.get(structure.models[0]).value; + if (!prop || !prop.data) return _emptyArray; + return prop.data.domainNames; + } +} + +export const DomainAnnotationsParams = { + serverUrl: PD.Text(DomainAnnotations.DefaultServerUrl, { + description: "JSON API Server URL", + }), +}; +export type DomainAnnotationsParams = typeof DomainAnnotationsParams; +export type DomainAnnotationsProps = PD.Values; + +export const DomainAnnotationsProvider: CustomModelProperty.Provider< + DomainAnnotationsParams, + DomainAnnotations +> = CustomModelProperty.createProvider({ + label: "Domain annotations", + descriptor: CustomPropertyDescriptor({ + name: "domain_annotations", + }), + type: "static", + defaultParams: DomainAnnotationsParams, + getParams: (data: Model) => DomainAnnotationsParams, + isApplicable: (data: Model) => DomainAnnotations.isApplicable(data), + obtain: async ( + ctx: CustomProperty.Context, + data: Model, + props: Partial + ) => { + const p = { ...PD.getDefaultValues(DomainAnnotationsParams), ...props }; + return await DomainAnnotations.fromServer(ctx, data, p); + }, +}); + +function findChainLabel( + map: any, + label_entity_id: string, + label_asym_id: string +): ChainIndex { + const entityIndex = map.entities.getEntityIndex; + const eI = entityIndex(label_entity_id); + if (eI < 0 || !map.entity_index_label_asym_id.has(eI)) + return -1 as ChainIndex; + const cm = map.entity_index_label_asym_id.get(eI); + if (!cm) return -1 as ChainIndex; + return cm.has(label_asym_id) ? cm.get(label_asym_id)! : (-1 as ChainIndex); +} + +function findResidue( + modelData: Model, + map: any, + label_entity_id: string, + label_asym_id: string, + label_seq_id: number +) { + const cI = findChainLabel(map, label_entity_id, label_asym_id); + if (cI < 0) return -1 as ResidueIndex; + const rm = map.chain_index_auth_seq_id.get(cI)!; + return rm.has(label_seq_id) ? rm.get(label_seq_id)! : (-1 as ResidueIndex); +} + +function createdomainMapFromJson( + modelData: Model, + data: any +): DomainAnnotations["data"] | undefined { + const domainTypes: string[] = []; + const domainNames: string[][] = []; + const ret = new Map(); + const defaultDomains = ["Pfam", "InterPro", "CATH", "SCOP"]; + + for (const db_name of Object.keys(data)) { + if (defaultDomains.indexOf(db_name) === -1) continue; + const tempDomains: string[] = []; + domainTypes.push(db_name); + const db = data[db_name]; + for (const db_code of Object.keys(db)) { + const domain = db[db_code]; + for (const map of domain.mappings) { + arraySetAdd(tempDomains, domain.identifier); + + const indexData = modelData.atomicHierarchy.index as any; + const indexMap = indexData.map; + for ( + let i = map.start.residue_number; + i <= map.end.residue_number; + i++ + ) { + const seq_id = i; + const idx = findResidue( + modelData, + indexMap, + map.entity_id + "", + map.chain_id, + seq_id + ); + let addVal: string[] = [domain.identifier]; + const prevVal = ret.get(idx); + if (prevVal) { + prevVal.push(domain.identifier); + addVal = prevVal; + } + ret.set(idx, addVal); + } + } + } + domainNames.push(tempDomains); + } + + return { + domains: IndexedCustomProperty.fromResidueMap(ret), + domainNames, + domainTypes, + }; +} diff --git a/frontend/venome-molstar/src/app/helpers.ts b/frontend/venome-molstar/src/app/helpers.ts new file mode 100644 index 00000000..b05790ca --- /dev/null +++ b/frontend/venome-molstar/src/app/helpers.ts @@ -0,0 +1,588 @@ +import { QualityAssessment } from "molstar/lib/extensions/model-archive/quality-assessment/prop"; +import { + Model, + Queries, + QueryContext, + ResidueIndex, + Structure, + StructureProperties, + StructureSelection, +} from "molstar/lib/mol-model/structure"; +import { AtomsQueryParams } from "molstar/lib/mol-model/structure/query/queries/generators"; +import { StructureQuery } from "molstar/lib/mol-model/structure/query/query"; +import { BuiltInTrajectoryFormat } from "molstar/lib/mol-plugin-state/formats/trajectory"; +import { CreateVolumeStreamingInfo } from "molstar/lib/mol-plugin/behavior/dynamic/volume-streaming/transformers"; +import { PluginCommands } from "molstar/lib/mol-plugin/commands"; +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import { MolScriptBuilder as MS } from "molstar/lib/mol-script/language/builder"; +import Expression from "molstar/lib/mol-script/language/expression"; +import { compile } from "molstar/lib/mol-script/runtime/query/compiler"; +import { StateSelection } from "molstar/lib/mol-state"; +import { Task } from "molstar/lib/mol-task"; +import { SIFTSMapping, SIFTSMappingMapping } from "./sifts-mapping"; +import { InitParams } from "./spec"; + +export type SupportedFormats = "mmcif" | "bcif" | "cif" | "pdb" | "sdf"; +export type LoadParams = { + url: string; + format?: BuiltInTrajectoryFormat; + assemblyId?: string; + isHetView?: boolean; + isBinary?: boolean; + progressMessage?: string; +}; + +export type MapParams = { + em?: MapStyle; + "2fo-fc"?: MapStyle; + "fo-fc(+ve)"?: MapStyle; + "fo-fc(-ve)"?: MapStyle; +}; +interface MapStyle { + opacity?: number; + wireframe?: boolean; +} + +export namespace PDBeVolumes { + export function mapParams( + defaultParams: any, + mapParams?: MapParams, + ref?: string | number + ) { + const pdbeParams = { ...defaultParams }; + pdbeParams.options.behaviorRef = + "volume-streaming" + + "" + + Math.floor(Math.random() * Math.floor(100)); + pdbeParams.options.emContourProvider = "pdbe"; + pdbeParams.options.serverUrl = + "https://www.ebi.ac.uk/pdbe/volume-server"; + const MAIN_MAP_DEFAULTS: MapStyle = { opacity: 0.49, wireframe: false }; + const DIFF_MAP_DEFAULTS: MapStyle = { opacity: 0.3, wireframe: true }; + pdbeParams.options.channelParams["em"] = addDefaults( + mapParams?.["em"], + MAIN_MAP_DEFAULTS + ); + pdbeParams.options.channelParams["2fo-fc"] = addDefaults( + mapParams?.["2fo-fc"], + MAIN_MAP_DEFAULTS + ); + pdbeParams.options.channelParams["fo-fc(+ve)"] = addDefaults( + mapParams?.["fo-fc(+ve)"], + DIFF_MAP_DEFAULTS + ); + pdbeParams.options.channelParams["fo-fc(-ve)"] = addDefaults( + mapParams?.["fo-fc(-ve)"], + DIFF_MAP_DEFAULTS + ); + return pdbeParams; + } + + export function displayUsibilityMessage(plugin: PluginContext) { + PluginCommands.Toast.Show(plugin, { + title: "Volume", + message: + "Streaming enabled, click on a residue or an atom to view the data.", + key: "toast-1", + timeoutMs: 7000, + }); + } + + export function toggle(plugin: PluginContext) { + const state = plugin.state.data; + const streamingState = state.select( + StateSelection.Generators.ofTransformer(CreateVolumeStreamingInfo) + )[0]; + + if (streamingState) { + PluginCommands.State.ToggleVisibility(plugin, { + state: state, + ref: streamingState.transform.ref, + }); + return; + } + } +} + +export namespace AlphafoldView { + export function getLociByPLDDT(score: number, contextData: Structure) { + const queryExp = MS.struct.modifier.union([ + MS.struct.modifier.wholeResidues([ + MS.struct.modifier.union([ + MS.struct.generator.atomGroups({ + "chain-test": MS.core.rel.eq([ + MS.ammp("objectPrimitive"), + "atomistic", + ]), + "residue-test": MS.core.rel.gr([ + QualityAssessment.symbols.pLDDT.symbol(), + score, + ]), + }), + ]), + ]), + ]); + + const query = compile(queryExp); + const sel = query(new QueryContext(contextData)); + return StructureSelection.toLociWithSourceUnits(sel); + } +} + +export type LigandQueryParam = { + label_comp_id_list?: any; + auth_asym_id?: string; + struct_asym_id?: string; + label_comp_id?: string; + auth_seq_id?: number; + show_all?: boolean; +}; + +export namespace LigandView { + export function query(ligandViewParams: LigandQueryParam): { + core: Expression.Expression; + surroundings: Expression.Expression; + } { + const atomGroupsParams: any = { + "group-by": MS.core.str.concat([ + MS.struct.atomProperty.core.operatorName(), + MS.struct.atomProperty.macromolecular.residueKey(), + ]), + }; + + // Residue Param + let residueParam: any; + if (ligandViewParams.auth_seq_id !== undefined) { + residueParam = MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_seq_id(), + ligandViewParams.auth_seq_id, + ]); + } else if (ligandViewParams.label_comp_id) { + residueParam = MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.label_comp_id(), + ligandViewParams.label_comp_id, + ]); + } + if (residueParam) atomGroupsParams["residue-test"] = residueParam; + + // Chain Param + if (ligandViewParams.auth_asym_id) { + atomGroupsParams["chain-test"] = MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_asym_id(), + ligandViewParams.auth_asym_id, + ]); + } else if (ligandViewParams.struct_asym_id) { + atomGroupsParams["chain-test"] = MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.label_asym_id(), + ligandViewParams.struct_asym_id, + ]); + } + + // Construct core query + const core = ligandViewParams.show_all + ? MS.struct.generator.atomGroups(atomGroupsParams) + : MS.struct.filter.first([ + MS.struct.generator.atomGroups(atomGroupsParams), + ]); + + // Construct surroundings query + const surroundings = MS.struct.modifier.includeSurroundings({ + 0: core, + radius: 5, + "as-whole-residues": true, + }); + + return { + core, + surroundings, + }; + } + + export function branchedQuery(params: any): { + core: Expression.Expression; + surroundings: Expression.Expression; + } { + const entityObjArray: any[] = []; + + params.atom_site.forEach((param: any) => { + const qEntities = { + "group-by": MS.core.str.concat([ + MS.struct.atomProperty.core.operatorName(), + MS.struct.atomProperty.macromolecular.residueKey(), + ]), + "residue-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_seq_id(), + param.auth_seq_id, + ]), + }; + entityObjArray.push(qEntities); + }); + + const atmGroupsQueries: Expression.Expression[] = []; + + entityObjArray.forEach((entityObj: any) => { + atmGroupsQueries.push(MS.struct.generator.atomGroups(entityObj)); + }); + + const core = MS.struct.modifier.union([ + atmGroupsQueries.length === 1 + ? atmGroupsQueries[0] + : // Need to union before merge for fast performance + MS.struct.combinator.merge( + atmGroupsQueries.map((q) => + MS.struct.modifier.union([q]) + ) + ), + ]); + + // Construct surroundings query + const surroundings = MS.struct.modifier.includeSurroundings({ + 0: core, + radius: 5, + "as-whole-residues": true, + }); + + return { + core, + surroundings, + }; + } +} + +export type QueryParam = { + auth_seq_id?: number; + entity_id?: string; + auth_asym_id?: string; + struct_asym_id?: string; + residue_number?: number; + start_residue_number?: number; + end_residue_number?: number; + auth_residue_number?: number; + auth_ins_code_id?: string; + start_auth_residue_number?: number; + start_auth_ins_code_id?: string; + end_auth_residue_number?: number; + end_auth_ins_code_id?: string; + atoms?: string[]; + label_comp_id?: string; + color?: any; + sideChain?: boolean; + representation?: string; + representationColor?: any; + focus?: boolean; + tooltip?: string; + start?: any; + end?: any; + atom_id?: number[]; + uniprot_accession?: string; + uniprot_residue_number?: number; + start_uniprot_residue_number?: number; + end_uniprot_residue_number?: number; +}; + +export namespace QueryHelper { + export function getQueryObject( + params: QueryParam[], + contextData: any + ): Expression.Expression { + const selections: Partial[] = []; + let siftMappings: SIFTSMappingMapping | undefined; + let currentAccession: string; + + params.forEach((param) => { + const selection: Partial = {}; + + // entity + if (param.entity_id) + selection["entityTest"] = (l) => + StructureProperties.entity.id(l.element) === + param.entity_id; + + // chain + if (param.struct_asym_id) { + selection["chainTest"] = (l) => + StructureProperties.chain.label_asym_id(l.element) === + param.struct_asym_id; + } else if (param.auth_asym_id) { + selection["chainTest"] = (l) => + StructureProperties.chain.auth_asym_id(l.element) === + param.auth_asym_id; + } + + // residues + if (param.label_comp_id) { + selection["residueTest"] = (l) => + StructureProperties.atom.label_comp_id(l.element) === + param.label_comp_id; + } else if ( + param.uniprot_accession && + param.uniprot_residue_number !== undefined + ) { + selection["residueTest"] = (l) => { + if ( + !siftMappings || + currentAccession !== param.uniprot_accession + ) { + siftMappings = SIFTSMapping.Provider.get( + contextData.models[0] + ).value; + currentAccession = param.uniprot_accession!; + } + const rI = StructureProperties.residue.key(l.element); + return ( + !!siftMappings && + param.uniprot_accession === + siftMappings.accession[rI] && + param.uniprot_residue_number === +siftMappings.num[rI] + ); + }; + } else if ( + param.uniprot_accession && + param.start_uniprot_residue_number !== undefined && + param.end_uniprot_residue_number !== undefined + ) { + selection["residueTest"] = (l) => { + if ( + !siftMappings || + currentAccession !== param.uniprot_accession + ) { + siftMappings = SIFTSMapping.Provider.get( + contextData.models[0] + ).value; + currentAccession = param.uniprot_accession!; + } + const rI = StructureProperties.residue.key(l.element); + return ( + !!siftMappings && + param.uniprot_accession === + siftMappings.accession[rI] && + param.start_uniprot_residue_number! <= + +siftMappings.num[rI] && + param.end_uniprot_residue_number! >= + +siftMappings.num[rI] + ); + }; + } else if (param.residue_number !== undefined) { + selection["residueTest"] = (l) => + StructureProperties.residue.label_seq_id(l.element) === + param.residue_number; + } else if ( + param.start_residue_number !== undefined && + param.end_residue_number !== undefined && + param.end_residue_number > param.start_residue_number + ) { + selection["residueTest"] = (l) => { + const labelSeqId = StructureProperties.residue.label_seq_id( + l.element + ); + return ( + labelSeqId >= param.start_residue_number! && + labelSeqId <= param.end_residue_number! + ); + }; + } else if ( + param.start_residue_number !== undefined && + param.end_residue_number !== undefined && + param.end_residue_number === param.start_residue_number + ) { + selection["residueTest"] = (l) => + StructureProperties.residue.label_seq_id(l.element) === + param.start_residue_number; + } else if (param.auth_seq_id !== undefined) { + selection["residueTest"] = (l) => + StructureProperties.residue.auth_seq_id(l.element) === + param.auth_seq_id; + } else if ( + param.auth_residue_number !== undefined && + !param.auth_ins_code_id + ) { + selection["residueTest"] = (l) => + StructureProperties.residue.auth_seq_id(l.element) === + param.auth_residue_number; + } else if ( + param.auth_residue_number !== undefined && + param.auth_ins_code_id + ) { + selection["residueTest"] = (l) => + StructureProperties.residue.auth_seq_id(l.element) === + param.auth_residue_number; + } else if ( + param.start_auth_residue_number !== undefined && + param.end_auth_residue_number !== undefined && + param.end_auth_residue_number > param.start_auth_residue_number + ) { + selection["residueTest"] = (l) => { + const authSeqId = StructureProperties.residue.auth_seq_id( + l.element + ); + return ( + authSeqId >= param.start_auth_residue_number! && + authSeqId <= param.end_auth_residue_number! + ); + }; + } else if ( + param.start_auth_residue_number !== undefined && + param.end_auth_residue_number !== undefined && + param.end_auth_residue_number === + param.start_auth_residue_number + ) { + selection["residueTest"] = (l) => + StructureProperties.residue.auth_seq_id(l.element) === + param.start_auth_residue_number; + } + + // atoms + if (param.atoms) { + selection["atomTest"] = (l) => + param.atoms!.includes( + StructureProperties.atom.label_atom_id(l.element) + ); + } + + if (param.atom_id) { + selection["atomTest"] = (l) => + param.atom_id!.includes( + StructureProperties.atom.id(l.element) + ); + } + + selections.push(selection); + }); + + const atmGroupsQueries: StructureQuery[] = []; + selections.forEach((selection) => { + atmGroupsQueries.push(Queries.generators.atoms(selection)); + }); + + return Queries.combinators.merge(atmGroupsQueries); + } + + export function getInteractivityLoci(params: any, contextData: any) { + const sel = StructureQuery.run( + QueryHelper.getQueryObject(params, contextData) as any, + contextData + ); + return StructureSelection.toLociWithSourceUnits(sel); + } + + export function getHetLoci( + queryExp: Expression.Expression, + contextData: any + ) { + const query = compile(queryExp); + const sel = query(new QueryContext(contextData)); + return StructureSelection.toLociWithSourceUnits(sel); + } +} + +export interface ModelInfo { + hetNames: string[]; + carbEntityCount: number; +} + +export namespace ModelInfo { + export async function get( + model: Model, + structures: any + ): Promise { + const { _rowCount: residueCount } = model.atomicHierarchy.residues; + const { offsets: residueOffsets } = + model.atomicHierarchy.residueAtomSegments; + const chainIndex = model.atomicHierarchy.chainAtomSegments.index; + + const hetNames: ModelInfo["hetNames"] = []; + let carbEntityCount: ModelInfo["carbEntityCount"] = 0; + for (let rI = 0 as ResidueIndex; rI < residueCount; rI++) { + const cI = chainIndex[residueOffsets[rI]]; + const eI = model.atomicHierarchy.index.getEntityFromChain(cI); + const entityType = model.entities.data.type.value(eI); + + if (entityType !== "non-polymer" && entityType !== "branched") + continue; + + // const comp_id = model.atomicHierarchy.atoms.label_comp_id.value(rI); + const comp_id = model.atomicHierarchy.atoms.label_comp_id.value( + residueOffsets[rI] + ); + if (entityType === "branched") { + carbEntityCount++; + } else { + if (hetNames.indexOf(comp_id) === -1) hetNames.push(comp_id); + } + } + + return { + hetNames, + carbEntityCount, + }; + } +} + +/** Run `action` with showing a message in the bottom-left corner of the plugin UI */ +export async function runWithProgressMessage( + plugin: PluginContext, + progressMessage: string | undefined, + action: () => any +) { + const task = Task.create(progressMessage ?? "Task", async (ctx) => { + let done = false; + try { + if (progressMessage) { + setTimeout(() => { + if (!done) ctx.update(progressMessage); + }, 1000); // Delay the first update to force showing message in UI + } + await action(); + } finally { + done = true; + } + }); + await plugin.runTask(task); +} + +/** Parameters for a request to ModelServer */ +export interface ModelServerRequest { + pdbId: string; + queryType: "full" | "residueSurroundings" | "atoms"; // add more when needed + queryParams?: Record; +} + +/** Return URL for a ModelServer request. + * If `queryType` is 'full' and `lowPrecisionCoords` is false, return URL of the static file instead (updated mmCIF or bCIF). */ +export function getStructureUrl( + initParams: InitParams, + request: ModelServerRequest +) { + const pdbeUrl = initParams.pdbeUrl.replace(/\/$/, ""); // without trailing slash + const useStaticFile = + request.queryType === "full" && !initParams.lowPrecisionCoords; + if (useStaticFile) { + const suffix = + initParams.encoding === "bcif" ? ".bcif" : "_updated.cif"; + return `${pdbeUrl}/entry-files/download/${request.pdbId}${suffix}`; + } else { + const queryParams = { + ...request.queryParams, + encoding: initParams.encoding, + lowPrecisionCoords: initParams.lowPrecisionCoords ? 1 : undefined, + }; + const queryString = Object.entries(queryParams) + .filter(([key, value]) => value !== undefined) + .map(([key, value]) => `${key}=${value}`) + .join("&"); + const url = `${pdbeUrl}/model-server/v1/${request.pdbId}/${request.queryType}`; + return queryString !== "" ? `${url}?${queryString}` : url; + } +} + +/** Create a copy of object `object`, fill in missing/undefined keys using `defaults` */ +export function addDefaults( + object: Partial | undefined, + defaults: T +): T { + const result: Partial = { ...object }; + for (const key in defaults) { + result[key] ??= defaults[key]; + } + return result as T; +} diff --git a/frontend/venome-molstar/src/app/index.ts b/frontend/venome-molstar/src/app/index.ts new file mode 100644 index 00000000..4720a281 --- /dev/null +++ b/frontend/venome-molstar/src/app/index.ts @@ -0,0 +1,1255 @@ +import { GeometryExport } from "molstar/lib/extensions/geo-export"; +import { MAQualityAssessment } from "molstar/lib/extensions/model-archive/quality-assessment/behavior"; +import { Mp4Export } from "molstar/lib/extensions/mp4-export"; +import { PDBeStructureQualityReport } from "molstar/lib/extensions/pdbe"; +import { + RCSBAssemblySymmetry, + RCSBAssemblySymmetryConfig, +} from "molstar/lib/extensions/rcsb/assembly-symmetry/behavior"; +import { Canvas3DProps } from "molstar/lib/mol-canvas3d/canvas3d"; +import { EmptyLoci, Loci } from "molstar/lib/mol-model/loci"; +import { AnimateAssemblyUnwind } from "molstar/lib/mol-plugin-state/animation/built-in/assembly-unwind"; +import { AnimateCameraRock } from "molstar/lib/mol-plugin-state/animation/built-in/camera-rock"; +import { AnimateCameraSpin } from "molstar/lib/mol-plugin-state/animation/built-in/camera-spin"; +import { AnimateModelIndex } from "molstar/lib/mol-plugin-state/animation/built-in/model-index"; +import { AnimateStructureSpin } from "molstar/lib/mol-plugin-state/animation/built-in/spin-structure"; +import { AnimateStateInterpolation } from "molstar/lib/mol-plugin-state/animation/built-in/state-interpolation"; +import { AnimateStateSnapshots } from "molstar/lib/mol-plugin-state/animation/built-in/state-snapshots"; +import { BuiltInTrajectoryFormat } from "molstar/lib/mol-plugin-state/formats/trajectory"; +import { clearStructureOverpaint } from "molstar/lib/mol-plugin-state/helpers/structure-overpaint"; +import { createStructureRepresentationParams } from "molstar/lib/mol-plugin-state/helpers/structure-representation-params"; +import { StructureComponentManager } from "molstar/lib/mol-plugin-state/manager/structure/component"; +import { PluginStateObject } from "molstar/lib/mol-plugin-state/objects"; +import { createPluginUI } from "molstar/lib/mol-plugin-ui/react18"; +import { PluginUISpec } from "molstar/lib/mol-plugin-ui/spec"; +import { FocusLoci } from "molstar/lib/mol-plugin/behavior/dynamic/camera"; +import { SelectLoci } from "molstar/lib/mol-plugin/behavior/dynamic/representation"; +import { StructureFocusRepresentation } from "molstar/lib/mol-plugin/behavior/dynamic/selection/structure-focus-representation"; +import { InitVolumeStreaming } from "molstar/lib/mol-plugin/behavior/dynamic/volume-streaming/transformers"; +import { PluginCommands } from "molstar/lib/mol-plugin/commands"; +import { PluginConfig } from "molstar/lib/mol-plugin/config"; +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import { PluginLayoutStateParams } from "molstar/lib/mol-plugin/layout"; +import { PluginSpec } from "molstar/lib/mol-plugin/spec"; +import { Representation } from "molstar/lib/mol-repr/representation"; +import { StateSelection, StateTransform } from "molstar/lib/mol-state"; +import { ElementSymbolColorThemeParams } from "molstar/lib/mol-theme/color/element-symbol"; +import { Asset } from "molstar/lib/mol-util/assets"; +import { Color } from "molstar/lib/mol-util/color/color"; +import { ParamDefinition } from "molstar/lib/mol-util/param-definition"; +import { RxEventHelper } from "molstar/lib/mol-util/rx-event-helper"; +import { CustomEvents } from "./custom-events"; +import { PDBeDomainAnnotations } from "./domain-annotations/behavior"; +import { + AlphafoldView, + LigandView, + LoadParams, + ModelServerRequest, + PDBeVolumes, + QueryHelper, + QueryParam, + addDefaults, + getStructureUrl, + runWithProgressMessage, +} from "./helpers"; +import { LoadingOverlay } from "./overlay"; +import { PluginCustomState } from "./plugin-custom-state"; +import { + ColorParams, + DefaultParams, + DefaultPluginUISpec, + InitParams, + validateInitParams, +} from "./spec"; +import { initParamsFromHtmlAttributes } from "./spec-from-html"; +import { subscribeToComponentEvents } from "./subscribe-events"; +import { initSuperposition } from "./superposition"; +import { SuperpositionFocusRepresentation } from "./superposition-focus-representation"; +import { LeftPanelControls } from "./ui/pdbe-left-panel"; +import { + PDBeLigandViewStructureTools, + PDBeStructureTools, + PDBeSuperpositionStructureTools, +} from "./ui/pdbe-structure-controls"; +import { PDBeViewportControls } from "./ui/pdbe-viewport-controls"; +import { SuperpostionViewport } from "./ui/superposition-viewport"; + +import "molstar/lib/mol-plugin-ui/skin/dark.scss"; +import "./overlay.scss"; + +export class PDBeMolstarPlugin { + private _ev = RxEventHelper.create(); + + readonly events = { + loadComplete: this._ev(), + }; + + plugin: PluginContext; + initParams: InitParams; + targetElement: HTMLElement; + assemblyRef = ""; + selectedParams: any; + defaultRendererProps: Canvas3DProps["renderer"]; + defaultMarkingProps: Canvas3DProps["marking"]; + isHighlightColorUpdated = false; + isSelectedColorUpdated = false; + + /** Extract InitParams from attributes of an HTML element */ + static initParamsFromHtmlAttributes( + element: HTMLElement + ): Partial { + return initParamsFromHtmlAttributes(element); + } + + async render(target: string | HTMLElement, options: Partial) { + console.debug( + "Rendering PDBeMolstarPlugin instance with options:", + options + ); + // Validate options + if (!options) { + console.error( + "Missing `options` argument to `PDBeMolstarPlugin.render" + ); + return; + } + const validationIssues = validateInitParams(options); + if (validationIssues) { + console.error("Invalid PDBeMolstarPlugin options:", options); + return; + } + this.initParams = addDefaults(options, DefaultParams); + + // Set PDBe Plugin Spec + const pdbePluginSpec: PluginUISpec = DefaultPluginUISpec(); + pdbePluginSpec.config ??= []; + + if ( + !this.initParams.ligandView && + !this.initParams.superposition && + this.initParams.selectInteraction + ) { + pdbePluginSpec.behaviors.push( + PluginSpec.Behavior(StructureFocusRepresentation) + ); + } + + if (this.initParams.superposition) { + pdbePluginSpec.behaviors.push( + PluginSpec.Behavior(SuperpositionFocusRepresentation), + PluginSpec.Behavior(MAQualityAssessment, { + autoAttach: true, + showTooltip: true, + }) + ); + } + + // Add custom properties + if (this.initParams.domainAnnotation) { + pdbePluginSpec.behaviors.push( + PluginSpec.Behavior(PDBeDomainAnnotations, { + autoAttach: true, + showTooltip: false, + }) + ); + } + if (this.initParams.validationAnnotation) { + pdbePluginSpec.behaviors.push( + PluginSpec.Behavior(PDBeStructureQualityReport, { + autoAttach: true, + showTooltip: false, + }) + ); + } + if (this.initParams.symmetryAnnotation) { + pdbePluginSpec.behaviors.push( + PluginSpec.Behavior(RCSBAssemblySymmetry) + ); + pdbePluginSpec.config.push( + [RCSBAssemblySymmetryConfig.DefaultServerType, "pdbe"], + [ + RCSBAssemblySymmetryConfig.DefaultServerUrl, + "https://www.ebi.ac.uk/pdbe/aggregated-api/pdb/symmetry", + ], + [RCSBAssemblySymmetryConfig.ApplyColors, false] + ); + } + + pdbePluginSpec.layout = { + initial: { + isExpanded: this.initParams.expanded, + showControls: !this.initParams.hideControls, + regionState: { + left: "full", + right: "full", + top: this.initParams.sequencePanel ? "full" : "hidden", + bottom: "full", + }, + controlsDisplay: this.initParams.reactive + ? "reactive" + : this.initParams.landscape + ? "landscape" + : PluginLayoutStateParams.controlsDisplay.defaultValue, + }, + }; + + pdbePluginSpec.components = { + controls: { + left: LeftPanelControls, + // right: DefaultStructureTools, + // top: 'none', + bottom: "none", + }, + viewport: { + controls: PDBeViewportControls, + view: this.initParams.superposition + ? SuperpostionViewport + : void 0, + }, + remoteState: "none", + structureTools: this.initParams.superposition + ? PDBeSuperpositionStructureTools + : this.initParams.ligandView + ? PDBeLigandViewStructureTools + : PDBeStructureTools, + }; + + if (this.initParams.alphafoldView) { + pdbePluginSpec.behaviors.push( + PluginSpec.Behavior(MAQualityAssessment, { + autoAttach: true, + showTooltip: true, + }) + ); + } + + pdbePluginSpec.config.push([ + PluginConfig.Structure.DefaultRepresentationPresetParams, + { + theme: { + globalName: this.initParams.alphafoldView + ? "plddt-confidence" + : undefined, + carbonColor: { name: "element-symbol", params: {} }, + focus: { + name: "element-symbol", + params: { + carbonColor: { name: "element-symbol", params: {} }, + }, + }, + }, + }, + ]); + + ElementSymbolColorThemeParams.carbonColor.defaultValue = { + name: "element-symbol", + params: {}, + }; + + // Add animation props + if (!this.initParams.ligandView && !this.initParams.superposition) { + pdbePluginSpec.animations = [ + AnimateModelIndex, + AnimateCameraSpin, + AnimateCameraRock, + AnimateStateSnapshots, + AnimateAssemblyUnwind, + AnimateStructureSpin, + AnimateStateInterpolation, + ]; + pdbePluginSpec.behaviors.push(PluginSpec.Behavior(Mp4Export)); + pdbePluginSpec.behaviors.push(PluginSpec.Behavior(GeometryExport)); + } + + if (this.initParams.hideCanvasControls.includes("expand")) + pdbePluginSpec.config.push([ + PluginConfig.Viewport.ShowExpand, + false, + ]); + if (this.initParams.hideCanvasControls.includes("selection")) + pdbePluginSpec.config.push([ + PluginConfig.Viewport.ShowSelectionMode, + false, + ]); + if (this.initParams.hideCanvasControls.includes("animation")) + pdbePluginSpec.config.push([ + PluginConfig.Viewport.ShowAnimation, + false, + ]); + if (this.initParams.hideCanvasControls.includes("controlToggle")) + pdbePluginSpec.config.push([ + PluginConfig.Viewport.ShowControls, + false, + ]); + if (this.initParams.hideCanvasControls.includes("controlInfo")) + pdbePluginSpec.config.push([ + PluginConfig.Viewport.ShowSettings, + false, + ]); + + // override default event bindings + if (this.initParams.selectBindings) { + pdbePluginSpec.behaviors.push( + PluginSpec.Behavior(SelectLoci, { + bindings: this.initParams.selectBindings, + }) + ); + } + + if (this.initParams.focusBindings) { + pdbePluginSpec.behaviors.push( + PluginSpec.Behavior(FocusLoci, { + bindings: this.initParams.focusBindings, + }) + ); + } + + this.targetElement = + typeof target === "string" + ? document.getElementById(target)! + : target; + (this.targetElement as any).viewerInstance = this; + + // Create/ Initialise Plugin + this.plugin = await createPluginUI(this.targetElement, pdbePluginSpec); + PluginCustomState(this.plugin).initParams = { ...this.initParams }; + PluginCustomState(this.plugin).events = { + segmentUpdate: this._ev(), + superpositionInit: this._ev(), + isBusy: this._ev(), + }; + + // Set background colour + if (this.initParams.bgColor || this.initParams.lighting) { + this.canvas.applySettings({ + color: this.initParams.bgColor, + lighting: this.initParams.lighting, + }); + } + + // Set selection granularity + if (this.initParams.granularity) { + this.plugin.managers.interactivity.setProps({ + granularity: this.initParams.granularity, + }); + } + + // Set default highlight and selection colors + if (this.initParams.highlightColor || this.initParams.selectColor) { + this.visual.setColor({ + highlight: this.initParams.highlightColor, + select: this.initParams.selectColor, + }); + } + + // Save renderer defaults + this.defaultRendererProps = { ...this.plugin.canvas3d!.props.renderer }; + this.defaultMarkingProps = { ...this.plugin.canvas3d!.props.marking }; + + if (this.initParams.superposition) { + // Set left panel tab + this.plugin.behaviors.layout.leftPanelTabName.next( + "segments" as any + ); + + // Initialise superposition + if (this.initParams.loadingOverlay) { + new LoadingOverlay(this.targetElement, { + resize: this.plugin?.canvas3d?.resized, + hide: this.events.loadComplete, + }).show(); + } + initSuperposition(this.plugin, this.events.loadComplete); + } else { + // Collapse left panel and set left panel tab to none + PluginCommands.Layout.Update(this.plugin, { + state: { + regionState: { + ...this.plugin.layout.state.regionState, + left: "collapsed", + }, + }, + }); + this.plugin.behaviors.layout.leftPanelTabName.next("none"); + + // Load Molecule CIF or coordQuery and Parse + const dataSource = this.getMoleculeSrcUrl(); + if (dataSource) { + if (this.initParams.loadingOverlay) { + new LoadingOverlay(this.targetElement, { + resize: this.plugin?.canvas3d?.resized, + hide: this.events.loadComplete, + }).show(); + } + this.load({ + url: dataSource.url, + format: dataSource.format as BuiltInTrajectoryFormat, + assemblyId: this.initParams.assemblyId, + isBinary: dataSource.isBinary, + progressMessage: `Loading ${ + this.initParams.moleculeId ?? "" + } ...`, + }); + } + + // Binding to other PDB Component events + if (this.initParams.subscribeEvents) { + subscribeToComponentEvents(this); + } + + // Event handling + CustomEvents.add(this.plugin, this.targetElement); + } + } + + getMoleculeSrcUrl() { + if (this.initParams.customData) { + let { url, format, binary } = this.initParams.customData; + if (!url || !format) { + throw new Error(`Provide all custom data parameters`); + } + if (format === "cif" || format === "bcif") format = "mmcif"; + // Validate supported format + const supportedFormats = ["mmcif", "pdb", "sdf"]; + if (!supportedFormats.includes(format)) { + throw new Error(`${format} not supported.`); + } + return { + url: url, + format: format, + isBinary: binary, + }; + } + + if (this.initParams.moleculeId) { + const request: Required = { + pdbId: this.initParams.moleculeId, + queryType: "full", + queryParams: {}, + }; + if (this.initParams.ligandView) { + request.queryType = "residueSurroundings"; + request.queryParams["data_source"] = "pdb-h"; + if (!this.initParams.ligandView.label_comp_id_list) { + request.queryParams["label_comp_id"] = + this.initParams.ligandView.label_comp_id; + request.queryParams["auth_seq_id"] = + this.initParams.ligandView.auth_seq_id; + request.queryParams["auth_asym_id"] = + this.initParams.ligandView.auth_asym_id; + } + } + return { + url: getStructureUrl(this.initParams, request), + format: "mmcif", + isBinary: this.initParams.encoding === "bcif", + }; + } + + throw new Error( + `Mandatory parameters missing! (customData or moleculeId must be defined)` + ); + } + + screenshotData() { + return this.plugin.helpers.viewportScreenshot?.getImageDataUri(); + } + + get state() { + return this.plugin.state.data; + } + + async createLigandStructure(isBranched: boolean) { + if (this.assemblyRef === "") return; + for await (const comp of this.plugin.managers.structure.hierarchy + .currentComponentGroups) { + await PluginCommands.State.RemoveObject(this.plugin, { + state: comp[0].cell.parent!, + ref: comp[0].cell.transform.ref, + removeParentGhosts: true, + }); + } + + const structure = this.state.select(this.assemblyRef)[0]; + + let ligandQuery; + if (isBranched) { + ligandQuery = LigandView.branchedQuery( + this.initParams.ligandView?.label_comp_id_list! + ); + } else { + ligandQuery = LigandView.query(this.initParams.ligandView!); + } + + const ligandVis = + await this.plugin.builders.structure.tryCreateComponentFromExpression( + structure, + ligandQuery.core, + "pivot", + { label: "Ligand" } + ); + if (ligandVis) + await this.plugin.builders.structure.representation.addRepresentation( + ligandVis, + { + type: "ball-and-stick", + color: "element-symbol", + colorParams: { + carbonColor: { name: "element-symbol", params: {} }, + }, + size: "uniform", + sizeParams: { value: 2.5 }, + }, + { tag: "ligand-vis" } + ); + + const ligandSurr = + await this.plugin.builders.structure.tryCreateComponentFromExpression( + structure, + ligandQuery.surroundings, + "rest", + { label: "Surroundings" } + ); + if (ligandSurr) + await this.plugin.builders.structure.representation.addRepresentation( + ligandSurr, + { + type: "ball-and-stick", + color: "element-symbol", + colorParams: { + carbonColor: { name: "element-symbol", params: {} }, + }, + size: "uniform", + sizeParams: { value: 0.8 }, + } + ); + + // Focus ligand + const ligRef = StateSelection.findTagInSubtree( + this.plugin.state.data.tree, + StateTransform.RootRef, + "ligand-vis" + ); + if (!ligRef) return; + const cell = this.plugin.state.data.cells.get(ligRef)!; + if (cell?.obj) { + const repr = cell.obj.data.repr as Representation; + const ligLoci = repr.getAllLoci()[0]; // getAllLoci returns multiple copies of the same loci (one per representation visual) + this.plugin.managers.structure.focus.setFromLoci(ligLoci); + // focus-add is not handled in camera behavior, doing it here + const current = this.plugin.managers.structure.focus.current?.loci; + if (current) this.plugin.managers.camera.focusLoci(current); + } + } + + async load( + { + url, + format = "mmcif", + isBinary = false, + assemblyId = "", + progressMessage, + }: LoadParams, + fullLoad = true + ) { + await runWithProgressMessage(this.plugin, progressMessage, async () => { + let success = false; + try { + if (fullLoad) await this.clear(); + const isHetView = this.initParams.ligandView ? true : false; + let downloadOptions: any = void 0; + let isBranchedView = false; + if ( + this.initParams.ligandView && + this.initParams.ligandView.label_comp_id_list + ) { + isBranchedView = true; + downloadOptions = { + body: JSON.stringify( + this.initParams.ligandView.label_comp_id_list + ), + headers: [["Content-type", "application/json"]], + }; + } + + const data = await this.plugin.builders.data.download( + { url: Asset.Url(url, downloadOptions), isBinary }, + { state: { isGhost: true } } + ); + const trajectory = + await this.plugin.builders.structure.parseTrajectory( + data, + format + ); + + if (!isHetView) { + await this.plugin.builders.structure.hierarchy.applyPreset( + trajectory, + this.initParams.defaultPreset as any, + { + structure: assemblyId + ? assemblyId === "preferred" + ? void 0 + : { + name: "assembly", + params: { id: assemblyId }, + } + : { name: "model", params: {} }, + showUnitcell: false, + representationPreset: "auto", + } + ); + + if ( + this.initParams.hideStructure.length > 0 || + this.initParams.visualStyle + ) { + this.applyVisualParams(); + } + } else { + const model = + await this.plugin.builders.structure.createModel( + trajectory + ); + await this.plugin.builders.structure.createStructure( + model, + { name: "model", params: {} } + ); + } + + // show selection if param is set + if (this.initParams.selection) { + this.visual.select(this.initParams.selection); + } + + // Store assembly ref + const pivotIndex = + this.plugin.managers.structure.hierarchy.selection + .structures.length - 1; + const pivot = + this.plugin.managers.structure.hierarchy.selection + .structures[pivotIndex]; + if (pivot && pivot.cell.parent) + this.assemblyRef = pivot.cell.transform.ref; + + // Load Volume + if (this.initParams.loadMaps) { + if (this.assemblyRef === "") return; + const asm = this.state.select(this.assemblyRef)[0].obj!; + const defaultMapParams = + InitVolumeStreaming.createDefaultParams( + asm, + this.plugin + ); + const pdbeMapParams = PDBeVolumes.mapParams( + defaultMapParams, + this.initParams.mapSettings, + "" + ); + if (pdbeMapParams) { + await this.plugin.runTask( + this.state.applyAction( + InitVolumeStreaming, + pdbeMapParams, + this.assemblyRef + ) + ); + if ( + pdbeMapParams.method !== "em" && + !this.initParams.ligandView + ) + PDBeVolumes.displayUsibilityMessage(this.plugin); + } + } + + // Create Ligand Representation + if (isHetView) { + await this.createLigandStructure(isBranchedView); + } + success = true; + } finally { + this.events.loadComplete.next(success); + } + }); + } + + applyVisualParams = () => { + const componentGroups = + this.plugin.managers.structure.hierarchy.currentComponentGroups; + for (const compGroup of componentGroups) { + const compRef = compGroup[compGroup.length - 1]; + const tag = compRef.key ?? ""; + const remove = this.initParams.hideStructure.some((type) => + StructureComponentTags[type]?.includes(tag) + ); + if (remove) { + this.plugin.managers.structure.hierarchy.remove([compRef]); + } + if (!remove && this.initParams.visualStyle) { + if (compRef && compRef.representations) { + compRef.representations.forEach((rep) => { + const currentParams = + createStructureRepresentationParams( + this.plugin, + void 0, + { type: this.initParams.visualStyle } + ); + this.plugin.managers.structure.component.updateRepresentations( + [compRef], + rep, + currentParams + ); + }); + } + } + } + }; + + canvas = { + toggleControls: (isVisible?: boolean) => { + if (typeof isVisible === "undefined") + isVisible = !this.plugin.layout.state.showControls; + PluginCommands.Layout.Update(this.plugin, { + state: { showControls: isVisible }, + }); + }, + + toggleExpanded: (isExpanded?: boolean) => { + if (typeof isExpanded === "undefined") + isExpanded = !this.plugin.layout.state.isExpanded; + PluginCommands.Layout.Update(this.plugin, { + state: { isExpanded: isExpanded }, + }); + }, + + setBgColor: async (color?: { r: number; g: number; b: number }) => { + if (!color) return; + await this.canvas.applySettings({ color }); + }, + + applySettings: async (settings?: { + color?: { r: number; g: number; b: number }; + lighting?: string; + }) => { + if (!settings) return; + if (!this.plugin.canvas3d) return; + const renderer = { ...this.plugin.canvas3d.props.renderer }; + if (settings.color) { + renderer.backgroundColor = Color.fromRgb( + settings.color.r, + settings.color.g, + settings.color.b + ); + } + if (settings.lighting) { + (renderer as any).style = { name: settings.lighting }; // I don't think this does anything and I don't see how it could ever have worked + } + await PluginCommands.Canvas3D.SetSettings(this.plugin, { + settings: { renderer }, + }); + }, + }; + + getLociForParams(params: QueryParam[], structureNumber?: number) { + let assemblyRef = this.assemblyRef; + if (structureNumber) { + assemblyRef = + this.plugin.managers.structure.hierarchy.current.structures[ + structureNumber - 1 + ].cell.transform.ref; + } + + if (assemblyRef === "") return EmptyLoci; + const data = ( + this.plugin.state.data.select(assemblyRef)[0] + .obj as PluginStateObject.Molecule.Structure + ).data; + if (!data) return EmptyLoci; + return QueryHelper.getInteractivityLoci(params, data); + } + + getLociByPLDDT(score: number, structureNumber?: number) { + let assemblyRef = this.assemblyRef; + if (structureNumber) { + assemblyRef = + this.plugin.managers.structure.hierarchy.current.structures[ + structureNumber - 1 + ].cell.transform.ref; + } + + if (assemblyRef === "") return EmptyLoci; + const data = ( + this.plugin.state.data.select(assemblyRef)[0] + .obj as PluginStateObject.Molecule.Structure + ).data; + if (!data) return EmptyLoci; + return AlphafoldView.getLociByPLDDT(score, data); + } + + normalizeColor(colorVal: any, defaultColor?: Color) { + let color = Color.fromRgb(170, 170, 170); + try { + if (typeof colorVal.r !== "undefined") { + color = Color.fromRgb(colorVal.r, colorVal.g, colorVal.b); + } else if (colorVal[0] === "#") { + color = Color(Number(`0x${colorVal.substr(1)}`)); + } else { + color = Color(colorVal); + } + } catch (e) { + if (defaultColor) color = defaultColor; + } + return color; + } + + visual = { + highlight: (params: { + data: QueryParam[]; + color?: any; + focus?: boolean; + structureNumber?: number; + }) => { + const loci = this.getLociForParams( + params.data, + params.structureNumber + ); + if (Loci.isEmpty(loci)) return; + if (params.color) { + this.visual.setColor({ highlight: params.color }); + } + this.plugin.managers.interactivity.lociHighlights.highlightOnly({ + loci, + }); + if (params.focus) this.plugin.managers.camera.focusLoci(loci); + }, + clearHighlight: async () => { + this.plugin.managers.interactivity.lociHighlights.highlightOnly({ + loci: EmptyLoci, + }); + if (this.isHighlightColorUpdated) + this.visual.reset({ highlightColor: true }); + }, + select: async (params: { + data: QueryParam[]; + nonSelectedColor?: any; + addedRepr?: boolean; + structureNumber?: number; + }) => { + // clear prvious selection + if (this.selectedParams) { + await this.visual.clearSelection(params.structureNumber); + } + + // Structure list to apply selection + let structureData = + this.plugin.managers.structure.hierarchy.current.structures; + if (params.structureNumber) { + structureData = [ + this.plugin.managers.structure.hierarchy.current.structures[ + params.structureNumber - 1 + ], + ]; + } + + // set non selected theme color + if (params.nonSelectedColor) { + for await (const s of structureData) { + await this.plugin.managers.structure.component.updateRepresentationsTheme( + s.components, + { + color: "uniform", + colorParams: { + value: this.normalizeColor( + params.nonSelectedColor + ), + }, + } + ); + } + } + + // apply individual selections + for await (const param of params.data) { + // get loci from param + const loci = this.getLociForParams( + [param], + params.structureNumber + ); + if (Loci.isEmpty(loci)) return; + // set default selection color to minimise change display + this.visual.setColor({ + select: param.color + ? param.color + : { r: 255, g: 112, b: 3 }, + }); + // apply selection + this.plugin.managers.interactivity.lociSelects.selectOnly({ + loci, + }); + // create theme param values and apply them to create overpaint + const themeParams = StructureComponentManager.getThemeParams( + this.plugin, + this.plugin.managers.structure.component.pivotStructure + ); + const colorValue = + ParamDefinition.getDefaultValues(themeParams); + colorValue.action.params = { + color: param.color + ? this.normalizeColor(param.color) + : Color.fromRgb(255, 112, 3), + opacity: 1, + }; + await this.plugin.managers.structure.component.applyTheme( + colorValue, + structureData + ); + // add new representations + if (param.sideChain || param.representation) { + let repr = "ball-and-stick"; + if (param.representation) repr = param.representation; + const defaultParams = + StructureComponentManager.getAddParams(this.plugin, { + allowNone: false, + hideSelection: true, + checkExisting: true, + }); + const defaultValues = + ParamDefinition.getDefaultValues(defaultParams); + defaultValues.options = { + label: "selection-by-script", + checkExisting: params.structureNumber ? false : true, + }; + const values = { + ...defaultValues, + ...{ representation: repr }, + }; + const structures = + this.plugin.managers.structure.hierarchy.getStructuresWithSelection(); + await this.plugin.managers.structure.component.add( + values, + structures + ); + + // Apply uniform theme + if (param.representationColor) { + let updatedStructureData = + this.plugin.managers.structure.hierarchy.current + .structures; + if (params.structureNumber) { + updatedStructureData = [ + this.plugin.managers.structure.hierarchy.current + .structures[params.structureNumber - 1], + ]; + } + const comps = updatedStructureData[0].components; + const lastCompsIndex = comps.length - 1; + const recentRepComp = [comps[lastCompsIndex]]; + const uniformColor = param.representationColor + ? this.normalizeColor(param.representationColor) + : Color.fromRgb(255, 112, 3); + this.plugin.managers.structure.component.updateRepresentationsTheme( + recentRepComp, + { + color: "uniform", + colorParams: { value: uniformColor }, + } + ); + } + + params.addedRepr = true; + } + // focus loci + if (param.focus) this.plugin.managers.camera.focusLoci(loci); + // remove selection + this.plugin.managers.interactivity.lociSelects.deselect({ + loci, + }); + } + + // reset selection color + this.visual.reset({ selectColor: true }); + // save selection params to optimise clear + this.selectedParams = params; + }, + clearSelection: async (structureNumber?: number) => { + const structIndex = structureNumber ? structureNumber - 1 : 0; + this.plugin.managers.interactivity.lociSelects.deselectAll(); + // reset theme to default + if (this.selectedParams && this.selectedParams.nonSelectedColor) { + this.visual.reset({ theme: true }); + } + // remove overpaints + await clearStructureOverpaint( + this.plugin, + this.plugin.managers.structure.hierarchy.current.structures[ + structIndex + ].components + ); + // remove selection representations + if (this.selectedParams && this.selectedParams.addedRepr) { + const selReprCells = []; + for (const c of this.plugin.managers.structure.hierarchy.current + .structures[structIndex].components) { + if ( + c.cell && + c.cell.params && + c.cell.params.values && + c.cell.params.values.label === "selection-by-script" + ) + selReprCells.push(c.cell); + } + if (selReprCells.length > 0) { + for await (const selReprCell of selReprCells) { + await PluginCommands.State.RemoveObject(this.plugin, { + state: selReprCell.parent!, + ref: selReprCell.transform.ref, + }); + } + } + } + this.selectedParams = undefined; + }, + update: async (options: Partial, fullLoad?: boolean) => { + console.debug( + "Updating PDBeMolstarPlugin instance with options:", + options + ); + // Validate options + if (!options) { + console.error( + "Missing `options` argument to `PDBeMolstarPlugin.visual.update" + ); + return; + } + const validationIssues = validateInitParams(options); + if (validationIssues) { + console.error("Invalid PDBeMolstarPlugin options:", options); + return; + } + + this.initParams = addDefaults(options, DefaultParams); + + if (!this.initParams.moleculeId && !this.initParams.customData) + return false; + if ( + this.initParams.customData && + this.initParams.customData.url && + !this.initParams.customData.format + ) + return false; + PluginCustomState(this.plugin).initParams = this.initParams; + + // Show/hide buttons in the viewport control panel + this.plugin.config.set( + PluginConfig.Viewport.ShowExpand, + !this.initParams.hideCanvasControls.includes("expand") + ); + this.plugin.config.set( + PluginConfig.Viewport.ShowSelectionMode, + !this.initParams.hideCanvasControls.includes("selection") + ); + this.plugin.config.set( + PluginConfig.Viewport.ShowAnimation, + !this.initParams.hideCanvasControls.includes("animation") + ); + this.plugin.config.set( + PluginConfig.Viewport.ShowControls, + !this.initParams.hideCanvasControls.includes("controlToggle") + ); + this.plugin.config.set( + PluginConfig.Viewport.ShowSettings, + !this.initParams.hideCanvasControls.includes("controlInfo") + ); + + // Set background colour + if (this.initParams.bgColor || this.initParams.lighting) { + await this.canvas.applySettings({ + color: this.initParams.bgColor, + lighting: this.initParams.lighting, + }); + } + + // Load Molecule CIF or coordQuery and Parse + const dataSource = this.getMoleculeSrcUrl(); + if (dataSource) { + await this.load( + { + url: dataSource.url, + format: dataSource.format as BuiltInTrajectoryFormat, + assemblyId: this.initParams.assemblyId, + isBinary: dataSource.isBinary, + }, + fullLoad + ); + } + }, + visibility: async (data: { + polymer?: boolean; + het?: boolean; + water?: boolean; + carbs?: boolean; + nonStandard?: boolean; + maps?: boolean; + [key: string]: any; + }) => { + if (!data) return; + + for (const visual in data) { + const tags = + StructureComponentTags[ + visual as keyof typeof StructureComponentTags + ] ?? []; + for (const tag of tags) { + const componentRef = StateSelection.findTagInSubtree( + this.plugin.state.data.tree, + StateTransform.RootRef, + tag + ); + if (componentRef) { + const compVisual = + this.plugin.state.data.select(componentRef)[0]; + if (compVisual && compVisual.obj) { + const currentlyVisible = + compVisual.state && compVisual.state.isHidden + ? false + : true; + if (data[visual] !== currentlyVisible) { + await PluginCommands.State.ToggleVisibility( + this.plugin, + { state: this.state, ref: componentRef } + ); + } + } + } + } + } + }, + toggleSpin: async (isSpinning?: boolean, resetCamera?: boolean) => { + if (!this.plugin.canvas3d) return; + const trackball = this.plugin.canvas3d.props.trackball; + + let toggleSpinParam: any = + trackball.animate.name === "spin" + ? { name: "off", params: {} } + : { name: "spin", params: { speed: 1 } }; + + if (typeof isSpinning !== "undefined") { + toggleSpinParam = { name: "off", params: {} }; + if (isSpinning) + toggleSpinParam = { name: "spin", params: { speed: 1 } }; + } + await PluginCommands.Canvas3D.SetSettings(this.plugin, { + settings: { + trackball: { ...trackball, animate: toggleSpinParam }, + }, + }); + if (resetCamera) await PluginCommands.Camera.Reset(this.plugin, {}); + }, + focus: async (params: QueryParam[], structureNumber?: number) => { + const loci = this.getLociForParams(params, structureNumber); + this.plugin.managers.camera.focusLoci(loci); + }, + setColor: async (param: { + highlight?: ColorParams; + select?: ColorParams; + }) => { + if (!this.plugin.canvas3d) return; + if (!param.highlight && !param.select) return; + const renderer = { ...this.plugin.canvas3d.props.renderer }; + const marking = { ...this.plugin.canvas3d.props.marking }; + if (param.highlight) { + renderer.highlightColor = this.normalizeColor(param.highlight); + marking.highlightEdgeColor = Color.darken( + this.normalizeColor(param.highlight), + 1 + ); + this.isHighlightColorUpdated = true; + } + if (param.select) { + renderer.selectColor = this.normalizeColor(param.select); + marking.selectEdgeColor = Color.darken( + this.normalizeColor(param.select), + 1 + ); + this.isSelectedColorUpdated = true; + } + await PluginCommands.Canvas3D.SetSettings(this.plugin, { + settings: { renderer, marking }, + }); + }, + reset: async (params: { + camera?: boolean; + theme?: boolean; + highlightColor?: boolean; + selectColor?: boolean; + }) => { + if (params.camera) + await PluginCommands.Camera.Reset(this.plugin, { + durationMs: 250, + }); + + if (params.theme) { + const defaultTheme: any = { + color: this.initParams.alphafoldView + ? "plddt-confidence" + : "default", + }; + const componentGroups = + this.plugin.managers.structure.hierarchy + .currentComponentGroups; + for (const compGrp of componentGroups) { + await this.plugin.managers.structure.component.updateRepresentationsTheme( + compGrp, + defaultTheme + ); + } + } + + if (params.highlightColor || params.selectColor) { + if (!this.plugin.canvas3d) return; + const renderer = { ...this.plugin.canvas3d.props.renderer }; + const marking = { ...this.plugin.canvas3d.props.marking }; + if (params.highlightColor) { + renderer.highlightColor = + this.defaultRendererProps.highlightColor; + marking.highlightEdgeColor = + this.defaultMarkingProps.highlightEdgeColor; + this.isHighlightColorUpdated = false; + } + if (params.selectColor) { + renderer.selectColor = + this.defaultRendererProps.selectColor; + marking.selectEdgeColor = + this.defaultMarkingProps.selectEdgeColor; + this.isSelectedColorUpdated = false; + } + await PluginCommands.Canvas3D.SetSettings(this.plugin, { + settings: { renderer, marking }, + }); + } + }, + }; + + async clear() { + await this.plugin.clear(); + this.assemblyRef = ""; + this.selectedParams = void 0; + this.isHighlightColorUpdated = false; + this.isSelectedColorUpdated = false; + } +} + +const StructureComponentTags = { + polymer: ["structure-component-static-polymer"], + het: [ + "structure-component-static-ligand", + "structure-component-static-ion", + ], + water: ["structure-component-static-water"], + carbs: ["structure-component-static-branched"], + nonStandard: ["structure-component-static-non-standard"], + coarse: ["structure-component-static-coarse"], + maps: ["volume-streaming-info"], +}; + +(window as any).PDBeMolstarPlugin = PDBeMolstarPlugin; diff --git a/frontend/venome-molstar/src/app/labels.ts b/frontend/venome-molstar/src/app/labels.ts new file mode 100644 index 00000000..99f86d4d --- /dev/null +++ b/frontend/venome-molstar/src/app/labels.ts @@ -0,0 +1,58 @@ +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import { PluginBehavior } from "molstar/lib/mol-plugin/behavior"; +import { Loci } from "molstar/lib/mol-model/loci"; +import { + StructureElement, + StructureProperties, +} from "molstar/lib/mol-model/structure"; +import { lociLabel } from "molstar/lib/mol-theme/label"; +import { LociLabel } from "molstar/lib/mol-plugin-state/manager/loci-label"; +import { PluginCustomState } from "./plugin-custom-state"; + +export const PDBeLociLabelProvider = PluginBehavior.create({ + name: "pdbe-loci-label-provider", + category: "interaction", + ctor: class implements PluginBehavior { + private f = { + label: (loci: Loci) => { + const superpositionView = PluginCustomState(this.ctx) + .initParams!.superposition; + + const label: string[] = []; + if ( + !superpositionView && + StructureElement.Loci.is(loci) && + loci.elements.length === 1 + ) { + const entityNames = new Set(); + for (const { unit: u } of loci.elements) { + const l = StructureElement.Location.create( + loci.structure, + u, + u.elements[0] + ); + const name = StructureProperties.entity + .pdbx_description(l) + .join(", "); + entityNames.add(name); + } + if (entityNames.size === 1) + entityNames.forEach((name) => label.push(name)); + } + label.push(lociLabel(loci)); + return label.filter((l) => !!l).join("
"); + }, + group: (label: LociLabel) => + label.toString().replace(/Model [0-9]+/g, "Models"), + priority: 100, + }; + register() { + this.ctx.managers.lociLabels.addProvider(this.f); + } + unregister() { + this.ctx.managers.lociLabels.removeProvider(this.f); + } + constructor(protected ctx: PluginContext) {} + }, + display: { name: "Provide PDBe Loci Label" }, +}); diff --git a/frontend/venome-molstar/src/app/loci-details.ts b/frontend/venome-molstar/src/app/loci-details.ts new file mode 100644 index 00000000..1d577850 --- /dev/null +++ b/frontend/venome-molstar/src/app/loci-details.ts @@ -0,0 +1,227 @@ +import { + Unit, + StructureElement, + StructureProperties as Props, + Bond, +} from "molstar/lib/mol-model/structure"; +import { Loci } from "molstar/lib/mol-model/loci"; +import { OrderedSet } from "molstar/lib/mol-data/int"; +import { SIFTSMapping as BestDatabaseSequenceMappingProp } from "molstar/lib/mol-model-props/sequence/sifts-mapping"; + +export type EventDetail = { + models?: string[]; + entity_id?: string; + label_asym_id?: string; + asym_id?: string; + auth_asym_id?: string; + unp_accession?: string; + unp_seq_id?: number; + seq_id?: number; + auth_seq_id?: number; + ins_code?: string; + comp_id?: string; + atom_id?: string[]; + alt_id?: string; + micro_het_comp_ids?: string[]; + seq_id_begin?: number; + seq_id_end?: number; + button?: number; + modifiers?: any; +}; + +type LabelGranularity = + | "element" + | "conformation" + | "residue" + | "chain" + | "structure"; + +export function lociDetails(loci: Loci): EventDetail | undefined { + switch (loci.kind) { + case "structure-loci": + return { + models: loci.structure.models + .map((m) => m.entry) + .filter((l) => !!l), + }; + case "element-loci": + return structureElementStatsDetail( + StructureElement.Stats.ofLoci(loci) + ); + case "bond-loci": + const bond = loci.bonds[0]; + return bond ? bondLabel(bond, "element") : ""; + default: + return void 0; + } +} + +function structureElementStatsDetail( + stats: StructureElement.Stats +): EventDetail | undefined { + const { chainCount, residueCount, elementCount } = stats; + + if (elementCount === 1 && residueCount === 0 && chainCount === 0) { + return getElementDetails(stats.firstElementLoc, "element"); + } else if (elementCount === 0 && residueCount === 1 && chainCount === 0) { + return getElementDetails(stats.firstResidueLoc, "residue"); + } else { + return void 0; + } +} + +function getElementDetails( + location: StructureElement.Location, + granularity: LabelGranularity = "element" +): EventDetail { + const basicDetails: any = {}; + + let entry = location.unit.model.entry; + if (entry.length > 30) entry = entry.substr(0, 27) + "\u2026"; // ellipsis + basicDetails["entry_id"] = entry; // entry + if (granularity !== "structure") { + basicDetails["model"] = location.unit.model.modelNum; // model + basicDetails["instance"] = location.unit.conformation.operator.name; // instance + } + + let elementDetails: any; + if (Unit.isAtomic(location.unit)) { + elementDetails = atomicElementDetails( + location as StructureElement.Location, + granularity + ); + } else if (Unit.isCoarse(location.unit)) { + elementDetails = coarseElementDetails( + location as StructureElement.Location< + Unit.Spheres | Unit.Gaussians + >, + granularity + ); + } + + return { ...basicDetails, ...elementDetails }; +} + +function atomicElementDetails( + location: StructureElement.Location, + granularity: LabelGranularity +): EventDetail { + const elementDetails: EventDetail = { + entity_id: Props.chain.label_entity_id(location), + label_asym_id: Props.chain.label_asym_id(location), + auth_asym_id: Props.chain.auth_asym_id(location), + unp_accession: undefined, + unp_seq_id: undefined, + seq_id: Props.residue.label_seq_id(location), + auth_seq_id: Props.residue.auth_seq_id(location), + ins_code: Props.residue.pdbx_PDB_ins_code(location), + comp_id: Props.atom.label_comp_id(location), + atom_id: [Props.atom.label_atom_id(location)], + alt_id: Props.atom.label_alt_id(location), + }; + + const unpLabel = BestDatabaseSequenceMappingProp.getLabel(location); + + if (unpLabel) { + const unpLabelDetails = unpLabel.split(" "); + if (unpLabelDetails[0] === "UNP") { + elementDetails.unp_accession = unpLabelDetails[1]; + elementDetails.unp_seq_id = +unpLabelDetails[2]; + } + } + + const microHetCompIds = Props.residue.microheterogeneityCompIds(location); + elementDetails["micro_het_comp_ids"] = + granularity === "residue" && microHetCompIds.length > 1 + ? microHetCompIds + : ([elementDetails["comp_id"]] as any); + + return elementDetails; +} + +function coarseElementDetails( + location: StructureElement.Location, + granularity: LabelGranularity +): EventDetail { + const elementDetails: EventDetail = { + asym_id: Props.coarse.asym_id(location), + seq_id_begin: Props.coarse.seq_id_begin(location), + seq_id_end: Props.coarse.seq_id_end(location), + }; + + if (granularity === "residue") { + if (elementDetails.seq_id_begin === elementDetails.seq_id_end) { + const entityIndex = Props.coarse.entityKey(location); + const seq = location.unit.model.sequence.byEntityKey[entityIndex]; + elementDetails["comp_id"] = seq.sequence.compId.value( + elementDetails.seq_id_begin! - 1 + ); // 1-indexed + } + } + + return elementDetails; +} + +export function bondLabel( + bond: Bond.Location, + granularity: LabelGranularity +): any { + return _bundleLabel( + { + loci: [ + StructureElement.Loci(bond.aStructure, [ + { + unit: bond.aUnit, + indices: OrderedSet.ofSingleton(bond.aIndex), + }, + ]), + StructureElement.Loci(bond.bStructure, [ + { + unit: bond.bUnit, + indices: OrderedSet.ofSingleton(bond.bIndex), + }, + ]), + ], + }, + granularity + ); +} + +export function _bundleLabel( + bundle: Loci.Bundle, + granularity: LabelGranularity +) { + let isSingleElements = true; + for (const l of bundle.loci) { + if ( + !StructureElement.Loci.is(l) || + StructureElement.Loci.size(l) !== 1 + ) { + isSingleElements = false; + break; + } + } + if (isSingleElements) { + const locations = (bundle.loci as StructureElement.Loci[]).map((l) => { + const { unit, indices } = l.elements[0]; + return StructureElement.Location.create( + l.structure, + unit, + unit.elements[OrderedSet.start(indices)] + ); + }); + const elementDetailsArr: EventDetail[] = locations.map((l) => + getElementDetails(l, granularity) + ); + const atomIds: any = [ + elementDetailsArr[0].atom_id![0], + elementDetailsArr[1].atom_id![0], + ]; + const elementDetails: EventDetail = elementDetailsArr[0]; + elementDetails["atom_id"] = atomIds; + return elementDetails; + } else { + const elementDetails = bundle.loci.map((l) => lociDetails(l)); + return elementDetails; + } +} diff --git a/frontend/venome-molstar/src/app/overlay.ts b/frontend/venome-molstar/src/app/overlay.ts new file mode 100644 index 00000000..d71f6a49 --- /dev/null +++ b/frontend/venome-molstar/src/app/overlay.ts @@ -0,0 +1,59 @@ +import { Subject, Subscription } from 'rxjs'; + + +const PdbeAnimatedLogoSvg = ''; +const OverlayBox = `
${PdbeAnimatedLogoSvg}
`; + +type OverlayEvents = 'resize' | 'hide'; + +/** Shows overlay layer with animated PDBe logo */ +export class LoadingOverlay { + private readonly subscriptions: { [key in OverlayEvents]?: Subscription } = {}; + + constructor( + private readonly target: HTMLElement, + private readonly subjects: { readonly [key in OverlayEvents]?: Subject } = {}, + private readonly overlayHtml: string = OverlayBox, + ) { } + + private getOverlayParent() { + return this.target.parentElement ?? document.body; + } + + show() { + this.hide(); + + const overlayParent = this.getOverlayParent(); + const divOverlay = document.createElement('div'); + divOverlay.classList.add('pdbemolstar-overlay'); + // divOverlay.setAttribute('title', 'Loading...'); + divOverlay.innerHTML = this.overlayHtml; + overlayParent.appendChild(divOverlay); + + const resize = () => { + const viewerRect = this.target.getElementsByClassName('msp-layout-main').item(0)?.getBoundingClientRect(); + if (viewerRect) { + const { left, top, width, height } = viewerRect; + const origin = this.target.offsetParent?.getBoundingClientRect() ?? { left: 0, top: 0 }; + divOverlay.setAttribute('style', `position: absolute; left: ${left - origin?.left}px; top: ${top - origin.top}px; width: ${width}px; height: ${height}px;`); + } else { + divOverlay.setAttribute('style', `position: fixed; top: 0px; bottom: 0px; left: 0px; right: 0px;`); + } + }; + + resize(); + this.subscriptions.resize = this.subjects.resize?.subscribe(() => resize()); + this.subscriptions.hide = this.subjects.hide?.subscribe(() => this.hide()); + } + + hide() { + const existingOverlays = this.getOverlayParent().getElementsByClassName('pdbemolstar-overlay'); + for (let i = 0; i < existingOverlays.length; i++) { + existingOverlays.item(i)?.remove(); + } + this.subscriptions.resize?.unsubscribe(); + this.subscriptions.resize = undefined; + this.subscriptions.hide?.unsubscribe(); + this.subscriptions.hide = undefined; + } +} diff --git a/frontend/venome-molstar/src/app/plugin-custom-state.ts b/frontend/venome-molstar/src/app/plugin-custom-state.ts new file mode 100644 index 00000000..f2a43721 --- /dev/null +++ b/frontend/venome-molstar/src/app/plugin-custom-state.ts @@ -0,0 +1,74 @@ +import { SymmetryOperator } from "molstar/lib/mol-math/geometry"; +import { Mat4 } from "molstar/lib/mol-math/linear-algebra"; +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import { StateSelection, StateTransform } from "molstar/lib/mol-state"; +import { Subject } from "rxjs"; +import { InitParams } from "./spec"; + +export interface PluginCustomState { + initParams?: InitParams; + events?: { + segmentUpdate: Subject; + superpositionInit: Subject; + isBusy: Subject; + }; + superpositionState?: { + models: { [molId: string]: string }; + entries: { [pdbId: string]: StateSelection.Selector }; + refMaps: { [ref: string]: string }; + segmentData: Segment[] | undefined; + matrixData: { [key: string]: { matrix: number[][] } }; + activeSegment: number; + loadedStructs: string[][]; + visibleRefs: StateTransform.Ref[][]; + invalidStruct: string[]; + noMatrixStruct: string[]; + hets: { [key: string]: unknown[] }; + colorPalette: [ + "dark-2", + "red-yellow-green", + "paired", + "set-1", + "accent", + "set-2", + "rainbow" + ]; + colorState: { palleteIndex: number; colorIndex: number }[]; + alphafold: { + apiData: { + cif: string; + pae: string; + length: number; + }; + length: number; + ref: string; + traceOnly: boolean; + visibility: boolean[]; + transforms: Mat4[]; + rmsds: string[][]; + coordinateSystems: (SymmetryOperator | undefined)[]; + }; + }; + superpositionError?: string; +} + +export interface ClusterMember { + pdb_id: string; + auth_asym_id: string; + struct_asym_id: string; + entity_id: number; + is_representative: boolean; +} +export interface Segment { + segment_start: number; + segment_end: number; + clusters: ClusterMember[][]; + isHetView?: boolean; + isBinary?: boolean; +} + +/** Access `plugin.customState` only through this function to get proper typing. + * Supports getting and setting properties. */ +export function PluginCustomState(plugin: PluginContext): PluginCustomState { + return ((plugin.customState as any) ??= {}); +} diff --git a/frontend/venome-molstar/src/app/sifts-mapping.ts b/frontend/venome-molstar/src/app/sifts-mapping.ts new file mode 100644 index 00000000..177fbeac --- /dev/null +++ b/frontend/venome-molstar/src/app/sifts-mapping.ts @@ -0,0 +1,116 @@ +import { Column } from "molstar/lib/mol-data/db"; +import { MmcifFormat } from "molstar/lib/mol-model-formats/structure/mmcif"; +import { CustomPropertyDescriptor } from "molstar/lib/mol-model/custom-property"; +import { Model } from "molstar/lib/mol-model/structure"; +import { StructureElement } from "molstar/lib/mol-model/structure/structure"; +import { CustomModelProperty } from "molstar/lib/mol-model-props/common/custom-model-property"; + +export { SIFTSMapping as SIFTSMapping }; + +export interface SIFTSMappingMapping { + readonly dbName: string[]; + readonly accession: string[]; + readonly num: string[]; + readonly residue: string[]; +} + +namespace SIFTSMapping { + export const Provider: CustomModelProperty.Provider< + {}, + SIFTSMappingMapping + > = CustomModelProperty.createProvider({ + label: "SIFTS Mapping", + descriptor: CustomPropertyDescriptor({ + name: "sifts_sequence_mapping", + }), + type: "static", + defaultParams: {}, + getParams: () => ({}), + isApplicable: (data: Model) => isAvailable(data), + obtain: async (ctx, data) => { + return { value: fromCif(data) }; + }, + }); + + export function isAvailable(model: Model) { + if (!MmcifFormat.is(model.sourceData)) return false; + + const { + pdbx_sifts_xref_db_name: db_name, + pdbx_sifts_xref_db_acc: db_acc, + pdbx_sifts_xref_db_num: db_num, + pdbx_sifts_xref_db_res: db_res, + } = model.sourceData.data.db.atom_site; + + return ( + db_name.isDefined && + db_acc.isDefined && + db_num.isDefined && + db_res.isDefined + ); + } + + export function getKey(loc: StructureElement.Location) { + const model = loc.unit.model; + const data = Provider.get(model).value; + if (!data) return ""; + const rI = model.atomicHierarchy.residueAtomSegments.index[loc.element]; + return data.accession[rI]; + } + + export function getLabel(loc: StructureElement.Location) { + const model = loc.unit.model; + const data = Provider.get(model).value; + if (!data) return; + const rI = model.atomicHierarchy.residueAtomSegments.index[loc.element]; + const dbName = data.dbName[rI]; + if (!dbName) return; + return `${dbName} ${data.accession[rI]} ${data.num[rI]} ${data.residue[rI]}`; + } + + function fromCif(model: Model): SIFTSMappingMapping | undefined { + if (!MmcifFormat.is(model.sourceData)) return; + + const { + pdbx_sifts_xref_db_name: db_name, + pdbx_sifts_xref_db_acc: db_acc, + pdbx_sifts_xref_db_num: db_num, + pdbx_sifts_xref_db_res: db_res, + } = model.sourceData.data.db.atom_site; + + if ( + !db_name.isDefined || + !db_acc.isDefined || + !db_num.isDefined || + !db_res.isDefined + ) + return; + + const { atomSourceIndex } = model.atomicHierarchy; + const { count, offsets: residueOffsets } = + model.atomicHierarchy.residueAtomSegments; + const dbName = new Array(count); + const accession = new Array(count); + const num = new Array(count); + const residue = new Array(count); + + for (let i = 0; i < count; i++) { + const row = atomSourceIndex.value(residueOffsets[i]); + + if (db_name.valueKind(row) !== Column.ValueKind.Present) { + dbName[i] = ""; + accession[i] = ""; + num[i] = ""; + residue[i] = ""; + continue; + } + + dbName[i] = db_name.value(row); + accession[i] = db_acc.value(row); + num[i] = db_num.value(row); + residue[i] = db_res.value(row); + } + + return { dbName, accession, num, residue }; + } +} diff --git a/frontend/venome-molstar/src/app/sifts-mappings-behaviour.ts b/frontend/venome-molstar/src/app/sifts-mappings-behaviour.ts new file mode 100644 index 00000000..08c7a93f --- /dev/null +++ b/frontend/venome-molstar/src/app/sifts-mappings-behaviour.ts @@ -0,0 +1,84 @@ +import { OrderedSet } from "molstar/lib/mol-data/int"; +import { SIFTSMapping as BestDatabaseSequenceMappingProp } from "./sifts-mapping"; +import { SIFTSMappingColorThemeProvider } from "molstar/lib/mol-model-props/sequence/themes/sifts-mapping"; +import { Loci } from "molstar/lib/mol-model/loci"; +import { StructureElement } from "molstar/lib/mol-model/structure"; +import { ParamDefinition as PD } from "molstar/lib/mol-util/param-definition"; +import { PluginBehavior } from "molstar/lib/mol-plugin/behavior"; + +export const PDBeSIFTSMapping = PluginBehavior.create<{ + autoAttach: boolean; + showTooltip: boolean; +}>({ + name: "pdbe-sifts-mapping-prop", + category: "custom-props", + display: { name: "PDBe SIFTS Mapping" }, + ctor: class extends PluginBehavior.Handler<{ + autoAttach: boolean; + showTooltip: boolean; + }> { + private provider = BestDatabaseSequenceMappingProp.Provider; + + private labelProvider = { + label: (loci: Loci): string | undefined => { + if (!this.params.showTooltip) return; + return PDBeBestDatabaseSequenceMappingLabel(loci); + }, + }; + + update(p: { autoAttach: boolean; showTooltip: boolean }) { + const updated = + this.params.autoAttach !== p.autoAttach || + this.params.showTooltip !== p.showTooltip; + this.params.autoAttach = p.autoAttach; + this.params.showTooltip = p.showTooltip; + this.ctx.customStructureProperties.setDefaultAutoAttach( + this.provider.descriptor.name, + this.params.autoAttach + ); + return updated; + } + + register(): void { + this.ctx.customModelProperties.register( + this.provider, + this.params.autoAttach + ); + this.ctx.representation.structure.themes.colorThemeRegistry.add( + SIFTSMappingColorThemeProvider + ); + this.ctx.managers.lociLabels.addProvider(this.labelProvider); + } + + unregister() { + this.ctx.customModelProperties.unregister( + this.provider.descriptor.name + ); + this.ctx.representation.structure.themes.colorThemeRegistry.remove( + SIFTSMappingColorThemeProvider + ); + this.ctx.managers.lociLabels.removeProvider(this.labelProvider); + } + }, + params: () => ({ + autoAttach: PD.Boolean(true), + showTooltip: PD.Boolean(true), + }), +}); + +// + +function PDBeBestDatabaseSequenceMappingLabel(loci: Loci): string | undefined { + if (loci.kind === "element-loci") { + if (loci.elements.length === 0) return; + + const e = loci.elements[0]; + const u = e.unit; + const se = StructureElement.Location.create( + loci.structure, + u, + u.elements[OrderedSet.getAt(e.indices, 0)] + ); + return BestDatabaseSequenceMappingProp.getLabel(se); + } +} diff --git a/frontend/venome-molstar/src/app/spec-from-html.ts b/frontend/venome-molstar/src/app/spec-from-html.ts new file mode 100644 index 00000000..bd1da2d5 --- /dev/null +++ b/frontend/venome-molstar/src/app/spec-from-html.ts @@ -0,0 +1,125 @@ +import { ColorParams, Encoding, InitParams, Lighting, Preset, VisualStyle, validateInitParams } from './spec'; + + +/** Extract InitParams from attributes of an HTML element */ +export function initParamsFromHtmlAttributes(element: HTMLElement): Partial { + const params = loadHtmlAttributes(element, InitParamsLoadingActions, {}); + const validationIssues = validateInitParams(params); + if (validationIssues) console.error('Invalid PDBeMolstarPlugin options:', params); + return params; +} + + +/** Actions for loading individual HTML attributes into InitParams object */ +const InitParamsLoadingActions: AttributeLoadingActions> = { + 'molecule-id': setString('moleculeId'), + 'custom-data-url': (value, params) => { (params.customData ??= defaultCustomData()).url = value; }, + 'custom-data-format': (value, params) => { (params.customData ??= defaultCustomData()).format = value; }, + 'custom-data-binary': (value, params) => { (params.customData ??= defaultCustomData()).binary = parseBool(value); }, + 'assembly-id': setString('assemblyId'), + 'default-preset': setLiteral(Preset, 'defaultPreset'), + 'ligand-label-comp-id': (value, params) => { (params.ligandView ??= {}).label_comp_id = value; }, + 'ligand-auth-asym-id': (value, params) => { (params.ligandView ??= {}).auth_asym_id = value; }, + 'ligand-struct-asym-id': (value, params) => { (params.ligandView ??= {}).struct_asym_id = value; }, + 'ligand-auth-seq-id': (value, params) => { (params.ligandView ??= {}).auth_seq_id = Number(value); }, + 'ligand-show-all': (value, params) => { (params.ligandView ??= {}).show_all = parseBool(value); }, + 'alphafold-view': setBool('alphafoldView'), + + 'visual-style': setLiteral(VisualStyle, 'visualStyle'), + 'hide-polymer': pushItem('hideStructure', 'polymer'), + 'hide-water': pushItem('hideStructure', 'water'), + 'hide-het': pushItem('hideStructure', 'het'), + 'hide-carbs': pushItem('hideStructure', 'carbs'), + 'hide-non-standard': pushItem('hideStructure', 'nonStandard'), + 'hide-coarse': pushItem('hideStructure', 'coarse'), + 'load-maps': setBool('loadMaps'), + 'bg-color-r': setColorComponent('bgColor', 'r'), + 'bg-color-g': setColorComponent('bgColor', 'g'), + 'bg-color-b': setColorComponent('bgColor', 'b'), + 'highlight-color-r': setColorComponent('highlightColor', 'r'), + 'highlight-color-g': setColorComponent('highlightColor', 'g'), + 'highlight-color-b': setColorComponent('highlightColor', 'b'), + 'select-color-r': setColorComponent('selectColor', 'r'), + 'select-color-g': setColorComponent('selectColor', 'g'), + 'select-color-b': setColorComponent('selectColor', 'b'), + 'lighting': setLiteral(Lighting, 'lighting'), + + 'validation-annotation': setBool('validationAnnotation'), + 'domain-annotation': setBool('domainAnnotation'), + 'symmetry-annotation': setBool('symmetryAnnotation'), + 'pdbe-url': setString('pdbeUrl'), + 'encoding': setLiteral(Encoding, 'encoding'), + 'low-precision': setBool('lowPrecisionCoords'), + 'select-interaction': setBool('selectInteraction'), + 'subscribe-events': setBool('subscribeEvents'), + + 'hide-controls': setBool('hideControls'), + 'hide-expand-icon': pushItem('hideCanvasControls', 'expand'), + 'hide-selection-icon': pushItem('hideCanvasControls', 'selection'), + 'hide-animation-icon': pushItem('hideCanvasControls', 'animation'), + 'hide-control-toggle-icon': pushItem('hideCanvasControls', 'controlToggle'), + 'hide-control-info-icon': pushItem('hideCanvasControls', 'controlInfo'), + 'sequence-panel': setBool('sequencePanel'), + 'pdbe-link': setBool('pdbeLink'), + 'loading-overlay': setBool('loadingOverlay'), + 'expanded': setBool('expanded'), + 'landscape': setBool('landscape'), + 'reactive': setBool('reactive'), +}; + + +/** Actions for loading individual HTML attributes into a context */ +type AttributeLoadingActions = { [attribute: string]: (value: string, context: TContext) => any } + +/** Load attributes of an HTML element into a context */ +function loadHtmlAttributes(element: HTMLElement, actions: AttributeLoadingActions, context: TContext): TContext { + for (const attribute in actions) { + const value = element.getAttribute(attribute); + if (typeof value === 'string') { + actions[attribute](value, context); + } + } + return context; +} + + +/** Select keys of an object type `T` which except type `V` as value */ +type KeyWith = Exclude<{ [key in keyof T]: V extends T[key] ? key : never }[keyof T], undefined> + +function setString(key: KeyWith) { + return (value: string, obj: T) => { obj[key] = value as any; }; +} +function setLiteral(allowedValues: readonly E[], key: KeyWith) { + return (value: string, ctx: T) => { + if (!allowedValues.includes(value as E)) console.error(`Value "${value}" is not valid for type ${allowedValues.map(s => `"${s}"`).join(' | ')}`); + ctx[key] = value as any; + }; +} +function setBool(key: KeyWith) { + return (value: string, obj: T) => { obj[key] = parseBool(value) as any; }; +} +function setColorComponent(key: KeyWith, component: 'r' | 'g' | 'b') { + return (value: string, obj: T) => { + const color = obj[key] ??= { r: 0, g: 0, b: 0 } as any; + color[component] = Number(value); + }; +} +function pushItem(key: KeyWith, item: any) { + return (value: string, obj: T) => { + if (parseBool(value)) { + const array = obj[key] ??= [] as any; + array.push(item); + } + }; +} + +/** Parse a string into a boolean. + * Consider strings like 'false', 'OFF', '0' as false; others as true. + * Empty string is parsed as true, because HTML attribute without value must be treated as truthy. */ +function parseBool(value: string): boolean { + const FalseyStrings = ['false', 'off', '0']; + return !FalseyStrings.includes(value.toLowerCase()); +} +function defaultCustomData(): Exclude { + return { url: '', format: '', binary: false }; +} diff --git a/frontend/venome-molstar/src/app/spec.ts b/frontend/venome-molstar/src/app/spec.ts new file mode 100644 index 00000000..38df4c52 --- /dev/null +++ b/frontend/venome-molstar/src/app/spec.ts @@ -0,0 +1,267 @@ +import { Loci } from "molstar/lib/mol-model/loci"; +import { StateActions } from "molstar/lib/mol-plugin-state/actions"; +import { VolumeStreamingCustomControls } from "molstar/lib/mol-plugin-ui/custom/volume"; +import { PluginUISpec } from "molstar/lib/mol-plugin-ui/spec"; +import { PluginBehaviors } from "molstar/lib/mol-plugin/behavior"; +import { DefaultFocusLociBindings } from "molstar/lib/mol-plugin/behavior/dynamic/camera"; +import { DefaultSelectLociBindings } from "molstar/lib/mol-plugin/behavior/dynamic/representation"; +import { CreateVolumeStreamingBehavior } from "molstar/lib/mol-plugin/behavior/dynamic/volume-streaming/transformers"; +import { PluginConfig } from "molstar/lib/mol-plugin/config"; +import { PluginSpec } from "molstar/lib/mol-plugin/spec"; +import { LigandQueryParam, MapParams, QueryParam } from "./helpers"; +import { PDBeLociLabelProvider } from "./labels"; +import { PDBeSIFTSMapping } from "./sifts-mappings-behaviour"; + +export const DefaultPluginSpec = (): PluginSpec => ({ + actions: [ + PluginSpec.Action(StateActions.Structure.EnableStructureCustomProps), + ], + behaviors: [ + PluginSpec.Behavior(PluginBehaviors.Representation.HighlightLoci), + PluginSpec.Behavior(PluginBehaviors.Representation.SelectLoci), + PluginSpec.Behavior(PDBeLociLabelProvider), + PluginSpec.Behavior(PluginBehaviors.Representation.FocusLoci), + PluginSpec.Behavior(PluginBehaviors.Camera.FocusLoci), + PluginSpec.Behavior(PluginBehaviors.Camera.CameraAxisHelper), + + PluginSpec.Behavior(PluginBehaviors.CustomProps.StructureInfo), + PluginSpec.Behavior(PluginBehaviors.CustomProps.AccessibleSurfaceArea), + PluginSpec.Behavior(PDBeSIFTSMapping, { + autoAttach: true, + showTooltip: true, + }), + PluginSpec.Behavior(PluginBehaviors.CustomProps.Interactions), + PluginSpec.Behavior(PluginBehaviors.CustomProps.SecondaryStructure), + PluginSpec.Behavior(PluginBehaviors.CustomProps.ValenceModel), + PluginSpec.Behavior(PluginBehaviors.CustomProps.CrossLinkRestraint), + ], + // animations: [], + config: [ + [ + PluginConfig.VolumeStreaming.DefaultServer, + "https://www.ebi.ac.uk/pdbe/volume-server", + ], + [ + PluginConfig.VolumeStreaming.EmdbHeaderServer, + "https://files.wwpdb.org/pub/emdb/structures", + ], + ], +}); + +export const DefaultPluginUISpec = (): PluginUISpec => ({ + ...DefaultPluginSpec(), + customParamEditors: [ + [CreateVolumeStreamingBehavior, VolumeStreamingCustomControls], + ], +}); + +/** RGB color (r, g, b values 0-255) */ +export interface ColorParams { + r: number; + g: number; + b: number; +} + +export const Preset = [ + "default", + "unitcell", + "all-models", + "supercell", +] as const; +export type Preset = (typeof Preset)[number]; + +export const Lighting = [ + "flat", + "matte", + "glossy", + "metallic", + "plastic", +] as const; +export type Lighting = (typeof Lighting)[number]; + +export const VisualStyle = [ + "cartoon", + "ball-and-stick", + "carbohydrate", + "ellipsoid", + "gaussian-surface", + "molecular-surface", + "point", + "putty", + "spacefill", +] as const; +export type VisualStyle = (typeof VisualStyle)[number]; + +export const Encoding = ["cif", "bcif"] as const; +export type Encoding = (typeof Encoding)[number]; + +/** Options for initializing `PDBeMolstarPlugin` */ +export interface InitParams { + // DATA + /** PDB ID (example: '1cbs'), or UniProt ID if `superposition` is `true`. Leave `undefined` only when setting `customData` */ + moleculeId?: string; + /** Load data from a specific data source. + * Example: `{ url: 'https://www.ebi.ac.uk/pdbe/model-server/v1/1cbs/atoms?label_entity_id=1&auth_asym_id=A&encoding=bcif', format: 'cif', binary: true }` */ + customData?: { url: string; format: string; binary: boolean }; + /** Leave `undefined` to load deposited model structure. Use assembly identifier to load assembly structure. or 'preferred' to load default assembly (i.e. the first assembly). */ + assemblyId?: string; + /** Specify type of structure to be loaded */ + defaultPreset: Preset; + /** Use to display the PDBe ligand page 3D view like here (https://www.ebi.ac.uk/pdbe/entry/pdb/1cbs/bound/REA). + * Example: `{ label_comp_id: 'REA' }`. At least one is required of `label_comp_id` and `auth_seq_id` */ + ligandView?: LigandQueryParam; + /** This applies AlphaFold confidence score colouring theme for AlphaFold model */ + alphafoldView: boolean; + /** Display the superposed structures view like the one on the PDBe-KB pages. */ + superposition: boolean; + /** Customize the superposed structures view. Example: `{ matrixAccession: 'P08684', segment: 1, ligandView: true, ligandColor: { r: 255, g: 255, b: 50} }`. */ + superpositionParams?: { + matrixAccession?: string; + segment?: number; + cluster?: number[]; + superposeCompleteCluster?: boolean; + ligandView?: boolean; + superposeAll?: boolean; + ligandColor?: ColorParams; + }; + /** Specify parts of the structure to highlight with different colors */ + selection?: { + data: QueryParam[]; + nonSelectedColor?: ColorParams; + clearPrevious?: boolean; + }; + + // APPEARANCE + /** Leave `undefined` to keep both cartoon and ball-and-sticks based on component type */ + visualStyle?: VisualStyle; + /** Molstar renders multiple visuals (polymer, ligand, water...) visuals by default. This option is to exclude any of these default visuals */ + hideStructure: ( + | "polymer" + | "het" + | "water" + | "carbs" + | "nonStandard" + | "coarse" + )[]; + /** Load electron density (or EM) maps from Volume Server if value is set to true */ + loadMaps: boolean; + /** Customize map style (opacity and solid/wireframe) */ + mapSettings?: MapParams; + /** Canvas background color */ + bgColor: ColorParams; + /** Color appearing on mouse-over */ + highlightColor?: ColorParams; + /** Color for marking the selected part of structure (when Selection Mode is active) */ + selectColor?: ColorParams; + /** Default lighting (I don't think it really works) */ + lighting?: Lighting; + + // BEHAVIOR + /** Load Validation Report Annotations. Adds 'Annotations' control in the menu */ + validationAnnotation: boolean; + /** Load Domain Annotations. Adds 'Annotations' control in the menu */ + domainAnnotation: boolean; + /** Load Assembly Symmetry Annotations. Adds 'Annotations' control in the menu */ + symmetryAnnotation: boolean; + /** This option is to set the default base URL for the data source. Mostly used internally to test the plugin on different environments */ + pdbeUrl: string; + /** Preferred encoding of input structural data */ + encoding: Encoding; + /** Load low precision coordinates from Model Server */ + lowPrecisionCoords: boolean; + /** Controls the action performed when clicking a residue. `true` (default) will zoom the residue + * and show ball-and-stick visual for its surroundings, `false` will only zoom the residue. + * If `ligandView` or `superposition` option is set, `selectInteraction` behaves as if `false`. */ + selectInteraction: boolean; + /** Override mouse selection behavior */ + selectBindings?: typeof DefaultSelectLociBindings; + /** Override mouse click focus behaviour */ + focusBindings?: typeof DefaultFocusLociBindings; + /** Structure granularity level for interactions like highlight, focus, select. + * (Granularity levels ending with `Instances` treat multiple copies of the same element/residue/chain in an assembly as one object). */ + granularity?: Loci.Granularity; + /** Subscribe to other PDB Web-components custom events */ + subscribeEvents: boolean; + + // INTERFACE + /** Hide all control panels by default (can be shown by the Toggle Controls Panel button (wrench icon)) */ + hideControls: boolean; + /** Hide individual icon buttons in the top-right corner of the canvas */ + hideCanvasControls: ( + | "expand" + | "selection" + | "animation" + | "controlToggle" + | "controlInfo" + )[]; + /** Display Sequence panel */ + sequencePanel: boolean; + /** Display PDBe entry link in top right corner of the canvas */ + pdbeLink: boolean; + /** Show overlay with PDBe logo while the initial structure is being loaded */ + loadingOverlay: boolean; + /** Display full-screen by default on load */ + expanded: boolean; + /** Set landscape layout (control panels on the sides instead of above and under the canvas) */ + landscape: boolean; + /** Set reactive layout (switching between landscape and portrait based on the browser window size). Overrides `landscape`. */ + reactive: boolean; +} + +/** Default values for `InitParams` */ +export const DefaultParams: InitParams = { + moleculeId: undefined, + customData: undefined, + assemblyId: undefined, + defaultPreset: "default", + ligandView: undefined, + alphafoldView: false, + superposition: false, + superpositionParams: undefined, + selection: undefined, + + visualStyle: undefined, + hideStructure: [], + loadMaps: false, + mapSettings: undefined, + bgColor: { r: 0, g: 0, b: 0 }, + highlightColor: undefined, + selectColor: undefined, + lighting: undefined, + + validationAnnotation: false, + domainAnnotation: false, + symmetryAnnotation: false, + pdbeUrl: "https://www.ebi.ac.uk/pdbe/", + encoding: "bcif", + lowPrecisionCoords: false, + selectInteraction: true, + selectBindings: undefined, + focusBindings: undefined, + granularity: undefined, + subscribeEvents: false, + + hideControls: false, + hideCanvasControls: [], + sequencePanel: false, + pdbeLink: true, + loadingOverlay: false, + expanded: false, + landscape: false, + reactive: false, +}; + +/** Return `undefined` if `params` are valid, an error message otherwise. */ +export function validateInitParams( + params: Partial +): string | undefined { + if (!params.moleculeId && !params.customData?.url) + return "Option `moleculeId` or `customData` must be defined"; + if (params.customData) { + if (!params.customData.url) + return "Option `customData.url` must be a non-empty string"; + if (!params.customData.format) + return "Option `customData.format` must be a non-empty string"; + } + return undefined; +} diff --git a/frontend/venome-molstar/src/app/subscribe-events.ts b/frontend/venome-molstar/src/app/subscribe-events.ts new file mode 100644 index 00000000..db23096d --- /dev/null +++ b/frontend/venome-molstar/src/app/subscribe-events.ts @@ -0,0 +1,209 @@ +export function subscribeToComponentEvents(wrapperCtx: any) { + document.addEventListener('PDB.interactions.click', function (e: any) { + if (typeof e.detail !== 'undefined') { + const data = e.detail.interacting_nodes ? { data: e.detail.interacting_nodes } : { data: [e.detail.selected_node] }; + data.data[0]['focus'] = true; + wrapperCtx.visual.select(data); + } + }); + + document.addEventListener('PDB.interactions.mouseover', function (e: any) { + if (typeof e.detail !== 'undefined') { + const data = e.detail.interacting_nodes ? { data: e.detail.interacting_nodes } : { data: [e.detail.selected_node] }; + wrapperCtx.visual.highlight(data); + } + }); + + document.addEventListener('PDB.interactions.mouseout', function (e: any) { + wrapperCtx.visual.clearHighlight(); + }); + + document.addEventListener('PDB.topologyViewer.click', function (e: any) { + if (typeof e.eventData !== 'undefined') { + // Create query object from event data + const highlightQuery = { + entity_id: e.eventData.entityId, + struct_asym_id: e.eventData.structAsymId, + start_residue_number: e.eventData.residueNumber, + end_residue_number: e.eventData.residueNumber, + sideChain: true, + focus: true + }; + // Call highlightAnnotation + wrapperCtx.visual.select({ data: [highlightQuery] }); + } + }); + + document.addEventListener('PDB.topologyViewer.mouseover', function (e: any) { + if (typeof e.eventData !== 'undefined') { + // Abort if entryid do not match or viewer type is unipdb + // if(e.eventData.entryId != scope.pdbId) return; + + // Create query object from event data + const highlightQuery = { + entity_id: e.eventData.entityId, + struct_asym_id: e.eventData.structAsymId, + start_residue_number: e.eventData.residueNumber, + end_residue_number: e.eventData.residueNumber + }; + // Call highlightAnnotation + wrapperCtx.visual.highlight({ data: [highlightQuery] }); + } + }); + + document.addEventListener('PDB.topologyViewer.mouseout', function (e: any) { + wrapperCtx.visual.clearHighlight(); + }); + + document.addEventListener('protvista-mouseover', function (e: any) { + if (typeof e.detail !== 'undefined') { + + let highlightQuery: any = undefined; + + // Create query object from event data + if (e.detail.start && e.detail.end) { + highlightQuery = { + start_residue_number: parseInt(e.detail.start), + end_residue_number: parseInt(e.detail.end) + }; + } + + if (e.detail.feature && e.detail.feature.entityId) highlightQuery['entity_id'] = e.detail.feature.entityId + ''; + if (e.detail.feature && e.detail.feature.bestChainId) highlightQuery['struct_asym_id'] = e.detail.feature.bestChainId; + if (e.detail.feature && e.detail.feature.chainId) highlightQuery['struct_asym_id'] = e.detail.feature.chainId; + + if (highlightQuery) wrapperCtx.visual.highlight({ data: [highlightQuery] }); + } + }); + + document.addEventListener('protvista-mouseout', function (e: any) { + wrapperCtx.visual.clearHighlight(); + }); + + document.addEventListener('protvista-click', function (e: any) { + if (typeof e.detail !== 'undefined') { + + let showInteraction = false; + let highlightQuery: any = undefined; + + // Create query object from event data + if (e.detail.start && e.detail.end) { + highlightQuery = { + start_residue_number: parseInt(e.detail.start), + end_residue_number: parseInt(e.detail.end) + }; + } + + if (e.detail.feature && e.detail.feature.entityId) highlightQuery['entity_id'] = e.detail.feature.entityId + ''; + if (e.detail.feature && e.detail.feature.bestChainId) highlightQuery['struct_asym_id'] = e.detail.feature.bestChainId; + if (e.detail.feature && e.detail.feature.chainId) highlightQuery['struct_asym_id'] = e.detail.feature.chainId; + + if (e.detail.feature && e.detail.feature.accession && e.detail.feature.accession.split(' ')[0] === 'Chain' || e.detail.feature.tooltipContent === 'Ligand binding site') { + showInteraction = true; + } + + if (e.detail.start === e.detail.end) showInteraction = true; + + if (highlightQuery) { + + if (showInteraction) { + highlightQuery['sideChain'] = true; + } else { + let selColor = undefined; + if (e.detail.trackIndex > -1 && e.detail.feature.locations && e.detail.feature.locations[0].fragments[e.detail.trackIndex].color) selColor = e.detail.feature.locations[0].fragments[e.detail.trackIndex].color; + if (typeof selColor == 'undefined' && e.detail.feature.color) selColor = e.detail.feature.color; + if (typeof selColor == 'undefined' && e.detail.color) selColor = e.detail.color; + + if (typeof selColor == 'undefined') { + selColor = { r: 65, g: 96, b: 91 }; + } else { + const isRgb = /rgb/g; + if (isRgb.test(selColor)) { + const rgbArr = selColor.substring(4, selColor.length - 1).split(','); + selColor = { r: rgbArr[0], g: rgbArr[1], b: rgbArr[2] }; + } + } + + highlightQuery['color'] = selColor; + } + highlightQuery['focus'] = true; + wrapperCtx.visual.select({ data: [highlightQuery] }); + } + } + }); + + const elementTypeArrForRange = ['uniprot', 'pfam', 'cath', 'scop', 'strand', 'helice']; + const elementTypeArrForSingle = ['chain', 'quality', 'quality_outlier', 'binding site', 'alternate conformer']; + document.addEventListener('PDB.seqViewer.click', function (e: any) { + if (typeof e.eventData !== 'undefined') { + // Abort if entryid and entityid do not match or viewer type is unipdb + // if(e.eventData.entryId != scope.pdbId) return; + + if (typeof e.eventData.elementData !== 'undefined' && elementTypeArrForSingle.indexOf(e.eventData.elementData.elementType) > -1) { + // Create query object from event data + const highlightQuery = { + entity_id: e.eventData.entityId, + struct_asym_id: e.eventData.elementData.pathData.struct_asym_id, + start_residue_number: e.eventData.residueNumber, + end_residue_number: e.eventData.residueNumber, + sideChain: true, + focus: true + }; + + // Call highlightAnnotation + wrapperCtx.visual.select({ data: [highlightQuery] }); + + } else if (typeof e.eventData.elementData !== 'undefined' && elementTypeArrForRange.indexOf(e.eventData.elementData.elementType) > -1) { + + const seqColorArray = e.eventData.elementData.color; + + // Create query object from event data + const highlightQuery = { + entity_id: e.eventData.entityId, + struct_asym_id: e.eventData.elementData.pathData.struct_asym_id, + start_residue_number: e.eventData.elementData.pathData.start.residue_number, + end_residue_number: e.eventData.elementData.pathData.end.residue_number, + color: { r: seqColorArray[0], g: seqColorArray[1], b: seqColorArray[2] }, + focus: true + }; + wrapperCtx.visual.select({ data: [highlightQuery] }); + } + + } + }); + + document.addEventListener('PDB.seqViewer.mouseover', function (e: any) { + if (typeof e.eventData !== 'undefined') { + // Abort if entryid and entityid do not match or viewer type is unipdb + // if(e.eventData.entryId != scope.pdbId) return; + + if (typeof e.eventData.elementData !== 'undefined' && elementTypeArrForSingle.indexOf(e.eventData.elementData.elementType) > -1) { + // Create query object from event data + const highlightQuery = { + entity_id: e.eventData.entityId, + struct_asym_id: e.eventData.elementData.pathData.struct_asym_id, + start_residue_number: e.eventData.residueNumber, + end_residue_number: e.eventData.residueNumber, + focus: true + }; + wrapperCtx.visual.select({ data: [highlightQuery] }); + + } else if (typeof e.eventData.elementData !== 'undefined' && elementTypeArrForRange.indexOf(e.eventData.elementData.elementType) > -1) { + + // Create query object from event data + const highlightQuery = { + entity_id: e.eventData.entityId, + struct_asym_id: e.eventData.elementData.pathData.struct_asym_id, + start_residue_number: e.eventData.elementData.pathData.start.residue_number, + end_residue_number: e.eventData.elementData.pathData.end.residue_number + }; + // Call highlightAnnotation + wrapperCtx.visual.highlight({ data: [highlightQuery] }); + } + } + }); + + document.addEventListener('PDB.seqViewer.mouseout', function (e) { + wrapperCtx.visual.clearHighlight(); + }); +} \ No newline at end of file diff --git a/frontend/venome-molstar/src/app/superposition-export.ts b/frontend/venome-molstar/src/app/superposition-export.ts new file mode 100644 index 00000000..31311f57 --- /dev/null +++ b/frontend/venome-molstar/src/app/superposition-export.ts @@ -0,0 +1,157 @@ +import { utf8ByteCount, utf8Write } from "molstar/lib/mol-io/common/utf8"; +import { to_mmCIF, Unit } from "molstar/lib/mol-model/structure"; +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import { Task } from "molstar/lib/mol-task"; +import { getFormattedTime } from "molstar/lib/mol-util/date"; +import { download } from "molstar/lib/mol-util/download"; +import { zip } from "molstar/lib/mol-util/zip/zip"; +import { PluginCommands } from "molstar/lib/mol-plugin/commands"; +import { PluginCustomState } from "./plugin-custom-state"; + +export async function superpositionExportHierarchy( + plugin: PluginContext, + options?: { format?: "cif" | "bcif" } +) { + try { + await plugin.runTask(_superpositionExportHierarchy(plugin, options), { + useOverlay: true, + }); + } catch (e) { + console.error(e); + plugin.log.error(`Model export failed. See console for details.`); + } +} + +function _superpositionExportHierarchy( + plugin: PluginContext, + options?: { format?: "cif" | "bcif" } +) { + return Task.create("Export", async (ctx) => { + await ctx.update({ + message: "Exporting...", + isIndeterminate: true, + canAbort: false, + }); + + const format = options?.format ?? "cif"; + // const { structures } = plugin.managers.structure.hierarchy.current; + const customState = PluginCustomState(plugin); + if (!customState.initParams) + throw new Error("customState.initParams has not been initialized"); + if (!customState.superpositionState) + throw new Error( + "customState.superpositionState has not been initialized" + ); + const superpositionState = customState.superpositionState; + + const segmentIndex = superpositionState.activeSegment - 1; + const files: [name: string, data: string | Uint8Array][] = []; + const entryMap = new Map(); + const structures = + superpositionState.loadedStructs[segmentIndex].slice(); + if (!customState.initParams.moleculeId) + throw new Error("initParams.moleculeId is not defined"); + if (superpositionState.alphafold.ref) + structures.push(`AF-${customState.initParams.moleculeId}`); + for (const molId of structures) { + const modelRef = superpositionState.models[molId]; + if (!modelRef) continue; + let isStrHidden = false; + const _s: any = + plugin.managers.structure.hierarchy.current.refs.get(modelRef!); + if (_s.cell.state.isHidden) isStrHidden = true; + for (const strComp of _s.components) { + if (strComp.cell.state.isHidden) isStrHidden = true; + } + if (isStrHidden) continue; + + const s = _s.transform?.cell.obj?.data ?? _s.cell.obj?.data; + if (!s) continue; + if (s.models.length > 1) { + plugin.log.warn( + `[Export] Skipping ${_s.cell.obj?.label}: Multimodel exports not supported.` + ); + continue; + } + if (s.units.some((u: any) => !Unit.isAtomic(u))) { + plugin.log.warn( + `[Export] Skipping ${_s.cell.obj?.label}: Non-atomic model exports not supported.` + ); + continue; + } + + const name = entryMap.has(s.model.entryId) + ? `${s.model.entryId}_${ + entryMap.get(s.model.entryId)! + 1 + }.${format}` + : `${s.model.entryId}.${format}`; + entryMap.set( + s.model.entryId, + (entryMap.get(s.model.entryId) ?? 0) + 1 + ); + + await ctx.update({ + message: `Exporting ${s.model.entryId}...`, + isIndeterminate: true, + canAbort: false, + }); + if (s.elementCount > 100000) { + // Give UI chance to update, only needed for larger structures. + await new Promise((res) => setTimeout(res, 50)); + } + + try { + files.push([ + name, + to_mmCIF(s.model.entryId, s, format === "bcif", { + copyAllCategories: true, + }), + ]); + } catch (e) { + if (format === "cif" && s.elementCount > 2000000) { + plugin.log.warn( + `[Export] The structure might be too big to be exported as Text CIF, consider using the BinaryCIF format instead.` + ); + } + throw e; + } + } + + if (files.length === 0) { + PluginCommands.Toast.Show(plugin, { + title: "Export Models", + message: "No visible structure in the 3D view to export!", + key: "superposition-toast-1", + timeoutMs: 7000, + }); + return; + } + + if (files.length === 1) { + download(new Blob([files[0][1]]), files[0][0]); + } else if (files.length > 1) { + const zipData: Record = {}; + for (const [fn, data] of files) { + if (data instanceof Uint8Array) { + zipData[fn] = data; + } else { + const bytes = new Uint8Array(utf8ByteCount(data)); + utf8Write(bytes, 0, data); + zipData[fn] = bytes; + } + } + await ctx.update({ + message: `Compressing Data...`, + isIndeterminate: true, + canAbort: false, + }); + const buffer = await zip(ctx, zipData); + download( + new Blob([new Uint8Array(buffer, 0, buffer.byteLength)]), + `structures_${getFormattedTime()}.zip` + ); + } + + plugin.log.info(`[Export] Done.`); + }); +} diff --git a/frontend/venome-molstar/src/app/superposition-focus-representation.ts b/frontend/venome-molstar/src/app/superposition-focus-representation.ts new file mode 100644 index 00000000..3f506c95 --- /dev/null +++ b/frontend/venome-molstar/src/app/superposition-focus-representation.ts @@ -0,0 +1,213 @@ +import { StructureElement } from "molstar/lib/mol-model/structure"; +import { createStructureRepresentationParams } from "molstar/lib/mol-plugin-state/helpers/structure-representation-params"; +import { PluginStateObject } from "molstar/lib/mol-plugin-state/objects"; +import { StateTransforms } from "molstar/lib/mol-plugin-state/transforms"; +import { PluginBehavior } from "molstar/lib/mol-plugin/behavior"; +import { MolScriptBuilder as MS } from "molstar/lib/mol-script/language/builder"; +import { + StateObjectCell, + StateSelection, + StateTransform, +} from "molstar/lib/mol-state"; +import { ParamDefinition as PD } from "molstar/lib/mol-util/param-definition"; +import { PluginCommands } from "molstar/lib/mol-plugin/commands"; +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import { lociDetails } from "./loci-details"; + +const SuperpositionFocusRepresentationParams = (plugin: PluginContext) => { + const reprParams = StateTransforms.Representation.StructureRepresentation3D + .definition.params!(void 0, plugin) as PD.Params; + return { + expandRadius: PD.Numeric(5, { min: 1, max: 10, step: 1 }), + surroundingsParams: PD.Group(reprParams, { + label: "Surroundings", + customDefault: createStructureRepresentationParams(plugin, void 0, { + type: "ball-and-stick", + size: "physical", + typeParams: { sizeFactor: 0.16 }, + sizeParams: { scale: 0.3 }, + }), + }), + }; +}; + +type SuperpositionFocusRepresentationProps = PD.ValuesFor< + ReturnType +>; + +export enum SuperpositionFocusRepresentationTags { + SurrSel = "superposition-focus-surr-sel", + SurrRepr = "superposition-focus-surr-repr", +} + +const TagSet: Set = new Set([ + SuperpositionFocusRepresentationTags.SurrSel, + SuperpositionFocusRepresentationTags.SurrRepr, +]); + +class SuperpositionFocusRepresentationBehavior extends PluginBehavior.WithSubscribers { + private get surrLabel() { + return `[Focus] Surroundings (${this.params.expandRadius} Ã…)`; + } + + private ensureShape( + cell: StateObjectCell + ) { + const state = this.plugin.state.data, + tree = state.tree; + const builder = state.build(); + const refs = StateSelection.findUniqueTagsInSubtree( + tree, + cell.transform.ref, + TagSet + ); + + // Selections + if (!refs[SuperpositionFocusRepresentationTags.SurrSel]) { + refs[SuperpositionFocusRepresentationTags.SurrSel] = builder + .to(cell) + .apply( + StateTransforms.Model.StructureSelectionFromExpression, + { + expression: MS.struct.generator.empty(), + label: this.surrLabel, + }, + { tags: SuperpositionFocusRepresentationTags.SurrSel } + ).ref; + } + + // Representations + if (!refs[SuperpositionFocusRepresentationTags.SurrRepr]) { + refs[SuperpositionFocusRepresentationTags.SurrRepr] = builder + .to(refs[SuperpositionFocusRepresentationTags.SurrSel]!) + .apply( + StateTransforms.Representation.StructureRepresentation3D, + this.params.surroundingsParams, + { tags: SuperpositionFocusRepresentationTags.SurrRepr } + ).ref; + } + + return { state, builder, refs }; + } + + private clear(root: StateTransform.Ref) { + const state = this.plugin.state.data; + + const surrs = state.select( + StateSelection.Generators.byRef(root) + .subtree() + .withTag(SuperpositionFocusRepresentationTags.SurrSel) + ); + if (surrs.length === 0) return; + + const update = state.build(); + const expression = MS.struct.generator.empty(); + for (const s of surrs) { + update + .to(s) + .update( + StateTransforms.Model.StructureSelectionFromExpression, + (old) => ({ ...old, expression }) + ); + } + + return PluginCommands.State.Update(this.plugin, { + state, + tree: update, + options: { doNotLogTiming: true, doNotUpdateCurrent: true }, + }); + } + + private async focus(sourceLoci: StructureElement.Loci) { + const parent = this.plugin.helpers.substructureParent.get( + sourceLoci.structure + ); + if (!parent || !parent.obj) return; + + const loci = StructureElement.Loci.remap(sourceLoci, parent.obj!.data); + + const residueLoci = StructureElement.Loci.extendToWholeResidues(loci); + const residueBundle = StructureElement.Bundle.fromLoci(residueLoci); + const target = StructureElement.Bundle.toExpression(residueBundle); + + let surroundings = MS.struct.modifier.includeSurroundings({ + 0: target, + radius: this.params.expandRadius, + "as-whole-residues": true, + }); + + const lociDeatils = lociDetails(sourceLoci); + if (!lociDeatils) { + surroundings = MS.struct.modifier.exceptBy({ + 0: surroundings, + by: target, + }); + } + + const { state, builder, refs } = this.ensureShape(parent); + + builder + .to(refs[SuperpositionFocusRepresentationTags.SurrSel]!) + .update( + StateTransforms.Model.StructureSelectionFromExpression, + (old) => ({ + ...old, + expression: surroundings, + label: this.surrLabel, + }) + ); + + await PluginCommands.State.Update(this.plugin, { + state, + tree: builder, + options: { doNotLogTiming: true, doNotUpdateCurrent: true }, + }); + } + + register(ref: string): void { + this.subscribeObservable( + this.plugin.managers.structure.focus.behaviors.current, + (entry) => { + // if (entry) this.focus(entry.loci); + // else this.clear(StateTransform.RootRef); + this.clear(StateTransform.RootRef); + if (entry) this.focus(entry.loci); + } + ); + } + + async update(params: SuperpositionFocusRepresentationProps) { + const old = this.params; + this.params = params; + + const state = this.plugin.state.data; + const builder = state.build(); + + const all = StateSelection.Generators.root.subtree(); + + for (const repr of state.select( + all.withTag(SuperpositionFocusRepresentationTags.SurrRepr) + )) { + builder.to(repr).update(this.params.surroundingsParams); + } + + await PluginCommands.State.Update(this.plugin, { + state, + tree: builder, + options: { doNotLogTiming: true, doNotUpdateCurrent: true }, + }); + + if (params.expandRadius !== old.expandRadius) + await this.clear(StateTransform.RootRef); + + return true; + } +} + +export const SuperpositionFocusRepresentation = PluginBehavior.create({ + name: "create-superposition-focus-representation", + display: { name: "Superposition Focus Representation" }, + category: "interaction", + ctor: SuperpositionFocusRepresentationBehavior, + params: (_, plugin) => SuperpositionFocusRepresentationParams(plugin), +}); diff --git a/frontend/venome-molstar/src/app/superposition-sifts-mapping.ts b/frontend/venome-molstar/src/app/superposition-sifts-mapping.ts new file mode 100644 index 00000000..01c8b807 --- /dev/null +++ b/frontend/venome-molstar/src/app/superposition-sifts-mapping.ts @@ -0,0 +1,250 @@ +import { Segmentation } from "molstar/lib/mol-data/int"; +import { MinimizeRmsd } from "molstar/lib/mol-math/linear-algebra/3d/minimize-rmsd"; +import { SIFTSMapping } from "./sifts-mapping"; +import { + ElementIndex, + ResidueIndex, +} from "molstar/lib/mol-model/structure/model/indexing"; +import { StructureElement } from "molstar/lib/mol-model/structure/structure/element"; +import { Structure } from "molstar/lib/mol-model/structure"; +import { Unit } from "molstar/lib/mol-model/structure/structure/unit"; + +export interface AlignmentResultEntry { + transform: MinimizeRmsd.Result; + pivot: number; + other: number; +} + +export interface AlignmentResult { + entries: AlignmentResultEntry[]; + zeroOverlapPairs: [number, number][]; + failedPairs: [number, number][]; +} + +type IncludeResidueTest = ( + traceElementOrFirstAtom: StructureElement.Location, + residueIndex: ResidueIndex, + startIndex: ElementIndex, + endIndex: ElementIndex +) => boolean; + +export function alignAndSuperposeWithSIFTSMapping( + structures: Structure[], + options?: { + traceOnly?: boolean; + includeResidueTest?: IncludeResidueTest; + applyTestIndex?: number[]; + } +): AlignmentResult { + const indexMap = new Map(); + + for (let i = 0; i < structures.length; i++) { + let includeResidueTest = + options?.includeResidueTest ?? _includeAllResidues; + if (options?.applyTestIndex && !options.applyTestIndex.includes(i)) + includeResidueTest = _includeAllResidues; + buildIndex( + structures[i], + indexMap, + i, + options?.traceOnly ?? true, + includeResidueTest + ); + } + + const index = Array.from(indexMap.values()); + + // TODO: support non-first structure pivots + const pairs = findPairs(structures.length, index); + + const zeroOverlapPairs: AlignmentResult["zeroOverlapPairs"] = []; + const failedPairs: AlignmentResult["failedPairs"] = []; + + const entries: AlignmentResultEntry[] = []; + for (const p of pairs) { + if (p.count === 0) { + zeroOverlapPairs.push([p.i, p.j]); + } else { + const [a, b] = getPositionTables(index, p.i, p.j, p.count); + const transform = MinimizeRmsd.compute({ a, b }); + if (Number.isNaN(transform.rmsd)) { + failedPairs.push([p.i, p.j]); + } else { + entries.push({ transform, pivot: p.i, other: p.j }); + } + } + } + + return { entries, zeroOverlapPairs, failedPairs }; +} + +function getPositionTables( + index: IndexEntry[], + pivot: number, + other: number, + N: number +) { + const xs = MinimizeRmsd.Positions.empty(N); + const ys = MinimizeRmsd.Positions.empty(N); + + let o = 0; + for (const { pivots } of index) { + const a = pivots[pivot]; + const b = pivots[other]; + if (!a || !b) continue; + + const l = Math.min(a[2] - a[1], b[2] - b[1]); + + // TODO: check if residue types match? + for (let i = 0; i < l; i++) { + let eI = (a[1] + i) as ElementIndex; + xs.x[o] = a[0].conformation.x(eI); + xs.y[o] = a[0].conformation.y(eI); + xs.z[o] = a[0].conformation.z(eI); + + eI = (b[1] + i) as ElementIndex; + ys.x[o] = b[0].conformation.x(eI); + ys.y[o] = b[0].conformation.y(eI); + ys.z[o] = b[0].conformation.z(eI); + o++; + } + } + + return [xs, ys]; +} + +function findPairs(N: number, index: IndexEntry[]) { + const pairwiseCounts: number[][] = []; + for (let i = 0; i < N; i++) { + pairwiseCounts[i] = []; + for (let j = 0; j < N; j++) pairwiseCounts[i][j] = 0; + } + + for (const { pivots } of index) { + for (let i = 0; i < N; i++) { + if (!pivots[i]) continue; + + const lI = pivots[i]![2] - pivots[i]![1]; + + for (let j = i + 1; j < N; j++) { + if (!pivots[j]) continue; + + const lJ = pivots[j]![2] - pivots[j]![1]; + pairwiseCounts[i][j] = pairwiseCounts[i][j] + Math.min(lI, lJ); + } + } + } + + const ret: { i: number; j: number; count: number }[] = []; + + for (let j = 1; j < N; j++) { + ret[j - 1] = { i: 0, j, count: pairwiseCounts[0][j] }; + } + + // TODO: support non-first structure pivots + // for (let i = 0; i < N - 1; i++) { + // let max = 0, maxJ = i; + // for (let j = i + 1; j < N; j++) { + // if (pairwiseCounts[i][j] > max) { + // maxJ = j; + // max = pairwiseCounts[i][j]; + // } + // } + + // ret[i] = { i, j: maxJ, count: max }; + // } + + return ret; +} + +interface IndexEntry { + key: string; + pivots: { + [i: number]: + | [unit: Unit.Atomic, start: ElementIndex, end: ElementIndex] + | undefined; + }; +} + +function _includeAllResidues() { + return true; +} + +function buildIndex( + structure: Structure, + index: Map, + sI: number, + traceOnly: boolean, + includeTest: IncludeResidueTest +) { + const loc = StructureElement.Location.create(structure); + + for (const unit of structure.units) { + if (unit.kind !== Unit.Kind.Atomic) continue; + + const { elements, model } = unit; + loc.unit = unit; + + const map = SIFTSMapping.Provider.get(model).value; + if (!map) return; + + const { dbName, accession, num } = map; + + const chainsIt = Segmentation.transientSegments( + unit.model.atomicHierarchy.chainAtomSegments, + elements + ); + const residuesIt = Segmentation.transientSegments( + unit.model.atomicHierarchy.residueAtomSegments, + elements + ); + const traceElementIndex = + unit.model.atomicHierarchy.derived.residue.traceElementIndex; + + while (chainsIt.hasNext) { + const chainSegment = chainsIt.move(); + residuesIt.setSegment(chainSegment); + while (residuesIt.hasNext) { + const residueSegment = residuesIt.move(); + const rI = residueSegment.index; + + if (!dbName[rI]) continue; + + const traceElement = traceElementIndex[rI]; + + let start, end; + if (traceOnly) { + start = traceElement; + if (start === -1) continue; + end = (start + 1) as ElementIndex; + } else { + start = elements[residueSegment.start]; + end = (elements[residueSegment.end - 1] + + 1) as ElementIndex; + } + + loc.element = ( + traceElement >= 0 ? traceElement : start + ) as ElementIndex; + if (!includeTest(loc, rI, start, end)) continue; + + const key = `${dbName[rI]}-${accession[rI].split("-")[0]}-${ + num[rI] + }`; + + if (!index.has(key)) { + index.set(key, { + key, + pivots: { [sI]: [unit, start, end] }, + }); + } else { + const entry = index.get(key)!; + + if (!entry.pivots[sI]) { + entry.pivots[sI] = [unit, start, end]; + } + } + } + } + } +} diff --git a/frontend/venome-molstar/src/app/superposition.ts b/frontend/venome-molstar/src/app/superposition.ts new file mode 100644 index 00000000..4fb4f1b2 --- /dev/null +++ b/frontend/venome-molstar/src/app/superposition.ts @@ -0,0 +1,1006 @@ +import { SymmetryOperator } from "molstar/lib/mol-math/geometry"; +import { Mat4 } from "molstar/lib/mol-math/linear-algebra"; +import { StructureProperties } from "molstar/lib/mol-model/structure"; +import { BuiltInTrajectoryFormat } from "molstar/lib/mol-plugin-state/formats/trajectory"; +import { + PluginStateObject as PSO, + PluginStateObject, +} from "molstar/lib/mol-plugin-state/objects"; +import { StateTransforms } from "molstar/lib/mol-plugin-state/transforms"; +import { PluginContext } from "molstar/lib/mol-plugin/context"; +import { MolScriptBuilder as MS } from "molstar/lib/mol-script/language/builder"; +import { Script } from "molstar/lib/mol-script/script"; +import { + State, + StateObjectRef, + StateObjectSelector, +} from "molstar/lib/mol-state"; +import { Task } from "molstar/lib/mol-task"; +import { Asset } from "molstar/lib/mol-util/assets"; +import { Color } from "molstar/lib/mol-util/color/color"; +import { ColorLists } from "molstar/lib/mol-util/color/lists"; +import { Subject } from "rxjs"; +import { applyAFTransparency } from "./alphafold-transparency"; +import { ModelInfo, ModelServerRequest, getStructureUrl } from "./helpers"; +import { ClusterMember, PluginCustomState } from "./plugin-custom-state"; +import { alignAndSuperposeWithSIFTSMapping } from "./superposition-sifts-mapping"; + +function getRandomColor(plugin: PluginContext, segmentIndex: number) { + const clList: any = ColorLists; + const spState = PluginCustomState(plugin).superpositionState; + if (!spState) + throw new Error( + "customState.superpositionState has not been initialized" + ); + let palleteIndex = spState.colorState[segmentIndex].palleteIndex; + let colorIndex = spState.colorState[segmentIndex].colorIndex; + if (clList[spState.colorPalette[palleteIndex]].list[colorIndex + 1]) { + colorIndex += 1; + } else { + colorIndex = 0; + palleteIndex = spState.colorPalette[palleteIndex + 1] + ? palleteIndex + 1 + : 0; + } + const palleteName = spState.colorPalette[palleteIndex]; + spState.colorState[segmentIndex].palleteIndex = palleteIndex; + spState.colorState[segmentIndex].colorIndex = colorIndex; + return clList[palleteName].list[colorIndex]; +} + +export async function initSuperposition( + plugin: PluginContext, + completeSubject?: Subject +) { + let success = false; + try { + await plugin.clear(); + + const customState = PluginCustomState(plugin); + customState.superpositionState = { + models: {}, + entries: {}, + refMaps: {}, + segmentData: void 0, + matrixData: {}, + activeSegment: 0, + loadedStructs: [], + visibleRefs: [], + invalidStruct: [], + noMatrixStruct: [], + hets: {}, + colorPalette: [ + "dark-2", + "red-yellow-green", + "paired", + "set-1", + "accent", + "set-2", + "rainbow", + ], + colorState: [], + alphafold: { + apiData: { + cif: "", + pae: "", + length: 0, + }, + length: 0, + ref: "", + traceOnly: true, + visibility: [], + transforms: [], + rmsds: [], + coordinateSystems: [], + }, + }; + + // Get segment and cluster information for the given uniprot accession + await getSegmentData(plugin); + const segmentData = customState.superpositionState.segmentData; + if (!segmentData) return; + + // Load Matrix Data + await getMatrixData(plugin); + if (!customState.superpositionState.segmentData) return; + + if (!customState.initParams!.moleculeId) + throw new Error("initParams.moleculeId is not defined"); + const afStrUrls = await getAfUrl( + plugin, + customState.initParams!.moleculeId + ); + if (afStrUrls) + customState.superpositionState.alphafold.apiData = afStrUrls; + + segmentData.forEach(() => { + customState.superpositionState!.loadedStructs.push([]); + customState.superpositionState!.visibleRefs.push([]); + customState.superpositionState!.colorState.push({ + palleteIndex: 0, + colorIndex: -1, + }); + }); + + // Set segment and cluster details from superPositionParams + const superpositionParams = customState.initParams!.superpositionParams; + const segmentIndex = superpositionParams?.segment + ? superpositionParams.segment - 1 + : 0; + customState.superpositionState.activeSegment = segmentIndex + 1; + const clusterIndexs = superpositionParams?.cluster + ? superpositionParams.cluster + : void 0; + + // Emit segment API data load event + customState.events?.superpositionInit.next(true); + + // Get entry list to load matrix data + let entryList: ClusterMember[] = []; + const clusters = segmentData[segmentIndex].clusters; + clusters.forEach((cluster: ClusterMember[], clusterIndex: number) => { + // Validate for cluster index if provided in superPositionParams + if (clusterIndexs && clusterIndexs.indexOf(clusterIndex) === -1) + return; + + // Add respresentative structure to the list + if (superpositionParams?.superposeAll) { + entryList = entryList.concat(cluster); + } else { + entryList.push(cluster[0]); + } + }); + + await renderSuperposition(plugin, segmentIndex, entryList); + success = true; + } finally { + completeSubject?.next(success); + } +} + +function createCarbVisLabel(carbLigNamesAndCount: any) { + const compList = []; + for (const carbCompId in carbLigNamesAndCount) { + compList.push(`${carbCompId} (${carbLigNamesAndCount[carbCompId]})`); + } + + return compList.join(", "); +} + +async function getAfUrl(plugin: PluginContext, accession: string) { + let apiResponse: any; + let apiData: any; + await plugin.runTask( + Task.create("Get AlphaFold URL", async (ctx) => { + try { + apiResponse = await plugin + .fetch({ + url: `https://alphafold.ebi.ac.uk/api/prediction/${accession}`, + type: "json", + }) + .runInContext(ctx); + if (apiResponse && apiResponse?.[0].bcifUrl) { + apiData = { + cif: apiResponse?.[0].cifUrl, + pae: apiResponse?.[0].paeImageUrl, + length: apiResponse?.[0].uniprotEnd, + }; + } + } catch (e) { + // console.warn(e); + } + }) + ); + + return apiData; +} + +export async function loadAfStructure(plugin: PluginContext) { + const customState = PluginCustomState(plugin); + if (!customState.superpositionState) + throw new Error( + "customState.superpositionState has not been initialized" + ); + const { structure } = await loadStructure( + plugin, + customState.superpositionState.alphafold.apiData.cif, + "mmcif", + false + ); + const strInstance = structure; + if (!strInstance) return false; + + // Store Refs in state + const spState = customState.superpositionState; + spState.alphafold.ref = strInstance?.ref; + if (!customState.initParams?.moleculeId) + throw new Error("initParams.moleculeId is not defined"); + spState.models[`AF-${customState.initParams.moleculeId}`] = + strInstance?.ref; + + const chainSel = await plugin.builders.structure.tryCreateComponentStatic( + strInstance, + "polymer", + { + label: `AlphaFold Structure`, + tags: [`alphafold-chain`, `superposition-sel`], + } + ); + + if (chainSel) { + await plugin.builders.structure.representation.addRepresentation( + chainSel, + { + type: "putty", + color: "plddt-confidence" as any, + size: "uniform", + sizeParams: { value: 1.5 }, + }, + { tag: `af-superposition-visual` } + ); + return strInstance?.ref; + } + + return false; +} + +export async function superposeAf( + plugin: PluginContext, + traceOnly: boolean, + segmentIndex?: number +) { + const customState = PluginCustomState(plugin); + const spState = customState.superpositionState; + if (!spState?.segmentData) return; + + // Load AF structure + const afStrRef = spState.alphafold.ref || (await loadAfStructure(plugin)); + if (!afStrRef) return; + const afStr: any = plugin.managers.structure.hierarchy.current.refs.get( + afStrRef! + ); + + const segmentNum = segmentIndex ? segmentIndex : spState.activeSegment - 1; + if (!spState.alphafold.transforms[segmentNum]) { + // Create representative list + const mappingResult: any = []; + const coordinateSystems: any = []; + const failedPairsResult: any = []; + const zeroOverlapPairsResult: any = []; + + let minRmsd = 0; + let minIndex = 0; + const rmsdList: string[] = []; + const segmentClusters = spState.segmentData[segmentNum].clusters; + segmentClusters.forEach((cluster: any) => { + const modelRef = + spState.models[ + `${cluster[0].pdb_id}_${cluster[0].struct_asym_id}` + ]; + if (modelRef) { + const structHierarchy: any = + plugin.managers.structure.hierarchy.current.refs.get( + modelRef! + ); + if (structHierarchy) { + const input = [structHierarchy.components[0], afStr]; + const structures = input.map((s) => s.cell.obj?.data!); + let { entries, failedPairs, zeroOverlapPairs } = + alignAndSuperposeWithSIFTSMapping(structures, { + traceOnly, + includeResidueTest: (loc) => + StructureProperties.atom.B_iso_or_equiv(loc) > + 70, + applyTestIndex: [1], + }); + + if ( + entries.length === 0 || + (entries && + entries[0] && + entries[0].transform.rmsd.toFixed(1) === "0.0") + ) { + const alignWithoutPlddt = + alignAndSuperposeWithSIFTSMapping(structures, { + traceOnly, + }); + entries = alignWithoutPlddt.entries; + } + + if (entries && entries[0]) { + mappingResult.push(entries[0]); + coordinateSystems.push( + input[0]?.transform?.cell.obj?.data.coordinateSystem + ); + const totalMappings = mappingResult.length; + if ( + totalMappings === 1 || + entries[0].transform.rmsd < minRmsd + ) { + minRmsd = entries[0].transform.rmsd; + minIndex = + totalMappings === 1 + ? 0 + : mappingResult.length - 1; + } + + rmsdList.push( + `${cluster[0].pdb_id} chain ${ + cluster[0].struct_asym_id + }:${entries[0].transform.rmsd.toFixed(2)}` + ); + } else { + if (failedPairs.length > 0) + failedPairsResult.push(failedPairs); + if (zeroOverlapPairs.length > 0) + zeroOverlapPairsResult.push(zeroOverlapPairs); + // rmsdList.push(`${cluster[0].pdb_id} ${cluster[0].struct_asym_id}:-`) + } + } + } + }); + + // console.log(failedPairsResult); + // console.log(zeroOverlapPairsResult); + if (mappingResult.length > 0) { + spState.alphafold.visibility[segmentNum] = true; + spState.alphafold.transforms[segmentNum] = + mappingResult[minIndex].transform.bTransform; + spState.alphafold.coordinateSystems[segmentNum] = + coordinateSystems[minIndex]; + spState.alphafold.rmsds[segmentNum] = rmsdList.sort( + (a: string, b: string) => + parseFloat(a.split(":")[1]) - parseFloat(b.split(":")[1]) + ); + } + } + + await afTransform( + plugin, + afStr.cell, + spState.alphafold.transforms[segmentNum], + spState.alphafold.coordinateSystems[segmentNum] + ); + applyAFTransparency(plugin, afStr, 0.8, 70); + + return true; +} + +export async function renderSuperposition( + plugin: PluginContext, + segmentIndex: number, + entryList: ClusterMember[] +) { + const customState = PluginCustomState(plugin); + const superpositionParams = customState.initParams!.superpositionParams; + let busyFlagOn = false; + if (entryList.length > 1) { + busyFlagOn = true; + customState.events?.isBusy.next(true); + } + + // Load Coordinates and render respresentations + return plugin.dataTransaction(async () => { + if (!customState.initParams) + throw new Error("customState.initParams has not been initialized"); + if (!customState.superpositionState) + throw new Error( + "customState.superpositionState has not been initialized" + ); + const spState = customState.superpositionState; + + for await (const s of entryList) { + // validate matrix availability + if (!spState.matrixData[`${s.pdb_id}_${s.auth_asym_id}`]) { + spState.noMatrixStruct.push(`${s.pdb_id}_${s.struct_asym_id}`); + spState.invalidStruct.push(`${s.pdb_id}_${s.struct_asym_id}`); + continue; + } + spState.loadedStructs[segmentIndex].push( + `${s.pdb_id}_${s.struct_asym_id}` + ); + + // Set Coordinate server url + const request: ModelServerRequest = + superpositionParams && superpositionParams.ligandView + ? { pdbId: s.pdb_id, queryType: "full" } + : { + pdbId: s.pdb_id, + queryType: "atoms", + queryParams: { auth_asym_id: s.auth_asym_id }, + }; + const strUrl = getStructureUrl(customState.initParams, request); + + // Load Data + let strInstance: any; + let modelRef: any; + let clearOnFail = true; + if ( + superpositionParams && + superpositionParams.ligandView && + spState.entries[s.pdb_id] + ) { + const polymerInstance = plugin.state.data.select( + spState.entries[s.pdb_id] + )[0]; + modelRef = polymerInstance.transform.parent; + const modelInstance = plugin.state.data.select(modelRef)[0]; + strInstance = await plugin.builders.structure.createStructure( + modelInstance, + { name: "model", params: {} } + ); + clearOnFail = false; + } else { + const isBinary = + customState.initParams.encoding === "bcif" ? true : false; + const { model, structure } = await loadStructure( + plugin, + strUrl, + "mmcif", + isBinary + ); + strInstance = structure; + modelRef = model!.ref; + } + + if (!strInstance) continue; + + // Store Refs in state + if (!spState.models[`${s.pdb_id}_${s.struct_asym_id}`]) + spState.models[`${s.pdb_id}_${s.struct_asym_id}`] = + strInstance?.ref; + if ( + superpositionParams && + superpositionParams.ligandView && + !spState.entries[s.pdb_id] + ) + spState.entries[s.pdb_id] = strInstance?.ref; + + // Apply tranform matrix + const matrix = Mat4.ofRows( + customState.superpositionState.matrixData[ + `${s.pdb_id}_${s.auth_asym_id}` + ].matrix + ); + await transform(plugin, strInstance, matrix); + + // Create representations + let chainSel: StateObjectSelector | undefined; + if ( + superpositionParams && + superpositionParams.ligandView && + s.is_representative + ) { + const uniformColor1 = getRandomColor(plugin, segmentIndex); // random color + chainSel = + await plugin.builders.structure.tryCreateComponentFromExpression( + strInstance, + chainSelection(s.struct_asym_id), + `Chain-${segmentIndex}`, + { label: `Chain`, tags: [`superposition-sel`] } + ); + if (chainSel) { + await plugin.builders.structure.representation.addRepresentation( + chainSel, + { + type: "putty", + color: "uniform", + colorParams: { value: uniformColor1 }, + size: "uniform", + }, + { tag: `superposition-visual` } + ); + spState.refMaps[ + chainSel.ref + ] = `${s.pdb_id}_${s.struct_asym_id}`; + } + } else if ( + superpositionParams && + superpositionParams.ligandView && + !s.is_representative + ) { + // Do nothing + } else { + const uniformColor2 = getRandomColor(plugin, segmentIndex); // random color + chainSel = + await plugin.builders.structure.tryCreateComponentStatic( + strInstance, + "polymer", + { + label: `Chain`, + tags: [ + `Chain-${segmentIndex}`, + `superposition-sel`, + ], + } + ); + if (chainSel) { + await plugin.builders.structure.representation.addRepresentation( + chainSel, + { + type: "putty", + color: "uniform", + colorParams: { value: uniformColor2 }, + size: "uniform", + }, + { tag: `superposition-visual` } + ); + spState.refMaps[ + chainSel.ref + ] = `${s.pdb_id}_${s.struct_asym_id}`; + } + + // // const addTooltipUpdate = plugin.state.behaviors.build().to(BestDatabaseSequenceMapping.id).update(BestDatabaseSequenceMapping, (old: any) => { old.showTooltip = true; }); + // // await plugin.runTask(plugin.state.behaviors.updateTree(addTooltipUpdate)); + // BestDatabaseSequenceMapping + // console.log(plugin.state.data.select(modelRef)[0]) + } + + let invalidStruct = chainSel ? false : true; + if (superpositionParams && superpositionParams.ligandView) { + const state = plugin.state.data; + const hetInfo = await getLigandNamesFromModelData( + plugin, + state, + modelRef + ); + const hets = hetInfo ? hetInfo.hetNames : []; + // const interactingHets = []; + if (hets && hets.length > 0) { + for await (const het of hets) { + const ligand = MS.struct.generator.atomGroups({ + "chain-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_asym_id(), + s.auth_asym_id, + ]), + "residue-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.label_comp_id(), + het, + ]), + "group-by": MS.core.str.concat([ + MS.struct.atomProperty.core.operatorName(), + MS.struct.atomProperty.macromolecular.residueKey(), + ]), + }); + + const labelTagParams = { + label: `${het}`, + tags: [`superposition-ligand-sel`], + }; + let hetColor = Color.fromRgb(253, 3, 253); + if (superpositionParams?.ligandColor) { + const { r, g, b } = superpositionParams.ligandColor; + hetColor = Color.fromRgb(r, g, b); + } + const ligandExp = + await plugin.builders.structure.tryCreateComponentFromExpression( + strInstance, + ligand, + `${het}-${segmentIndex}`, + labelTagParams + ); + if (ligandExp) { + await plugin.builders.structure.representation.addRepresentation( + ligandExp, + { + type: "ball-and-stick", + color: "uniform", + colorParams: { value: hetColor }, + }, + { tag: `superposition-ligand-visual` } + ); + spState.refMaps[ + ligandExp.ref + ] = `${s.pdb_id}_${s.struct_asym_id}`; + invalidStruct = false; + // interactingHets.push(het); + } + } + } + + const carbEntityCount = hetInfo ? hetInfo.carbEntityCount : 0; + if (carbEntityCount > 0) { + // Get Carbohydrate Polymers details from PDBe API + const allCarbPolymers = await getCarbPolymerDetailsFromApi( + plugin, + s.pdb_id + ); + + // Polymer chain + surroundings query + const polymerChainWithSurroundings = + MS.struct.modifier.includeSurroundings({ + 0: MS.struct.generator.atomGroups({ + "entity-test": MS.core.rel.eq([ + MS.ammp("entityType"), + "polymer", + ]), + "chain-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_asym_id(), + s.auth_asym_id, + ]), + "group-by": MS.core.str.concat([ + MS.struct.atomProperty.core.operatorName(), + MS.struct.atomProperty.macromolecular.residueKey(), + ]), + }), + radius: 5, + "as-whole-residues": true, + }); + + let i = 0; + for (const carbEntityChainId of allCarbPolymers.branchedChains) { + const carbEntityChain = MS.struct.generator.atomGroups({ + "entity-test": MS.core.rel.eq([ + MS.ammp("entityType"), + "branched", + ]), + "chain-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_asym_id(), + carbEntityChainId, + ]), + "group-by": MS.core.str.concat([ + MS.struct.atomProperty.core.operatorName(), + MS.struct.atomProperty.macromolecular.residueKey(), + ]), + }); + + const carbEntityChainInVicinity = + MS.struct.filter.intersectedBy({ + 0: polymerChainWithSurroundings, + by: carbEntityChain, + }); + + const data = plugin.state.data.select( + strInstance.ref + )[0].obj.data; + const carbChainSel = Script.getStructureSelection( + carbEntityChainInVicinity, + data + ); + if (carbChainSel && carbChainSel.kind === "sequence") { + // console.log(carbEntityChainId + ' chain present in 5 A radius'); + const carbLigands = []; + const carbLigNamesAndCount: any = {}; + const carbLigList = []; + + for (const carbLigs of allCarbPolymers + .branchedLigands[i]) { + const ligResDetails = carbLigs.split("-"); + carbLigands.push( + MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_seq_id(), + +ligResDetails[1], + ]) + ); + + if (carbLigNamesAndCount[ligResDetails[0]]) { + carbLigNamesAndCount[ligResDetails[0]]++; + } else { + carbLigNamesAndCount[ligResDetails[0]] = 1; + } + + carbLigList.push(ligResDetails[0]); + } + + const carbVisLabel = + createCarbVisLabel(carbLigNamesAndCount); + + const branchedEntity = + MS.struct.generator.atomGroups({ + "entity-test": MS.core.rel.eq([ + MS.ammp("entityType"), + "branched", + ]), + "group-by": MS.core.str.concat([ + MS.struct.atomProperty.core.operatorName(), + MS.struct.atomProperty.macromolecular.residueKey(), + ]), + "chain-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.auth_asym_id(), + carbEntityChainId, + ]), + "residue-test": + MS.core.logic.or(carbLigands), + }); + + const labelTagParams = { + label: `${carbVisLabel}`, + tags: [`superposition-carb-sel`], + }; + const ligandExp = + await plugin.builders.structure.tryCreateComponentFromExpression( + strInstance, + branchedEntity, + `${carbLigList.join("-")}-${segmentIndex}`, + labelTagParams + ); + if (ligandExp) { + await plugin.builders.structure.representation.addRepresentation( + ligandExp, + { type: "carbohydrate" }, + { tag: `superposition-carb-visual` } + ); + spState.refMaps[ + ligandExp.ref + ] = `${s.pdb_id}_${s.struct_asym_id}`; + invalidStruct = false; + } + } + + i++; + } + } + + if (invalidStruct) { + spState.invalidStruct.push( + `${s.pdb_id}_${s.struct_asym_id}` + ); + const loadedStructIndex = spState.loadedStructs[ + segmentIndex + ].indexOf(`${s.pdb_id}_${s.struct_asym_id}`); + if (loadedStructIndex > -1) + spState.loadedStructs[segmentIndex].splice( + loadedStructIndex, + 1 + ); + + // remove downloaded data + if (clearOnFail) { + // const m = plugin.state.data.select(modelRef)[0]; + // const t = plugin.state.data.select(m.transform.parent)[0]; + // const d = plugin.state.data.select(t.transform.parent)[0]; + // PluginCommands.State.RemoveObject(plugin, { state: d.parent!, ref: d.transform.parent, removeParentGhosts: true }); + } + } else { + // if(interactingHets.length > 0) spState.hets[`${s.pdb_id}_${s.struct_asym_id}`] = interactingHets; + } + } + } + if (busyFlagOn) { + busyFlagOn = false; + customState.events?.isBusy.next(false); + } + }); +} + +async function getLigandNamesFromModelData( + plugin: PluginContext, + state: State, + modelRef: string +) { + const cell = state.select(modelRef)[0]; + if (!cell || !cell.obj) return void 0; + const model = cell.obj.data; + if (!model) return; + + const structures: any[] = []; + for (const s of plugin.managers.structure.hierarchy.selection.structures) { + const structure = s.cell.obj?.data; + if (structure) structures.push(structure); + } + + const info = await ModelInfo.get(model, structures); + return info; +} + +async function loadStructure( + plugin: PluginContext, + url: string, + format: BuiltInTrajectoryFormat, + isBinary?: boolean +) { + try { + const data = await plugin.builders.data.download({ + url: Asset.Url(url), + isBinary: isBinary, + }); + const trajectory = await plugin.builders.structure.parseTrajectory( + data, + format + ); + const model = await plugin.builders.structure.createModel(trajectory); + const modelProperties = + await plugin.builders.structure.insertModelProperties(model); + const structure = await plugin.builders.structure.createStructure( + modelProperties || model, + { name: "model", params: {} } + ); + await plugin.builders.structure.insertStructureProperties(structure); + + return { data, trajectory, model, structure }; + } catch (e) { + return { structure: void 0 }; + } +} + +function chainSelection(struct_asym_id: string) { + return MS.struct.generator.atomGroups({ + "chain-test": MS.core.rel.eq([ + MS.struct.atomProperty.macromolecular.label_asym_id(), + struct_asym_id, + ]), + }); +} + +function transform( + plugin: PluginContext, + s: StateObjectRef, + matrix: Mat4 +) { + const b = plugin.state.data + .build() + .to(s) + .insert(StateTransforms.Model.TransformStructureConformation, { + transform: { + name: "matrix", + params: { data: matrix, transpose: false }, + }, + }); + return plugin.runTask(plugin.state.data.updateTree(b)); +} + +async function afTransform( + plugin: PluginContext, + s: StateObjectRef, + matrix: Mat4, + coordinateSystem?: SymmetryOperator +) { + const r = StateObjectRef.resolveAndCheck(plugin.state.data, s); + if (!r) return; + const o = plugin.state.data.selectQ((q) => + q + .byRef(r.transform.ref) + .subtree() + .withTransformer( + StateTransforms.Model.TransformStructureConformation + ) + )[0]; + + const transform = + coordinateSystem && !Mat4.isIdentity(coordinateSystem.matrix) + ? Mat4.mul(Mat4(), coordinateSystem.matrix, matrix) + : matrix; + + const params = { + transform: { + name: "matrix" as const, + params: { data: transform, transpose: false }, + }, + }; + const b = o + ? plugin.state.data.build().to(o).update(params) + : plugin.state.data + .build() + .to(s) + .insert( + StateTransforms.Model.TransformStructureConformation, + params, + { tags: "SuperpositionTransform" } + ); + await plugin.runTask(plugin.state.data.updateTree(b)); +} + +async function getMatrixData(plugin: PluginContext) { + const customState = PluginCustomState(plugin); + if (!customState.initParams) + throw new Error("customState.initParams has not been initialized"); + if (!customState.superpositionState) + throw new Error( + "customState.superpositionState has not been initialized" + ); + + const matrixAccession = + customState.initParams.superpositionParams?.matrixAccession ?? + customState.initParams.moleculeId; + const clusterRecUrlStr = `${customState.initParams.pdbeUrl}static/superpose/matrices/${matrixAccession}`; + const assetManager = plugin.managers.asset; + const clusterRecUrl = Asset.getUrlAsset(assetManager, clusterRecUrlStr); + try { + const clusterRecData = await plugin.runTask( + assetManager.resolve(clusterRecUrl, "json", false) + ); + if (clusterRecData && clusterRecData.data) { + customState.superpositionState.matrixData = clusterRecData.data; + } + } catch (e) { + customState.superpositionError = `Matrix data not available for ${matrixAccession}`; + customState.events?.superpositionInit.next(true); // Emit segment API data load event + } +} + +async function getSegmentData(plugin: PluginContext) { + const customState = PluginCustomState(plugin); + if (!customState.initParams) + throw new Error("customState.initParams has not been initialized"); + if (!customState.superpositionState) + throw new Error( + "customState.superpositionState has not been initialized" + ); + + // Get Data + const segmentsUrl = `${customState.initParams.pdbeUrl}graph-api/uniprot/superposition/${customState.initParams.moleculeId}`; + const assetManager = plugin.managers.asset; + const url = Asset.getUrlAsset(assetManager, segmentsUrl); + try { + const result = await plugin.runTask( + assetManager.resolve(url, "json", false) + ); + if (result?.data) { + customState.superpositionState.segmentData = + result.data[customState.initParams.moleculeId!]; + } + } catch (e) { + customState.superpositionError = `Superposition data not available for ${customState.initParams.moleculeId}`; + customState.events?.superpositionInit.next(true); // Emit segment API data load event + } +} + +function getChainLigands(carbEntity: any) { + const ligandChain: string[] = []; + const ligandLabels: string[] = []; + const ligands: string[][] = []; + + const labelValueArr = []; + let ligNameStr = ""; + for (const chemComp of carbEntity.chem_comp_list) { + labelValueArr.push(`${chemComp.chem_comp_id} (${chemComp.count})`); + } + ligNameStr = labelValueArr.join(", "); + + for (const chain of carbEntity.chains) { + ligandChain.push(chain.chain_id); + ligandLabels.push(ligNameStr); + const chainLigands = []; + for (const residue of chain.residues) { + chainLigands.push( + residue.chem_comp_id + "-" + residue.residue_number + ); + } + ligands.push(chainLigands); + } + + return { + ligands, + ligandChain, + ligandLabels, + }; +} + +async function getCarbPolymerDetailsFromApi( + plugin: PluginContext, + pdb_id: string +) { + const customState = PluginCustomState(plugin); + if (!customState.initParams) + throw new Error("customState.initParams has not been initialized"); + + // Get Data + const apiUrl = `${customState.initParams.pdbeUrl}api/pdb/entry/carbohydrate_polymer/${pdb_id}`; + const assetManager = plugin.managers.asset; + const url = Asset.getUrlAsset(assetManager, apiUrl); + let branchedLigands: string[][] = []; + let branchedChains: string[] = []; + let branchedlabels: string[] = []; + try { + const result = await plugin.runTask( + assetManager.resolve(url, "json", false) + ); + if (result && result.data) { + const carbEntities = result.data[pdb_id]; + for (const carbEntity of carbEntities) { + const carbLigData = getChainLigands(carbEntity); + branchedLigands = branchedLigands.concat(carbLigData.ligands); + branchedChains = branchedChains.concat(carbLigData.ligandChain); + branchedlabels = branchedlabels.concat( + carbLigData.ligandLabels + ); + } + } + } catch (e) {} + + return { + branchedChains, + branchedLigands, + branchedlabels, + }; +} diff --git a/frontend/venome-molstar/src/app/ui/alphafold-superposition.tsx b/frontend/venome-molstar/src/app/ui/alphafold-superposition.tsx new file mode 100644 index 00000000..9b6509de --- /dev/null +++ b/frontend/venome-molstar/src/app/ui/alphafold-superposition.tsx @@ -0,0 +1,236 @@ +import React from 'react'; +import { CollapsableControls, PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { TuneSvg, SuperposeChainsSvg, SuperpositionSvg, Icon } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { Button, ToggleButton } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { superposeAf } from '../superposition'; +import { scaleLinear as d3ScaleLinear } from 'd3-scale'; +import { axisBottom as d3AxisBotom, axisLeft as d3AxisLeft } from 'd3-axis'; +import { select as d3Select } from 'd3-selection'; +import { PluginCustomState } from '../plugin-custom-state'; + +const _InfoIcon = ; +export function InfoIconSvg() { return _InfoIcon; } + +export class AlphafoldPaeControls extends CollapsableControls { + private axisBoxRef: any; + defaultState() { + return { + isCollapsed: false, + header: 'AlphaFold PAE', + brand: { accent: 'gray' as const, svg: SuperpositionSvg }, + isHidden: true + }; + } + + constructor(props: any, context: any) { + super(props, context); + this.axisBoxRef = React.createRef(); + } + + componentDidMount() { + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, sel => { + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (superpositionState && superpositionState.alphafold.ref && superpositionState.alphafold.apiData.pae && superpositionState.alphafold.apiData.pae !== '' && superpositionState.alphafold.apiData.pae !== '') { + this.setState({ isHidden: false }); + + const domainMax = superpositionState.alphafold.apiData.length; + + const x = d3ScaleLinear().domain([0, domainMax]).range([0, 200]); + const xAxis = d3AxisBotom(x).ticks(6).tickFormat(this.formatTicks).tickSizeOuter(0); + const yAxis = d3AxisLeft(x).ticks(6).tickFormat(this.formatTicks).tickSizeOuter(0); + const axisContainer = d3Select(this.axisBoxRef.current); + + axisContainer.append('svg:svg') + .attr('width', 220) + .attr('height', 30) + .attr('class', 'pae-x-axis') + .style('z-index', '1') + .style('position', 'absolute') + .attr('transform', `translate(-93,202)`) + .append('g') + .attr('transform', `translate(6,0)`) + .call(xAxis); + + axisContainer.append('svg:svg') + .attr('width', 50) + .attr('height', 220) + .attr('class', 'pae-y-axis') + .style('z-index', '1') + .style('position', 'absolute') + .attr('transform', `translate(-123,0)`) + .append('g') + .attr('transform', `translate(36,4)`) + .call(yAxis); + + } + }); + + + } + + formatTicks(d: any) { + return d > 999 ? d / 1000 + 'k' : d; + } + + renderControls() { + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (!superpositionState || !superpositionState.alphafold) return null; + + const errorScale = [0, 5, 10, 15, 20, 25, 30]; + + return
+ +
+ Aligned residue + +
+
+ PAE +
+
Scored residue
+ + PAE Scale +
    + {errorScale.map((errValue) =>
  • {errValue}
  • )} +
+ +
Expected position error (Ångströms)
+ +
+
; + } +} + +export class AlphafoldSuperpositionControls extends CollapsableControls { + defaultState() { + return { + isCollapsed: false, + header: 'AlphaFold Superposition', + brand: { accent: 'gray' as const, svg: SuperpositionSvg }, + isHidden: true + }; + } + + componentDidMount() { + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, sel => { + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (superpositionState && superpositionState.alphafold.apiData.cif && superpositionState.alphafold.apiData.cif !== '') { + this.setState({ isHidden: false }); + } + }); + } + + rmsdTable() { + const spData = PluginCustomState(this.plugin).superpositionState; + if (!spData) throw new Error('customState.superpositionState has not been initialized'); + const { activeSegment } = spData; + const { rmsds } = spData.alphafold; + return
+ {(rmsds.length === 0 || !rmsds[activeSegment - 1]) &&
+ No overlap found! +
+ } + {rmsds[activeSegment - 1] &&
+
Entry
+
RMSD (Å)
+
+ } + {rmsds[activeSegment - 1] && rmsds[activeSegment - 1].map((d: string) => { + const details = d.split(':'); + return details[1] !== '-' ?
+
{details[0]}
+
{details[1]}
+
: null; + })} +
; + } + + renderControls() { + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (!superpositionState) throw new Error('customState.superpositionState has not been initialized'); + return <> + {superpositionState.alphafold.ref !== '' && this.rmsdTable()} + {superpositionState.alphafold.ref === '' && } + ; + } +} + +export const AlphafoldSuperpositionParams = { + // alignSequences: PD.Boolean(true, { isEssential: true, description: 'For Chain-based 3D superposition, perform a sequence alignment and use the aligned residue pairs to guide the 3D superposition.' }), + traceOnly: PD.Boolean(true, { description: 'For Chain- and Uniprot-based 3D superposition, base superposition only on CA (and equivalent) atoms.' }) +}; +const DefaultAlphafoldSuperpositionOptions = PD.getDefaultValues(AlphafoldSuperpositionParams); +export type AlphafoldSuperpositionOptions = PD.ValuesFor + +// const SuperpositionTag = 'SuperpositionTransform'; + +type AfSuperpositionControlsState = { + isBusy: boolean, + action?: 'byChains' | 'byAtoms' | 'options', + canUseDb?: boolean, + options: AlphafoldSuperpositionOptions +} + +export class AfSuperpositionControls extends PurePluginUIComponent<{}, AfSuperpositionControlsState> { + state: AfSuperpositionControlsState = { + isBusy: false, + canUseDb: true, + action: undefined, + options: DefaultAlphafoldSuperpositionOptions + }; + + componentDidMount() { + this.subscribe(this.plugin.behaviors.state.isBusy, v => { + this.setState({ isBusy: v }); + }); + } + + get selection() { + return this.plugin.managers.structure.selection; + } + + get customState() { + return PluginCustomState(this.plugin); + } + + superposeDb = async () => { + this.setState({ isBusy: true }); + const spData = this.customState.superpositionState; + if (!spData) throw new Error('customState.superpositionState has not been initialized'); + spData.alphafold.traceOnly = this.state.options.traceOnly; + superposeAf(this.plugin, this.state.options.traceOnly); + }; + + toggleOptions = () => this.setState({ action: this.state.action === 'options' ? void 0 : 'options' }); + + superposeByDbMapping() { + return <> + + ; + } + + private setOptions = (values: AlphafoldSuperpositionOptions) => { + this.setState({ options: values }); + }; + + render() { + return <> +
New Feature!
+
+
Load and superpose AlphaFold structure against representative chains.
+
+
+ {this.state.canUseDb && this.superposeByDbMapping()} + +
+ {this.state.action === 'options' &&
+ +
} + ; + + } +} \ No newline at end of file diff --git a/frontend/venome-molstar/src/app/ui/alphafold-tranparency.tsx b/frontend/venome-molstar/src/app/ui/alphafold-tranparency.tsx new file mode 100644 index 00000000..9dbcb041 --- /dev/null +++ b/frontend/venome-molstar/src/app/ui/alphafold-tranparency.tsx @@ -0,0 +1,52 @@ +import { CollapsableControls } from 'molstar/lib/mol-plugin-ui/base'; +import { SuperpositionSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import { applyAFTransparency, clearStructureTransparency } from '../alphafold-transparency'; +import { PluginCustomState } from '../plugin-custom-state'; + + +const TransparencyParams = { + score: PD.Numeric(70, { min: 0, max: 100, step: 1 }, { label: 'pLDDT less than', description: 'pLDDT score value in the range of 0 to 100' }), + opacity: PD.Numeric(0.2, { min: 0, max: 1, step: 0.01 }, { description: 'Opacity value in the range 0 to 1' }) +}; +type TransparencyParams = PD.Values + +export class AlphafoldTransparencyControls extends CollapsableControls<{}, { transpareny: any }> { + defaultState() { + return { + isCollapsed: false, + header: 'AlphaFold Structure Opacity', + brand: { accent: 'gray' as const, svg: SuperpositionSvg }, + isHidden: true, + transpareny: { + score: 70, + opacity: 0.2 + } + }; + } + + componentDidMount() { + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, sel => { + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (superpositionState && superpositionState.alphafold.ref && superpositionState.alphafold.ref !== '') { + this.setState({ isHidden: false }); + } + }); + } + + updateTransparency = async (val: any) => { + this.setState({ transpareny: val }); + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (!superpositionState) throw new Error('customState.superpositionState has not been initialized'); + const afStr: any = this.plugin.managers.structure.hierarchy.current.refs.get(superpositionState.alphafold.ref!); + await clearStructureTransparency(this.plugin, afStr.components); + await applyAFTransparency(this.plugin, afStr, 1 - val.opacity, val.score); + }; + + renderControls() { + return <> + + ; + } +} \ No newline at end of file diff --git a/frontend/venome-molstar/src/app/ui/annotation-controls.tsx b/frontend/venome-molstar/src/app/ui/annotation-controls.tsx new file mode 100644 index 00000000..fcf2d726 --- /dev/null +++ b/frontend/venome-molstar/src/app/ui/annotation-controls.tsx @@ -0,0 +1,199 @@ +import { PDBeStructureQualityReport } from 'molstar/lib/extensions/pdbe/structure-quality-report/behavior'; +import { StructureQualityReportColorThemeProvider } from 'molstar/lib/extensions/pdbe/structure-quality-report/color'; +import { StructureHierarchyManager } from 'molstar/lib/mol-plugin-state/manager/structure/hierarchy'; +import { PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { Button } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { ArrowDropDownSvg, ArrowRightSvg, Icon } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { StateSelection, StateTransform } from 'molstar/lib/mol-state'; +import { PDBeDomainAnnotations } from '../domain-annotations/behavior'; +import { DomainAnnotationsColorThemeProvider } from '../domain-annotations/color'; +import { PluginCustomState } from '../plugin-custom-state'; +import { AnnotationRowControls } from './annotation-row-controls'; +import { SymmetryAnnotationControls, isAssemblySymmetryAnnotationApplicable } from './symmetry-annotation-controls'; + + +const _TextsmsOutlined = ; +export function TextsmsOutlinedSvg() { return _TextsmsOutlined; } + +type AnnotationType = 'validation' | 'domains' | 'symmetry' + +interface AnnotationsComponentControlsState { + isCollapsed: boolean, + validationApplied: boolean, + validationOptions: boolean, + validationParams: any, + domainsApplied: boolean, + domainsOptions: boolean, + domainsParams: any, + showSymmetryAnnotation: boolean, + description?: string, +} + + +export class AnnotationsComponentControls extends PurePluginUIComponent<{}, AnnotationsComponentControlsState> { + state: AnnotationsComponentControlsState = { + isCollapsed: false, + validationApplied: false, + validationOptions: false, + validationParams: undefined, + domainsApplied: false, + domainsOptions: false, + domainsParams: undefined, + showSymmetryAnnotation: false, + }; + + componentDidMount() { + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, () => { + this.initOptionParams(); + this.forceUpdate(); + }); + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, c => this.setState({ + description: StructureHierarchyManager.getSelectedStructuresDescription(this.plugin) + })); + } + + initOptionParams = () => { + const initParams = PluginCustomState(this.plugin).initParams; + const validationAnnotationCtrl = !!initParams?.validationAnnotation; + const domainAnnotationCtrl = !!initParams?.domainAnnotation; + const symmetryAnnotationCtrl = !!initParams?.symmetryAnnotation && isAssemblySymmetryAnnotationApplicable(this.plugin); + this.setState({ showSymmetryAnnotation: symmetryAnnotationCtrl }); + + if ((validationAnnotationCtrl && !this.state.validationParams) || (domainAnnotationCtrl && !this.state.domainsParams)) { + + const structure = this.getStructure()?.data; + if (structure) { + const themeDataCtx = { structure }; + + if (validationAnnotationCtrl && !this.state.validationParams) { + const validationActionsParams = StructureQualityReportColorThemeProvider.getParams(themeDataCtx); + if (validationActionsParams) { + this.setState({ + validationParams: { + params: validationActionsParams, + values: { type: validationActionsParams.type.defaultValue } + } + }); + } + } + + if (domainAnnotationCtrl && !this.state.domainsParams) { + const domainActionsParams = DomainAnnotationsColorThemeProvider.getParams(themeDataCtx); + if (domainActionsParams) { + this.setState({ + domainsParams: { + params: domainActionsParams, + values: { type: domainActionsParams.type.defaultValue } + } + }); + } + } + + } + } + }; + getStructure = () => { + const groupRef = StateSelection.findTagInSubtree(this.plugin.state.data.tree, StateTransform.RootRef, 'structure-component-static-polymer'); + return groupRef ? this.plugin.state.data.select(groupRef)[0]?.obj : undefined; + }; + + toggleCollapsed = () => { + this.setState({ isCollapsed: !this.state.isCollapsed }); + }; + + applyAnnotation = (type: 'validation' | 'domains', visibleState: boolean, params?: any) => { + // Defaults + let themeName: any = 'chain-id'; + let themePropsToAdd = PDBeStructureQualityReport; + let themePropsToRemove = this.state.domainsParams ? PDBeDomainAnnotations : void 0; + + // Set Theme Params + if (type === 'validation') { + if (visibleState) { + themeName = 'pdbe-structure-quality-report'; + } + this.setState({ validationApplied: visibleState }); + this.setState({ domainsApplied: false }); + } else if (type === 'domains') { + themePropsToAdd = PDBeDomainAnnotations; + themePropsToRemove = this.state.validationParams ? PDBeStructureQualityReport : void 0; + if (visibleState) themeName = 'pdbe-domain-annotations'; + this.setState({ domainsApplied: visibleState }); + this.setState({ validationApplied: false }); + } + + // Update Tooltip + if (visibleState && themeName !== 'chain-id') { + const addTooltipUpdate = this.plugin.state.behaviors.build().to(themePropsToAdd.id).update(themePropsToAdd, (old: any) => { old.showTooltip = true; }); + this.plugin.runTask(this.plugin.state.behaviors.updateTree(addTooltipUpdate)); + + if (themePropsToRemove) { + const removeTooltipUpdate = this.plugin.state.behaviors.build().to(themePropsToRemove.id).update(themePropsToRemove, (old: any) => { old.showTooltip = false; }); + this.plugin.runTask(this.plugin.state.behaviors.updateTree(removeTooltipUpdate)); + } + } + + let polymerGroup: any; + const componentGroups = this.plugin.managers.structure.hierarchy.currentComponentGroups; + componentGroups.forEach((compGrp) => { + if (compGrp[0].key === 'structure-component-static-polymer') polymerGroup = compGrp; + }); + if (polymerGroup) { + this.plugin.managers.structure.component.updateRepresentationsTheme(polymerGroup, { color: themeName, colorParams: params ? params : void 0 }); + } + }; + + toggleAnnotation = (type: AnnotationType) => { + if (type === 'validation') this.applyAnnotation('validation', !this.state.validationApplied, this.state.validationParams.values); + if (type === 'domains') this.applyAnnotation('domains', !this.state.domainsApplied, this.state.domainsParams.values); + }; + + updateValidationParams = (val: any) => { + const updatedParams = { ...this.state.validationParams }; + updatedParams.values = val; + this.setState({ validationParams: updatedParams }); + if (this.state.validationApplied) this.applyAnnotation('validation', this.state.validationApplied, val); + }; + updateDomainParams = (val: any) => { + const updatedParams = { ...this.state.domainsParams }; + updatedParams.values = val; + this.setState({ domainsParams: updatedParams }); + if (this.state.domainsApplied) this.applyAnnotation('domains', this.state.domainsApplied, val); + }; + + render() { + if (!this.state.validationParams && !this.state.domainsParams && !this.state.showSymmetryAnnotation) return <>; + + const brand = { + accent: 'green', + svg: TextsmsOutlinedSvg + }; + + const wrapClass = this.state.isCollapsed + ? 'msp-transform-wrapper msp-transform-wrapper-collapsed' + : 'msp-transform-wrapper'; + + return
+
+ +
+ + {!this.state.isCollapsed && <> + this.toggleAnnotation('validation')} /> + this.toggleAnnotation('domains')} /> + {this.state.showSymmetryAnnotation && + } + } +
; + } +} diff --git a/frontend/venome-molstar/src/app/ui/annotation-row-controls.tsx b/frontend/venome-molstar/src/app/ui/annotation-row-controls.tsx new file mode 100644 index 00000000..03080da5 --- /dev/null +++ b/frontend/venome-molstar/src/app/ui/annotation-row-controls.tsx @@ -0,0 +1,74 @@ +import { Button, IconButton } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { MoreHorizSvg, VisibilityOffOutlinedSvg, VisibilityOutlinedSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { ParameterControls, ParameterControlsProps } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import React from 'react'; + + +type AnnotationRowControlsProps

= ParameterControlsProps

& { + shortTitle?: string, + title: string, + applied?: boolean, + onChangeApplied?: (applied: boolean) => void, +} + +type AnnotationRowControlsState = { + applied: boolean, + optionsExpanded: boolean, +} + + +/** UI controls for a single annotation source (row) in Annotations section */ +export class AnnotationRowControls

extends React.PureComponent, AnnotationRowControlsState> { + state = { applied: false, optionsExpanded: false }; + + // componentDidMount() { + // this.subscribe(this.plugin.state.events.cell.stateUpdated, e => { + // if (State.ObjectEvent.isCell(e, this.pivot.cell)) this.forceUpdate(); + // }); + // } + + isApplied() { + return this.props.applied ?? this.state.applied; + } + + toggleApplied(applied?: boolean) { + const newState = applied ?? !this.isApplied(); + if (this.props.applied === undefined) { + this.setState({ applied: newState }); + } + this.props.onChangeApplied?.(newState); + } + + toggleOptions() { + this.setState(s => ({ optionsExpanded: !s.optionsExpanded })); + } + + render() { + if (!this.props.params) return null; + return <> +

+ + this.toggleApplied()} toggleState={false} + svg={!this.isApplied() ? VisibilityOffOutlinedSvg : VisibilityOutlinedSvg} + title={`Click to ${this.isApplied() ? 'hide' : 'show'} ${this.props.title}`} small className='msp-form-control' flex /> + this.toggleOptions()} svg={MoreHorizSvg} title='Options' toggleState={this.state.optionsExpanded} className='msp-form-control' flex /> +
+ {this.state.optionsExpanded && +
+
+
+ {this.renderOptions()} +
+
+
+ } + ; + } + + renderOptions() { + return ; + } +} \ No newline at end of file diff --git a/frontend/venome-molstar/src/app/ui/export-superposition.tsx b/frontend/venome-molstar/src/app/ui/export-superposition.tsx new file mode 100644 index 00000000..c1be9fee --- /dev/null +++ b/frontend/venome-molstar/src/app/ui/export-superposition.tsx @@ -0,0 +1,63 @@ +import { useState } from 'react'; +import { CollapsableControls, CollapsableState } from 'molstar/lib/mol-plugin-ui/base'; +import { Button } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { GetAppSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { useBehavior } from 'molstar/lib/mol-plugin-ui/hooks/use-behavior'; +import { PluginContext } from 'molstar/lib/mol-plugin/context'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import { superpositionExportHierarchy } from '../superposition-export'; + +export class SuperpositionModelExportUI extends CollapsableControls<{}, {}> { + protected defaultState(): CollapsableState { + return { + header: 'Export Models', + isCollapsed: true, + brand: { accent: 'cyan', svg: GetAppSvg } + }; + } + protected renderControls(): JSX.Element | null { + return ; + } +} + +const Params = { + format: PD.Select<'cif' | 'bcif'>('cif', [['cif', 'mmCIF'], ['bcif', 'Binary mmCIF']]) +}; +const DefaultParams = PD.getDefaultValues(Params); + +function SuperpositionExportControls({ plugin }: { plugin: PluginContext }) { + const [params, setParams] = useState(DefaultParams); + const [exporting, setExporting] = useState(false); + useBehavior(plugin.managers.structure.hierarchy.behaviors.selection); // triggers UI update + const isBusy = useBehavior(plugin.behaviors.state.isBusy); + const hierarchy = plugin.managers.structure.hierarchy.current; + + let label: string = 'Nothing to Export'; + if (hierarchy.structures.length === 1) { + label = 'Export'; + } if (hierarchy.structures.length > 1) { + label = 'Export (as ZIP)'; + } + + const onExport = async () => { + setExporting(true); + try { + await superpositionExportHierarchy(plugin, { format: params.format }); + } finally { + setExporting(false); + } + }; + + return <> + + + ; +} \ No newline at end of file diff --git a/frontend/venome-molstar/src/app/ui/pdbe-left-panel.tsx b/frontend/venome-molstar/src/app/ui/pdbe-left-panel.tsx new file mode 100644 index 00000000..0c42f3ba --- /dev/null +++ b/frontend/venome-molstar/src/app/ui/pdbe-left-panel.tsx @@ -0,0 +1,205 @@ +import { Canvas3DParams } from 'molstar/lib/mol-canvas3d/canvas3d'; +import { PluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { IconButton, SectionHeader } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { AccountTreeOutlinedSvg, DeleteOutlinedSvg, HelpOutlineSvg, HomeOutlinedSvg, TuneSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { StateObjectActions } from 'molstar/lib/mol-plugin-ui/state/actions'; +import { RemoteStateSnapshots, StateSnapshots } from 'molstar/lib/mol-plugin-ui/state/snapshots'; +import { StateTree } from 'molstar/lib/mol-plugin-ui/state/tree'; +import { HelpContent, HelpGroup, HelpText } from 'molstar/lib/mol-plugin-ui/viewport/help'; +import { PluginCommands } from 'molstar/lib/mol-plugin/commands'; +import { StateTransform } from 'molstar/lib/mol-state'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import * as React from 'react'; +import { PluginCustomState } from '../plugin-custom-state'; +import { SegmentTree } from './segment-tree'; + + +const _WavesIcon = ; +export function WavesIconSvg() { return _WavesIcon; } + +type LeftPanelTabName = 'none' | 'root' | 'data' | 'states' | 'settings' | 'help' | 'segments' + +export class LeftPanelControls extends PluginUIComponent<{}, { tab: LeftPanelTabName }> { + state = { tab: this.plugin.behaviors.layout.leftPanelTabName.value as LeftPanelTabName }; + + componentDidMount() { + this.subscribe(this.plugin.behaviors.layout.leftPanelTabName, tab => { + if (this.state.tab !== tab) this.setState({ tab }); + if (tab === 'none' && this.plugin.layout.state.regionState.left !== 'collapsed') { + PluginCommands.Layout.Update(this.plugin, { state: { regionState: { ...this.plugin.layout.state.regionState, left: 'collapsed' } } }); + } + }); + + this.subscribe(this.plugin.state.data.events.changed, ({ state }) => { + if (this.state.tab !== 'data') return; + if (state.cells.size === 1) this.set('root'); + }); + } + + set = (tab: LeftPanelTabName) => { + if (this.state.tab === tab) { + this.setState({ tab: 'none' }, () => this.plugin.behaviors.layout.leftPanelTabName.next('none')); + PluginCommands.Layout.Update(this.plugin, { state: { regionState: { ...this.plugin.layout.state.regionState, left: 'collapsed' } } }); + return; + } + + this.setState({ tab }, () => this.plugin.behaviors.layout.leftPanelTabName.next(tab as any)); + if (this.plugin.layout.state.regionState.left !== 'full') { + PluginCommands.Layout.Update(this.plugin, { state: { regionState: { ...this.plugin.layout.state.regionState, left: 'full' } } }); + } + }; + + tabs: { [K in LeftPanelTabName]: JSX.Element } = { + 'none': <>, + 'root': <> + + + {this.plugin.spec.components?.remoteState !== 'none' && } + , + 'data': <> + State Tree} /> + + , + 'segments': <> + {/* */} + + , + 'states': , + 'settings': <> + + + , + 'help': <> + + + + + }; + + render() { + const tab = this.state.tab; + const customState = PluginCustomState(this.plugin); + return
+
+ {/* this.set('root')} title='Home' /> */} + {/* */} + {/* this.set('states')} title='Plugin State' /> */} + this.set('help')} title='Help' /> + {customState && customState.initParams && customState.initParams.superposition && this.set('segments')} title='Superpose segments' />} +
+ this.set('settings')} title='Settings' /> +
+
+
+ {this.tabs[tab]} +
+
; + } +} + +// class DataIcon extends PluginUIComponent<{ set: (tab: LeftPanelTabName) => void }, { changed: boolean }> { +// state = { changed: false }; + +// get tab() { +// return this.plugin.behaviors.layout.leftPanelTabName.value; +// } + +// componentDidMount() { +// this.subscribe(this.plugin.behaviors.layout.leftPanelTabName, tab => { +// if (this.tab === 'data') this.setState({ changed: false }); +// else this.forceUpdate(); +// }); + +// this.subscribe(this.plugin.state.data.events.changed, state => { +// if (this.tab !== 'data') this.setState({ changed: true }); +// }); +// } + +// render() { +// return this.props.set('data')} title='State Tree' +// style={{ position: 'relative' }} extraContent={this.state.changed ?
: void 0} />; +// } +// } + +class FullSettings extends PluginUIComponent { + private setSettings = (p: { param: PD.Base, name: string, value: any }) => { + PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { [p.name]: p.value } }); + }; + + componentDidMount() { + this.subscribe(this.plugin.events.canvas3d.settingsUpdated, () => this.forceUpdate()); + this.subscribe(this.plugin.layout.events.updated, () => this.forceUpdate()); + + this.subscribe(this.plugin.canvas3d!.camera.stateChanged, state => { + if (state.radiusMax !== undefined || state.radius !== undefined) { + this.forceUpdate(); + } + }); + } + + render() { + return <> + {this.plugin.canvas3d && <> + + + } + {/* + */} + ; + } +} + +class RemoveAllButton extends PluginUIComponent<{}> { + componentDidMount() { + this.subscribe(this.plugin.state.events.cell.created, e => { + if (e.cell.transform.parent === StateTransform.RootRef) this.forceUpdate(); + }); + + this.subscribe(this.plugin.state.events.cell.removed, e => { + if (e.parent === StateTransform.RootRef) this.forceUpdate(); + }); + } + + remove = (e: React.MouseEvent) => { + e.preventDefault(); + PluginCommands.State.RemoveObject(this.plugin, { state: this.plugin.state.data, ref: StateTransform.RootRef }); + }; + + render() { + const count = this.plugin.state.data.tree.children.get(StateTransform.RootRef).size; + if (count === 0) return null; + return ; + } +} + +function HelpSection(props: { header: string }) { + return
{props.header}
; +} + +class SuperpositionHelpContent extends PluginUIComponent { + componentDidMount() { + this.subscribe(this.plugin.events.canvas3d.settingsUpdated, () => this.forceUpdate()); + } + render() { + return
+ + + +

Discrete UniProt sequence range mapped to the structure

+
+
+ + +

Structural chains that possess significantly close superposition Q-score

+
+
+ + +

The best-ranked chain within a cluster chosen based on the model quality, resolution, observed residues ratio and UniProt sequence coverage

+
+
+
; + } +} \ No newline at end of file diff --git a/frontend/venome-molstar/src/app/ui/pdbe-screenshot-controls.tsx b/frontend/venome-molstar/src/app/ui/pdbe-screenshot-controls.tsx new file mode 100644 index 00000000..7b18a01b --- /dev/null +++ b/frontend/venome-molstar/src/app/ui/pdbe-screenshot-controls.tsx @@ -0,0 +1,109 @@ +import * as React from 'react'; +import { PluginContext } from 'molstar/lib/mol-plugin/context'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { PluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { ScreenshotPreview } from 'molstar/lib/mol-plugin-ui/controls/screenshot'; +import { Button, ToggleButton } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { PluginCommands } from 'molstar/lib/mol-plugin/commands'; +import { useBehavior } from 'molstar/lib/mol-plugin-ui/hooks/use-behavior'; +import { GetAppSvg, CopySvg, CropOrginalSvg, CropSvg, CropFreeSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; + +interface ImageControlsState { + showPreview: boolean, + isDisabled: boolean, + imageData?: string +} + +export class DownloadScreenshotControls extends PluginUIComponent<{ close: () => void }, ImageControlsState> { + state: ImageControlsState = { + showPreview: true, + isDisabled: false + } as ImageControlsState; + + private download = () => { + this.plugin.helpers.viewportScreenshot?.download(); + this.props.close(); + }; + + private copy = async () => { + try { + await this.plugin.helpers.viewportScreenshot?.copyToClipboard(); + PluginCommands.Toast.Show(this.plugin, { + message: 'Copied to clipboard.', + title: 'Screenshot', + timeoutMs: 1500 + }); + } catch { + return this.copyImg(); + } + }; + + private copyImg = async () => { + const src = await this.plugin.helpers.viewportScreenshot?.getImageDataUri(); + this.setState({ imageData: src }); + }; + + componentDidMount() { + this.subscribe(this.plugin.state.data.behaviors.isUpdating, v => { + this.setState({ isDisabled: v }); + }); + } + + componentWillUnmount() { + this.setState({ imageData: void 0 }); + } + + open = (e: React.ChangeEvent) => { + if (!e.target.files || !e.target.files![0]) return; + PluginCommands.State.Snapshots.OpenFile(this.plugin, { file: e.target.files![0] }); + }; + + render() { + const hasClipboardApi = !!(navigator.clipboard as any)?.write; + + return
+ {this.state.showPreview &&
+ + +
} +
+ {!this.state.imageData && } + {this.state.imageData && } + +
+ {this.state.imageData &&
+
Right click below + Copy Image
+ +
} + +
; + } +} + +function ScreenshotParams({ plugin, isDisabled }: { plugin: PluginContext, isDisabled: boolean }) { + const helper = plugin.helpers.viewportScreenshot!; + const values = useBehavior(helper.behaviors.values); + + return helper.behaviors.values.next(v)} isDisabled={isDisabled} />; +} + +function CropControls({ plugin }: { plugin: PluginContext }) { + const helper = plugin.helpers.viewportScreenshot; + const cropParams = useBehavior(helper?.behaviors.cropParams!); + useBehavior(helper?.behaviors.relativeCrop); + + if (!helper) return null; + + return
+ helper.toggleAutocrop()} label={'Auto-crop ' + (cropParams.auto ? 'On' : 'Off')} /> + + {!cropParams.auto &&
; +} \ No newline at end of file diff --git a/frontend/venome-molstar/src/app/ui/pdbe-structure-controls.tsx b/frontend/venome-molstar/src/app/ui/pdbe-structure-controls.tsx new file mode 100644 index 00000000..374f57fe --- /dev/null +++ b/frontend/venome-molstar/src/app/ui/pdbe-structure-controls.tsx @@ -0,0 +1,77 @@ +import { PluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { StructureComponentControls } from 'molstar/lib/mol-plugin-ui/structure/components'; +import { StructureMeasurementsControls } from 'molstar/lib/mol-plugin-ui/structure/measurements'; +import { StructureSourceControls } from 'molstar/lib/mol-plugin-ui/structure/source'; +import { VolumeStreamingControls, VolumeSourceControls } from 'molstar/lib/mol-plugin-ui/structure/volume'; +import { AnnotationsComponentControls } from './annotation-controls'; +import { Icon, BuildSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { SuperpositionComponentControls } from './superposition-components'; +import { StructureQuickStylesControls } from 'molstar/lib/mol-plugin-ui/structure/quick-styles'; +import { AlphafoldPaeControls, AlphafoldSuperpositionControls } from './alphafold-superposition'; +import { SuperpositionModelExportUI } from './export-superposition'; +import { AlphafoldTransparencyControls } from './alphafold-tranparency'; +import { AssemblySymmetry } from 'molstar/lib/extensions/rcsb/assembly-symmetry/prop'; + + +export class PDBeStructureTools extends PluginUIComponent { + render() { + const AssemblySymmetryKey = AssemblySymmetry.Tag.Representation; + return <> +
Structure Tools
+ + + + + + + + + + ; + } +} + +export class CustomStructureControls extends PluginUIComponent<{ initiallyCollapsed?: boolean, takeKeys?: string[], skipKeys?: string[] }> { + componentDidMount() { + this.subscribe(this.plugin.state.behaviors.events.changed, () => this.forceUpdate()); + } + + render() { + const takeKeys = this.props.takeKeys ?? Array.from(this.plugin.customStructureControls.keys()); + const result: JSX.Element[] = []; + for (const key of takeKeys) { + if (this.props.skipKeys?.includes(key)) continue; + const Controls = this.plugin.customStructureControls.get(key); + if (!Controls) continue; + result.push(); + } + return result.length > 0 ? <>{result} : null; + } +} + +export class PDBeLigandViewStructureTools extends PluginUIComponent { + render() { + return <> +
Structure Tools
+ + + + + ; + } +} + +export class PDBeSuperpositionStructureTools extends PluginUIComponent { + render() { + return <> +
Structure Tools
+ + + + + + + + ; + } +} \ No newline at end of file diff --git a/frontend/venome-molstar/src/app/ui/pdbe-viewport-controls.tsx b/frontend/venome-molstar/src/app/ui/pdbe-viewport-controls.tsx new file mode 100644 index 00000000..5d9f9c91 --- /dev/null +++ b/frontend/venome-molstar/src/app/ui/pdbe-viewport-controls.tsx @@ -0,0 +1,40 @@ +import { ViewportControls } from 'molstar/lib/mol-plugin-ui/viewport'; +import { PluginCustomState } from '../plugin-custom-state'; + + +export class PDBeViewportControls extends ViewportControls { + private isBlack(): boolean { + const bgColor = PluginCustomState(this.plugin).initParams?.bgColor; + return bgColor !== undefined && bgColor.r === 0 && bgColor.g === 0 && bgColor.b === 0; + } + + render() { + const initParams = PluginCustomState(this.plugin).initParams; + const showPDBeLink = initParams?.moleculeId && initParams?.pdbeLink && !initParams?.superposition; + const pdbeLinkColor = this.isBlack() ? '#fff' : '#555'; + const pdbeLink = { + parentStyle: { width: 'auto' }, + bgStyle: { position: 'absolute', height: '27px', width: '54px', marginLeft: '-33px' }, + containerStyle: { position: 'absolute', right: '10px', top: '10px', padding: '3px 3px 3px 18px' }, + style: { display: 'inline-block', fontSize: '14px', color: pdbeLinkColor, borderBottom: 'none', cursor: 'pointer', textDecoration: 'none', position: 'absolute', right: '5px' }, + pdbeImg: { + src: 'https://www.ebi.ac.uk/pdbe/entry/static/images/logos/PDBe/logo_T_64.png', + alt: 'PDBe logo', + style: { height: '12px', width: '12px', border: 0, position: 'absolute', margin: '4px 0 0 -13px' } + } + } as const; + + return <> + {showPDBeLink &&
+ } +
+ {super.render()} +
+ ; + } +} \ No newline at end of file diff --git a/frontend/venome-molstar/src/app/ui/segment-tree.tsx b/frontend/venome-molstar/src/app/ui/segment-tree.tsx new file mode 100644 index 00000000..03e03d72 --- /dev/null +++ b/frontend/venome-molstar/src/app/ui/segment-tree.tsx @@ -0,0 +1,785 @@ +import { Mat4 } from 'molstar/lib/mol-math/linear-algebra'; +import { StructureComponentRef, StructureRepresentationRef } from 'molstar/lib/mol-plugin-state/manager/structure/hierarchy-state'; +import { PluginStateObject } from 'molstar/lib/mol-plugin-state/objects'; +import { StateTransforms } from 'molstar/lib/mol-plugin-state/transforms'; +import { PluginUIComponent, PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { ActionMenu } from 'molstar/lib/mol-plugin-ui/controls/action-menu'; +import { Button, ExpandGroup, IconButton, SectionHeader } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { ArrowDropDownSvg, ArrowRightSvg, CheckSvg, CloseSvg, VisibilityOffOutlinedSvg, VisibilityOutlinedSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { UpdateTransformControl } from 'molstar/lib/mol-plugin-ui/state/update-transform'; +import { PluginCommands } from 'molstar/lib/mol-plugin/commands'; +import { MolScriptBuilder as MS } from 'molstar/lib/mol-script/language/builder'; +import { State, StateObjectRef, StateSelection } from 'molstar/lib/mol-state'; +import { Color } from 'molstar/lib/mol-util/color'; +import { ColorLists } from 'molstar/lib/mol-util/color/lists'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import * as React from 'react'; +import { Subject } from 'rxjs'; +import { debounceTime, filter } from 'rxjs/operators'; +import { ClusterMember, PluginCustomState, Segment } from '../plugin-custom-state'; +import { renderSuperposition, superposeAf } from '../superposition'; + + +const SuperpositionTag = 'SuperpositionTransform'; + +export class SegmentTree extends PurePluginUIComponent<{}, { segment?: any, isBusy: boolean }> { + + componentDidMount() { + this.subscribe(PluginCustomState(this.plugin).events!.superpositionInit, () => { + const customState = this.customState; + if (customState && !customState.superpositionError) { + this.getSegmentParams(); + } + this.forceUpdate(); + }); + + this.subscribe(PluginCustomState(this.plugin).events!.isBusy, (e: boolean) => { + this.setState({ isBusy: e }); + if (e) { + PluginCommands.Toast.Show(this.plugin, { + title: 'Process', + message: 'Loading / computing large dataset!', + key: 'is-busy-toast' + }); + } else { + PluginCommands.Toast.Hide(this.plugin, { key: 'is-busy-toast' }); + } + }); + + this.subscribe(this.plugin.behaviors.layout.leftPanelTabName, (e: string) => { + if (e !== 'segments') return; + this.getSegmentParams(); + this.forceUpdate(); + }); + } + + get customState() { + return PluginCustomState(this.plugin); + } + + getSegmentParams = () => { + const customState = this.customState; + if (!customState.superpositionState || !customState.superpositionState.segmentData) return; + + const segmentData: Segment[] = customState.superpositionState.segmentData; + + const segmentArr: [string, string][] = segmentData.map((segment, i: number) => { + const segmentLabel = `${i + 1} ( ${segment.segment_start} - ${segment.segment_end} )`; + return [segmentLabel, segmentLabel]; + }); + + const segmentOptions = { + segment: PD.Select('', segmentArr, { label: 'Select Segment', description: 'Select segment to view its clusters below' }) + }; + + const segmentIndex = customState.superpositionState.activeSegment - 1; + this.setState({ + segment: { + params: segmentOptions, + value: { segment: segmentArr[segmentIndex][0] } + } + }); + this.setState({ isBusy: false }); + }; + + updateSegment = async (val: any) => { + if (!this.state.segment) return; + if (!this.state.segment) return; + const customState = this.customState; + if (!customState.superpositionState) throw new Error('customState.superpositionState has not been initialized'); + customState.events?.isBusy.next(true); + + // Hide pervious segement structures + this.hideStructures(customState.superpositionState.activeSegment - 1); + + // Set current segment params + const updatedParams = { ...this.state.segment as any }; + updatedParams.value = val; + this.setState({ segment: updatedParams }); + + setTimeout(async () => { + const updatedSegmentIndex = parseInt(val.segment.split(' ')[0]); + customState.superpositionState!.activeSegment = updatedSegmentIndex; + + // Display current segment visible structures + await this.displayStructures(customState.superpositionState!.activeSegment - 1); + customState.events?.isBusy.next(false); + customState.events?.segmentUpdate.next(true); + }, 100); + return false; + }; + + hideStructures = (segmentIndex: number) => { + // clear selections + this.plugin.managers.interactivity.lociSelects.deselectAll(); + + // clear Focus + this.plugin.managers.structure.focus.clear(); + + // remove measurements + const measurements: any = this.plugin.managers.structure.measurement.state; + const measureTypes = ['labels', 'distances', 'angles', 'dihedrals']; + let measurementCell: any = void 0; + measureTypes.forEach((type: string) => { + if (measurementCell) return; + if (measurements[type][0]) { + measurementCell = this.plugin.state.data.cells.get(measurements[type][0].transform.parent)!; + } + }); + if (measurementCell) { + PluginCommands.State.RemoveObject(this.plugin, { state: measurementCell.parent!, ref: measurementCell.transform.parent, removeParentGhosts: true }); + } + + // hide structures + const customState = this.customState; + if (!customState.superpositionState) throw new Error('customState.superpositionState has not been initialized'); + customState.superpositionState.visibleRefs[segmentIndex] = []; + for (const struct of customState.superpositionState.loadedStructs[segmentIndex]) { + const structRef = customState.superpositionState.models[struct]; + if (structRef) { + const structHierarchy: any = this.plugin.managers.structure.hierarchy.current.refs.get(structRef); + if (structHierarchy && structHierarchy.components) { + for (const c of structHierarchy.components) { + if (c && c.cell && !c.cell.state.isHidden) { + customState.superpositionState.visibleRefs[segmentIndex].push(c.cell.transform.ref); + PluginCommands.State.ToggleVisibility(this.plugin, { state: c.cell.parent!, ref: c.cell.transform.ref }); + } + } + } + } + } + + if (customState.superpositionState.alphafold.ref) { + const afStr: any = this.plugin.managers.structure.hierarchy.current.refs.get(customState.superpositionState.alphafold.ref); + if (afStr && afStr.components) { + for (const c of afStr.components) { + if (c && c.cell && !c.cell.state.isHidden) { + PluginCommands.State.ToggleVisibility(this.plugin, { state: c.cell.parent!, ref: c.cell.transform.ref }); + } + } + } + } + }; + + displayStructures = async (segmentIndex: number) => { + const customState = this.customState; + const spState = customState.superpositionState; + if (!spState) throw new Error('customState.superpositionState has not been initialized'); + if (spState.visibleRefs[segmentIndex].length === 0) { + const loadStrs: any = []; + spState.segmentData?.[segmentIndex].clusters.forEach(cluster => { + + let entryList = [cluster[0]]; + if (customState.initParams?.superpositionParams?.superposeAll) { + entryList = cluster; + } + + entryList.forEach((str: ClusterMember) => { + + const structStateId = `${str.pdb_id}_${str.struct_asym_id}`; + const structRef = spState.models[structStateId]; + if (structRef) { + const cell = this.plugin.state.data.cells.get(structRef)!; + const isHidden = cell.state.isHidden ? true : false; + if (isHidden) { + PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent!, ref: structRef }); + // PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent!, ref: cell.transform.parent }); + } + } else { + loadStrs.push(str); + } + }); + }); + PluginCommands.Camera.Reset(this.plugin); + + if (loadStrs.length > 0) { + await renderSuperposition(this.plugin, segmentIndex, loadStrs); + PluginCommands.Camera.Reset(this.plugin); + } + + } else { + for (const ref of spState.visibleRefs[segmentIndex]) { + const cell = this.plugin.state.data.cells.get(ref)!; + if (cell && cell.state.isHidden) { + PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent!, ref }); + } + } + PluginCommands.Camera.Reset(this.plugin); + } + + if (spState.alphafold.ref) { + superposeAf(this.plugin, spState.alphafold.traceOnly); + PluginCommands.Camera.Reset(this.plugin); + } + + if (spState.alphafold.ref && spState.alphafold.visibility[segmentIndex]) { + const afStr: any = this.plugin.managers.structure.hierarchy.current.refs.get(spState.alphafold.ref); + if (afStr && afStr.components) { + for (const c of afStr.components) { + if (c && c.cell && c.cell.state.isHidden) { + PluginCommands.State.ToggleVisibility(this.plugin, { state: c.cell.parent!, ref: c.cell.transform.ref }); + } + } + } + } + }; + + async transform(s: StateObjectRef, matrix: Mat4) { + const r = StateObjectRef.resolveAndCheck(this.plugin.state.data, s); + if (!r) return; + // TODO should find any TransformStructureConformation decorator instance + const o = StateSelection.findTagInSubtree(this.plugin.state.data.tree, r.transform.ref, SuperpositionTag); + + const params = { + transform: { + name: 'matrix' as const, + params: { data: matrix, transpose: false } + } + }; + // TODO add .insertOrUpdate to StateBuilder? + const b = o + ? this.plugin.state.data.build().to(o).update(params) + : this.plugin.state.data.build().to(s) + .insert(StateTransforms.Model.TransformStructureConformation, params, { tags: SuperpositionTag }); + await this.plugin.runTask(this.plugin.state.data.updateTree(b)); + } + + render() { + let sectionHeader = ; + const customState = this.customState; + if (customState && customState.initParams && !customState.initParams.superposition) { + return <> + {sectionHeader} +
Functionality unavailable!
+ ; + } else { + if (customState && customState.initParams && customState.initParams.superposition) { + + sectionHeader = ; + + if (customState.superpositionError) { + return <> + {sectionHeader} +
{customState.superpositionError}
+ ; + } else if (!customState.superpositionState || !customState.superpositionState.segmentData) { + return <> + {sectionHeader} +
Loading Segment Data!
+ ; + } + } + } + + if (this.state) { + const segmentIndex = parseInt(this.state.segment.value.segment.split(' ')[0]) - 1; + if (!customState.superpositionState?.segmentData) throw new Error('customState.superpositionState.segmentData has not been initialized'); + const segmentData: Segment[] = customState.superpositionState.segmentData; + const fullSegmentRange = `( ${segmentData[0].segment_start} - ${segmentData[segmentData.length - 1].segment_end} )`; + sectionHeader = ; + return <> + {sectionHeader} + + {segmentData[segmentIndex].clusters.map((c: any[], i: number) => )} + ; + } + + return <>; + + } +} + +class ClusterNode extends PluginUIComponent<{ cluster: any[], totalClusters: number, segmentIndex: number, clusterIndex: number }, { isCollapsed: boolean, showAll: boolean, showNone: boolean, showSearch: boolean, isBusy: boolean, searchText: string, cluster: any[] }> { + + state = { + isCollapsed: false, + showAll: false, + showNone: false, + showSearch: false, + isBusy: false, + cluster: this.props.cluster, + searchText: '' + }; + + private inputStream = new Subject(); + private handleInputStream = (inputStr: string) => { + this.setState({ searchText: inputStr }); + const filteredRes = this.props.cluster.filter((item) => { + return item.pdb_id.toLowerCase().indexOf(inputStr.toLowerCase()) >= 0; + }); + this.setState({ cluster: filteredRes }); + }; + + componentDidMount() { + this.subscribe(PluginCustomState(this.plugin).events!.isBusy, (e: boolean) => { + this.setState({ isBusy: e, showAll: false, showNone: false }); + }); + this.subscribe(this.inputStream.pipe(debounceTime(1000 / 24)), (e: any) => this.handleInputStream(e)); + } + + get customState() { + return PluginCustomState(this.plugin); + } + + toggleExpanded = (e: React.MouseEvent) => { + e.preventDefault(); + this.setState({ isCollapsed: !this.state.isCollapsed }); + e.currentTarget.blur(); + }; + + selectAll = (e: React.MouseEvent) => { + e.preventDefault(); + this.setState({ showAll: !this.state.showAll, showNone: false }); + e.currentTarget.blur(); + }; + + selectNone = (e: React.MouseEvent) => { + e.preventDefault(); + this.setState({ showAll: false, showNone: !this.state.showNone }); + e.currentTarget.blur(); + }; + + applyAction = async (e: React.MouseEvent) => { + e.preventDefault(); + e.currentTarget.blur(); + const customState = this.customState; + customState.events?.isBusy.next(true); + const currentState = { ...this.state }; + this.setState({ showAll: false, showNone: false }); + setTimeout(async () => { + const loadStrs: any = []; + for await (const str of this.state.cluster) { + const structStateId = `${str.pdb_id}_${str.struct_asym_id}`; + let structRef = undefined; + if (customState && customState.superpositionState && customState.superpositionState.models[structStateId]) { + structRef = customState.superpositionState.models[structStateId]; + } + + if (structRef) { + + const cell = this.plugin.state.data.cells.get(structRef)!; + if (cell) { + const isHidden = cell.state.isHidden ? true : false; + if ((isHidden && currentState.showAll) || (!isHidden && currentState.showNone)) { + await PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent!, ref: structRef }); + // await PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent!, ref: cell.transform.parent }); + } + } + } else { + if (currentState.showAll) loadStrs.push(str); + } + }; + PluginCommands.Camera.Reset(this.plugin); + if (loadStrs.length > 0) { + await renderSuperposition(this.plugin, this.props.segmentIndex, loadStrs); + } + customState.events?.isBusy.next(false); + }); + }; + + cancelAction = (e: React.MouseEvent) => { + e.preventDefault(); + this.setState({ showAll: false, showNone: false }); + e.currentTarget.blur(); + }; + + clearSearch = (e: React.MouseEvent) => { + e.preventDefault(); + this.setState({ searchText: '' }); + this.inputStream.next(''); + e.currentTarget.blur(); + }; + + render() { + const customState = this.customState; + if (!customState.superpositionState || !customState.superpositionState.segmentData) return <>; + const expand = ; + const title = `Segment ${customState.superpositionState.activeSegment} Cluster ${this.props.clusterIndex + 1}`; + const label = ; + + const selectionControls = <> + + + ; + + const mainRow =
+ {expand} + {label} + {this.props.cluster.length > 1 && selectionControls} +
; + + const searchControls =
+
+ Search PDB ID +
+ this.inputStream.next(e.target.value)} value={this.state.searchText} maxLength={4} /> +
+
+ +
; + + return <> + {mainRow} + {(this.state.showAll || this.state.showNone) &&
+
+ {this.state.showAll ? 'Display' : 'Hide'} {this.state.cluster.length < this.props.cluster.length ? `${this.state.cluster.length} / ` : 'all '}{this.props.cluster.length} chains + + +
+
+ } + {(!this.state.isCollapsed && this.props.cluster.length > 5) && searchControls} + {!this.state.isCollapsed &&
1) ? '330px' : '87%', overflowY: 'auto' }}> + {this.state.cluster.map((s: any, i: number) => )} +
+ } + ; + } + +} + +class StructureNode extends PluginUIComponent<{ structure: any, isRep: boolean, segmentIndex: number }, { showControls: boolean, isBusy: boolean, isProcessing: boolean, isHidden: boolean }> { + + state = { + showControls: false, + isBusy: false, + isProcessing: false, + isHidden: true, + }; + + get customState() { + return PluginCustomState(this.plugin); + } + + get ref() { + if (this.customState && this.customState.superpositionState && this.customState.superpositionState.models[`${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`]) { + return this.customState.superpositionState.models[`${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`]; + } else { + return undefined; + } + } + + get modelCell() { + if (this.ref) { + return this.plugin.state.data.cells.get(this.ref); + } else { + return undefined; + } + } + + get isAllHidden() { + let isHidden = true; + if (this.ref) { + const structHierarchy: any = this.plugin.managers.structure.hierarchy.current.refs.get(this.ref!); + if (structHierarchy && structHierarchy.components) { + for (const c of structHierarchy.components) { + if (c && c.cell && !c.cell.state.isHidden) { + isHidden = false; + break; + } + } + } else { + isHidden = false; + } + } + return isHidden; + } + + checkRelation(ref: string) { + let isRelated = false; + const cell = this.plugin.state.data.cells.get(ref)!; + if (cell && cell.transform.parent) { + if (cell && cell.transform.parent === this.ref) { + isRelated = true; + } else { + const pcell = this.plugin.state.data.cells.get(cell.transform.parent)!; + if (pcell && pcell.transform.parent === this.ref) isRelated = true; + } + } else { + const currentNodeCell = this.plugin.state.data.cells.get(this.ref!)!; + if (currentNodeCell && currentNodeCell.transform.parent === cell.transform.parent) { + isRelated = true; + } + } + return isRelated; + } + + is(e: State.ObjectEvent) { + + if (!this.ref) return false; + let isRelated = false; + if (this.ref && e.ref !== this.ref) { + isRelated = this.checkRelation(e.ref); + } + if (e.ref === this.ref || isRelated) { + return true; + } else { + const id = `${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`; + const invalidStruct = this.customState.superpositionState?.invalidStruct.includes(id) ?? false; + return invalidStruct; + } + } + + componentDidMount() { + this.setState({ isHidden: this.isAllHidden }); + this.subscribe(PluginCustomState(this.plugin).events!.isBusy, (e: boolean) => { + this.setState({ isBusy: e, showControls: false }); + }); + this.subscribe(this.plugin.state.events.cell.stateUpdated.pipe(filter(e => this.is(e)), debounceTime(33)), e => { + this.setState({ isHidden: this.isAllHidden }); + // this.forceUpdate(); + }); + } + + toggleVisible = async (e: React.MouseEvent) => { + e.preventDefault(); + e.currentTarget.blur(); + this.setState({ isProcessing: true, showControls: false }); + if (this.ref) { + + const structHierarchy: any = this.plugin.managers.structure.hierarchy.current.refs.get(this.ref!); + if (structHierarchy && structHierarchy.components) { + for (const c of structHierarchy.components) { + const currentHiddenState = c.cell.state.isHidden ? true : false; + if (currentHiddenState === this.state.isHidden) { + PluginCommands.State.ToggleVisibility(this.plugin, { state: c.cell.parent!, ref: c.cell.transform.ref }); + } + } + this.setState({ isHidden: !this.state.isHidden }); + } + + } else { + await renderSuperposition(this.plugin, this.props.segmentIndex, [this.props.structure]); + } + this.setState({ isProcessing: false }); + PluginCommands.Camera.Reset(this.plugin); + }; + + selectAction: ActionMenu.OnSelect = item => { + if (!item) return; + this.setState({ showControls: false }); + (item?.value as any)(); + }; + + getTagRefs(tags: string[]) { + const TagSet: Set = new Set(tags); + const tree = this.plugin.state.data.tree; + return StateSelection.findUniqueTagsInSubtree(tree, this.modelCell!.transform.ref, TagSet); + }; + + getRandomColor() { + const clList: any = ColorLists; + const spState = PluginCustomState(this.plugin).superpositionState; + if (!spState) throw new Error('customState.superpositionState has not been initialized'); + let palleteIndex = spState.colorState[this.props.segmentIndex].palleteIndex; + let colorIndex = spState.colorState[this.props.segmentIndex].colorIndex; + if (clList[spState.colorPalette[palleteIndex]].list[colorIndex + 1]) { + colorIndex += 1; + } else { + colorIndex = 0; + palleteIndex = spState.colorPalette[palleteIndex + 1] ? palleteIndex + 1 : 0; + } + const palleteName = spState.colorPalette[palleteIndex]; + spState.colorState[this.props.segmentIndex].palleteIndex = palleteIndex; + spState.colorState[this.props.segmentIndex].colorIndex = colorIndex; + return clList[palleteName].list[colorIndex]; + } + + async addChainRepr() { + const uniformColor1 = this.getRandomColor(); + const strInstance = this.plugin.state.data.select(this.ref!)[0]; + const query = MS.struct.generator.atomGroups({ + 'chain-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_asym_id(), this.props.structure.struct_asym_id]) + }); + const chainSel = await this.plugin.builders.structure.tryCreateComponentFromExpression(strInstance, query, `Chain-${this.props.segmentIndex}`, { label: `Chain`, tags: [`superposition-sel`] }); + if (chainSel) { + await this.plugin.builders.structure.representation.addRepresentation(chainSel, { type: 'cartoon', color: 'uniform', colorParams: { value: uniformColor1 } }, { tag: `superposition-visual` }); + } + } + + updates() { + const structHierarchy: any = this.plugin.managers.structure.hierarchy.current.refs.get(this.ref!); + if (structHierarchy && structHierarchy.components) { + const representations: any = []; + let showAddChainBtn = true; + structHierarchy.components.forEach((comps: any) => { + const gKeys = comps.key!.split(','); + const cId1Arr = gKeys[0].split('-'); + if (cId1Arr[2] === 'Chain') showAddChainBtn = false; + + if (comps.representations) { + comps.representations.forEach((repr: any) => { + representations.push(repr); + }); + } + }); + + const customState = PluginCustomState(this.plugin); + if (customState.initParams?.superpositionParams && !customState.initParams.superpositionParams.ligandView) { + showAddChainBtn = false; + } + + if (representations.length > 0) { + return
+ {representations.length > 0 && representations.map((r: any, i: number) => )} + {showAddChainBtn &&
+ +
} +
; + } + } + return <>; + } + + highlight = (e: React.MouseEvent) => { + e.preventDefault(); + if (this.ref) { + const cell = this.plugin.state.data.cells.get(this.ref)!; + PluginCommands.Interactivity.Object.Highlight(this.plugin, { state: cell.parent!, ref: this.ref }); + } + e.currentTarget.blur(); + }; + + clearHighlight = (e: React.MouseEvent) => { + e.preventDefault(); + PluginCommands.Interactivity.ClearHighlights(this.plugin); + e.currentTarget.blur(); + }; + + toggleControls = (e: React.MouseEvent) => { + e.preventDefault(); + this.setState({ showControls: !this.state.showControls }); + e.currentTarget.blur(); + }; + + getSubtitle() { + if (!this.customState.superpositionState) throw new Error('customState.superpositionState has not been initialized'); + const hetList = this.customState.superpositionState.hets[`${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`]; + let subtitle: string | undefined; + if (hetList) { + const hetLimit = this.props.structure.is_representative ? 1 : 4; + const totalHets = hetList.length; + let hetStr = hetList.join(', '); + if (totalHets > hetLimit) { + hetStr = hetList.slice(0, hetLimit).join(', '); + hetStr += ` + ${totalHets - hetLimit}`; + } + subtitle = ` ( ${hetStr} )`; + if (this.props.structure.is_representative) subtitle = ` ${subtitle} ( Representative )`; + } else if (this.props.structure.is_representative) { + subtitle = ' ( Representative )'; + } + return subtitle; + } + + get panelColor() { + let panelColor = '#808080'; + if (!this.state.isHidden) { + if (this.modelCell) { + const refs = this.getTagRefs([`superposition-visual`, `superposition-ligand-visual`]); + const visualRef = refs[`superposition-ligand-visual`] ? refs[`superposition-ligand-visual`] : refs[`superposition-visual`] ? refs[`superposition-visual`] : undefined; + if (visualRef) { + const visualCell = this.plugin.state.data.cells.get(visualRef)!; + if (visualCell.params && visualCell.params!.values && visualCell.params!.values.colorTheme) { + const colorTheme = visualCell.params!.values!.colorTheme; + if (colorTheme.params && colorTheme.params.value) { + panelColor = `${Color.toStyle(colorTheme.params.value)}`; + } else if (colorTheme.params && colorTheme.params.palette) { + const colorList1 = colorTheme.params.palette.params.list.colors; + panelColor = `${Color.toStyle(colorList1[0])}`; + } else if (colorTheme.params && colorTheme.params.list) { + const colorList2 = colorTheme.params.list.colors; + panelColor = `${Color.toStyle(colorList2[0])}`; + } + } + } + } + } + return panelColor; + } + + render() { + const superpositionParams = this.customState.initParams!.superpositionParams; + const strutStateId = `${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`; + const invalidStruct = this.customState.superpositionState?.invalidStruct.includes(strutStateId); + const noMatrixStruct = this.customState.superpositionState?.noMatrixStruct.includes(strutStateId); + const subTitle = invalidStruct ? noMatrixStruct ? ` Matrix not available!` : ` No Ligand found!` : this.getSubtitle(); + + let strTitle = `${this.props.structure.pdb_id} chain ${this.props.structure.auth_asym_id}`; + if (superpositionParams && superpositionParams.ligandView) { + strTitle = `${this.props.structure.pdb_id} ${this.props.structure.struct_asym_id}`; + } + const label = ; + + const expand = ; + const visibility = ; + const row =
+ {!this.state.isHidden && expand} + {label} + {visibility} +
; + + return
+ {row} + {this.state.showControls && this.updates()} +
; + } + +} + +class StructureRepresentationEntry extends PurePluginUIComponent<{ group: StructureComponentRef[], representation: StructureRepresentationRef }> { + componentDidMount() { + this.subscribe(this.plugin.state.events.cell.stateUpdated, e => { + if (State.ObjectEvent.isCell(e, this.props.representation.cell)) this.forceUpdate(); + }); + } + + toggleVisible = (e: React.MouseEvent) => { + e.preventDefault(); + e.currentTarget.blur(); + const cell = this.props.representation.cell; + PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent!, ref: cell.transform.parent }); + }; + + render() { + const repr = this.props.representation.cell; + let label = repr.obj?.label; + if (repr.obj?.data.repr && repr.obj?.data.repr.label) { + let sourceLabel = (repr.obj?.data.repr.label.indexOf('[Focus]') >= 0) ? '[Focus]' : repr.obj?.data.repr.label; + const isLargeLabel = sourceLabel.length > 10 ? true : false; + sourceLabel = `${isLargeLabel ? `${sourceLabel.substring(0, 28)}...` : sourceLabel}`; + if (isLargeLabel) { + label = sourceLabel; + } else { + label = `${sourceLabel} ${(label && label.length < 21) ? ' - ' + label : ''}`; + } + } + if (repr.obj?.data.repr && repr.obj?.data.repr.label === 'Custom Selection') label = 'Custom Selection'; + return
+ {repr.parent && + + } + +
; + } +} \ No newline at end of file diff --git a/frontend/venome-molstar/src/app/ui/superposition-components.tsx b/frontend/venome-molstar/src/app/ui/superposition-components.tsx new file mode 100644 index 00000000..85ab67c1 --- /dev/null +++ b/frontend/venome-molstar/src/app/ui/superposition-components.tsx @@ -0,0 +1,498 @@ +import { StructureComponentRef, StructureRepresentationRef } from 'molstar/lib/mol-plugin-state/manager/structure/hierarchy-state'; +import { PluginCommands } from 'molstar/lib/mol-plugin/commands'; +import { State, StateTransformer } from 'molstar/lib/mol-state'; +import { ParamDefinition } from 'molstar/lib/mol-util/param-definition'; +import { CollapsableControls, CollapsableState, PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { Button, IconButton } from 'molstar/lib/mol-plugin-ui/controls/common'; +import { CubeOutlineSvg, VisibilityOffOutlinedSvg, VisibilityOutlinedSvg, MoreHorizSvg, CheckSvg, CloseSvg } from 'molstar/lib/mol-plugin-ui/controls/icons'; +import { ParameterControls } from 'molstar/lib/mol-plugin-ui/controls/parameters'; +import { StructureRepresentation3D } from 'molstar/lib/mol-plugin-state/transforms/representation'; +import { debounceTime } from 'rxjs/operators'; +import { Subject } from 'rxjs'; +import { PluginCustomState } from '../plugin-custom-state'; + +interface StructureComponentControlState extends CollapsableState { + isDisabled: boolean +} + +export class SuperpositionComponentControls extends CollapsableControls<{}, StructureComponentControlState> { + protected defaultState(): StructureComponentControlState { + return { + header: 'Components', + isCollapsed: false, + isDisabled: false, + brand: { accent: 'blue', svg: CubeOutlineSvg } + }; + } + + renderControls() { + return <> + + ; + } +} + +interface ComponentGroups { nonLigGroups: StructureComponentRef[][], ligGroups: StructureComponentRef[][], carbGroups: StructureComponentRef[][], alphafold: StructureComponentRef[][] } + +interface ComponentListControlsState { + segmentWatch: boolean, + ligSearchText: string, + carbSearchText: string, + componentGroups: ComponentGroups, + ligGroups: StructureComponentRef[][], + isLigCollapsed: boolean, + carbGroups: StructureComponentRef[][], + isCarbCollapsed: boolean, + isBusy: boolean +}; + +class ComponentListControls extends PurePluginUIComponent<{}, ComponentListControlsState> { + + state = { + segmentWatch: false, + ligSearchText: '', + carbSearchText: '', + componentGroups: { nonLigGroups: [], ligGroups: [], carbGroups: [], alphafold: [] }, + ligGroups: [], + isLigCollapsed: false, + carbGroups: [], + isCarbCollapsed: false, + isBusy: false + }; + + private ligInputStream = new Subject(); + private handleLigInputStream = (inputStr: string) => { + this.setState({ ligSearchText: inputStr }); + const filteredRes = this.state.componentGroups.ligGroups.filter((g: StructureComponentRef[]) => { + const gKeys = g[0].key!.split(','); + const cId1Arr = gKeys[0].split('-'); + return cId1Arr[2].toLowerCase().indexOf(inputStr.toLowerCase()) >= 0; + }); + this.setState({ ligGroups: filteredRes }); + }; + + private carbInputStream = new Subject(); + private handleCarbInputStream = (inputStr: string) => { + this.setState({ carbSearchText: inputStr }); + const filteredRes = this.state.componentGroups.carbGroups.filter((g: StructureComponentRef[]) => { + const gKeys = g[0].key!.split(','); + const cId1Arr = gKeys[0].split('-'); + cId1Arr.splice(0, 2); + cId1Arr.pop(); + return cId1Arr.join('-').toLowerCase().indexOf(inputStr.toLowerCase()) >= 0; + }); + this.setState({ carbGroups: filteredRes }); + }; + + componentDidMount() { + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, () => { + this.categoriseGroups(); + this.forceUpdate(); + }); + this.subscribe(this.plugin.behaviors.state.isBusy, v => { + this.setState({ isBusy: v }); + }); + } + + componentDidUpdate() { + const customState = PluginCustomState(this.plugin); + if (customState.events && !this.state.segmentWatch) { + this.setState({ segmentWatch: true }); + this.subscribe(customState.events.segmentUpdate, () => { + this.categoriseGroups(); + this.forceUpdate(); + }); + } + this.subscribe(this.ligInputStream.pipe(debounceTime(1000 / 24)), e => this.handleLigInputStream(e)); + this.subscribe(this.carbInputStream.pipe(debounceTime(1000 / 24)), e => this.handleCarbInputStream(e)); + } + + categoriseGroups() { + const componentGroupsVal: ComponentGroups = { nonLigGroups: [], ligGroups: [], carbGroups: [], alphafold: [] }; + const componentGroups = this.plugin.managers.structure.hierarchy.currentComponentGroups; + const customState = PluginCustomState(this.plugin); + componentGroups.forEach((g: StructureComponentRef[]) => { + const superpositionState = customState.superpositionState; + if (!superpositionState) throw new Error('customState.superpositionState has not been initialized'); + let isLigandView = false; + if (customState.initParams && customState.initParams.superpositionParams && customState.initParams.superpositionParams.ligandView) { + isLigandView = true; + } + + if (isLigandView) { + const gKeys = g[0].key!.split(','); + const cId1Arr = gKeys[0].split('-'); + if (gKeys.indexOf('superposition-focus-surr-sel') === -1) { + if (cId1Arr[cId1Arr.length - 1] !== (superpositionState.activeSegment - 1) + '') return; + if (gKeys.indexOf('superposition-ligand-sel') >= 0) { + componentGroupsVal.ligGroups.push(g); + } else if (gKeys.indexOf('superposition-carb-sel') >= 0) { + componentGroupsVal.carbGroups.push(g); + } else if (gKeys.indexOf('alphafold-chain') >= 0) { + componentGroupsVal.alphafold.push(g); + } else { + componentGroupsVal.nonLigGroups.push(g); + } + } else { + componentGroupsVal.nonLigGroups.push(g); + } + } else { + const gKeys = g[0].key!.split(','); + if (gKeys.indexOf('superposition-focus-surr-sel') >= 0 || gKeys.indexOf(`Chain-${superpositionState.activeSegment - 1}`) >= 0) { + componentGroupsVal.nonLigGroups.push(g); + } else if (gKeys.indexOf('alphafold-chain') >= 0) { + componentGroupsVal.alphafold.push(g); + } + } + }); + this.setState({ componentGroups: componentGroupsVal, ligGroups: componentGroupsVal.ligGroups, carbGroups: componentGroupsVal.carbGroups, ligSearchText: '', carbSearchText: '' }); + } + + toggleVisible = (e: React.MouseEvent, action: 'hide' | 'show', type: 'ligands' | 'carbohydrates') => { + e.preventDefault(); + e.currentTarget.blur(); + + const customState = PluginCustomState(this.plugin); + customState.events?.isBusy.next(true); + + const visualEntites = (type === 'ligands') ? this.state.ligGroups : this.state.carbGroups; + + setTimeout(async () => { + for await (const visualEntity of visualEntites) { + this.plugin.managers.structure.hierarchy.toggleVisibility(visualEntity, action); + }; + customState.events?.isBusy.next(false); + }); + + }; + + showHideAllControls = (type: 'ligands' | 'carbohydrates') => { + return <> + + + ; + }; + + clearLigSearch = (e: React.MouseEvent) => { + e.preventDefault(); + this.setState({ ligSearchText: '' }); + this.ligInputStream.next(''); + e.currentTarget.blur(); + }; + + clearCarbSearch = (e: React.MouseEvent) => { + e.preventDefault(); + this.setState({ carbSearchText: '' }); + this.carbInputStream.next(''); + e.currentTarget.blur(); + }; + + collapseSection = (e: React.MouseEvent, type: 'ligands' | 'carbohydrates') => { + e.preventDefault(); + e.currentTarget.blur(); + if (type === 'ligands') { + this.setState({ isLigCollapsed: !this.state.isLigCollapsed }); + } else { + this.setState({ isCarbCollapsed: !this.state.isCarbCollapsed }); + } + }; + + sectionHeader = (type: 'ligands' | 'carbohydrates') => { + const showHideAllControls = (type === 'ligands') ? this.showHideAllControls('ligands') : this.showHideAllControls('carbohydrates'); + const title = (type === 'ligands') ? 'Ligand' : 'Carbohydrates'; + const visibleVisuals = (type === 'ligands') ? this.state.ligGroups.length : this.state.carbGroups.length; + const totalVisuals = (type === 'ligands') ? this.state.componentGroups.ligGroups.length : this.state.componentGroups.carbGroups.length; + return
+ + {visibleVisuals > 1 && showHideAllControls} +
; + }; + + + + render() { + + const ligSearchControls =
+
+ Search Ligand +
+ this.ligInputStream.next(e.target.value)} value={this.state.ligSearchText} maxLength={3} /> +
+
+ +
; + + const carbSearchControls =
+
+ Search Carbohydrate +
+ this.carbInputStream.next(e.target.value)} value={this.state.carbSearchText} maxLength={3} /> +
+
+ +
; + + const ligSectionHeader = this.sectionHeader('ligands'); + const carbSectionHeader = this.sectionHeader('carbohydrates'); + + return <> + {(this.state.componentGroups.nonLigGroups.length > 0) &&
+ {this.state.componentGroups.nonLigGroups.map((g: any) => )} +
} + {(this.state.componentGroups.alphafold.length > 0) &&
+ {this.state.componentGroups.alphafold.map((g: any) => )} +
} + {(this.state.componentGroups.ligGroups.length > 0) && ligSectionHeader} + {(!this.state.isLigCollapsed && this.state.componentGroups.ligGroups.length > 5) && ligSearchControls} + {(this.state.componentGroups.ligGroups.length > 0) &&
+ {!this.state.isLigCollapsed && this.state.ligGroups.map((g: any) => )} +
} + {(this.state.componentGroups.carbGroups.length > 0) && carbSectionHeader} + {(!this.state.isCarbCollapsed && this.state.componentGroups.carbGroups.length > 5) && carbSearchControls} + {(this.state.componentGroups.carbGroups.length > 0) &&
+ {!this.state.isCarbCollapsed && this.state.carbGroups.map((g: any) => )} +
} + ; + } +} + +type StructureComponentEntryActions = 'action' | 'label' + +class StructureComponentGroup extends PurePluginUIComponent<{ group: StructureComponentRef[], boldHeader?: boolean, type?: string }, { action?: StructureComponentEntryActions, isHidden: boolean, isBusy: boolean }> { + state = { + action: void 0 as StructureComponentEntryActions | undefined, + isHidden: false, + isBusy: false + }; + + get pivot() { + return this.props.group[0]; + } + + checkAllHidden = async () => { + let allHidden = true; + for (const c of this.props.group) { + if (!c.cell.state.isHidden) { + allHidden = false; + break; + } + } + if (allHidden) this.setState({ isHidden: true }); + }; + + componentDidMount() { + this.checkAllHidden(); + this.subscribe(this.plugin.state.events.cell.stateUpdated, e => { + // if (State.ObjectEvent.isCell(e, this.pivot.cell)) this.forceUpdate(); + if (this.pivot.cell.obj?.label === e.cell.obj?.label) { + if (!e.cell.state.isHidden) { + this.setState({ isHidden: false }); + } else { + this.checkAllHidden(); + } + } + }); + + this.subscribe(this.plugin.behaviors.state.isBusy, v => { + this.setState({ isBusy: v }); + }); + + this.subscribe(PluginCustomState(this.plugin).events!.isBusy, (e: boolean) => { + this.setState({ isBusy: e }); + }); + } + + toggleVisible = (e: React.MouseEvent) => { + e.preventDefault(); + e.currentTarget.blur(); + this.plugin.managers.structure.component.toggleVisibility(this.props.group); + this.setState({ isHidden: !this.state.isHidden }); + if (this.props.type === 'alphafold') { + const spState = PluginCustomState(this.plugin).superpositionState; + if (!spState) throw new Error('customState.superpositionState has not been initialized'); + spState.alphafold.visibility[spState.activeSegment - 1] = this.state.isHidden; + } + }; + + toggleAction = () => this.setState({ action: this.state.action === 'action' ? void 0 : 'action' }); + + highlight = (e: React.MouseEvent) => { + e.preventDefault(); + if (!this.props.group[0].cell.parent) return; + PluginCommands.Interactivity.Object.Highlight(this.plugin, { state: this.props.group[0].cell.parent!, ref: this.props.group.map(c => c.cell.transform.ref) }); + }; + + clearHighlight = (e: React.MouseEvent) => { + e.preventDefault(); + PluginCommands.Interactivity.ClearHighlights(this.plugin); + }; + + focus = () => { + let allHidden = true; + for (const c of this.props.group) { + if (!c.cell.state.isHidden) { + allHidden = false; + break; + } + } + + if (allHidden) { + this.plugin.managers.structure.hierarchy.toggleVisibility(this.props.group, 'show'); + } + + this.plugin.managers.camera.focusSpheres(this.props.group, e => { + if (e.cell.state.isHidden) return; + return e.cell.obj?.data.boundary.sphere; + }); + }; + + render() { + const component = this.pivot; + const cell = component.cell; + const label = cell.obj?.label; + const labelEle = this.props.boldHeader ? {label} : label; + + return <> +
+ + + +
+ {this.state.action === 'action' &&
+
+ {component.representations.map(r => )} +
+
} + ; + } +} + +class StructureRepresentationEntry extends PurePluginUIComponent<{ group: StructureComponentRef[], representation: StructureRepresentationRef }, { isBusy: boolean, clusterVal?: any }> { + + state = { + isBusy: false, + clusterVal: { cluster: 'All' } + }; + + remove = () => this.plugin.managers.structure.component.removeRepresentations(this.props.group, this.props.representation); + toggleVisible = (e: React.MouseEvent) => { + e.preventDefault(); + e.currentTarget.blur(); + this.plugin.managers.structure.component.toggleVisibility(this.props.group, this.props.representation); + }; + + componentDidMount() { + this.subscribe(this.plugin.state.events.cell.stateUpdated, e => { + if (State.ObjectEvent.isCell(e, this.props.representation.cell)) this.forceUpdate(); + }); + this.subscribe(this.plugin.behaviors.state.isBusy, v => { + this.setState({ isBusy: v }); + }); + this.subscribe(PluginCustomState(this.plugin).events!.isBusy, (e: boolean) => { + this.setState({ isBusy: e }); + }); + } + + updateRepresentations(components: ReadonlyArray, pivot: StructureRepresentationRef, params: StateTransformer.Params) { + + if (components.length === 0) return Promise.resolve(); + const index = components[0].representations.indexOf(pivot); + if (index < 0) return Promise.resolve(); + + const superpositionState = PluginCustomState(this.plugin).superpositionState; + if (!superpositionState) throw new Error('customState.superpositionState has not been initialized'); + let filteredComps: any = []; + if (this.state.clusterVal.cluster !== 'All') { + if (!superpositionState.segmentData) throw new Error('customState.superpositionState.segmentData has not been initialized'); + const clusterData = superpositionState.segmentData[superpositionState.activeSegment - 1].clusters[parseInt(this.state.clusterVal.cluster) - 1]; + + filteredComps = clusterData.map((s: any) => { + return `${s.pdb_id}_${s.struct_asym_id}`; + }); + + if (filteredComps.length === 0) return; + + } + + const update = this.plugin.state.data.build(); + + for (const c of components) { + // TODO: is it ok to use just the index here? Could possible lead to ugly edge cases, but perhaps not worth the trouble to "fix". + const repr = c.representations[index]; + if (!repr) continue; + if (repr.cell.transform.transformer !== pivot.cell.transform.transformer) continue; + + if (this.state.clusterVal.cluster !== 'All') { + const rmIndex = filteredComps.indexOf(superpositionState.refMaps[repr.cell.transform.parent]); + if (rmIndex === -1) continue; + } + + const updatedParams = { + type: params.type ? params.type : repr.cell.params?.values.type, + colorTheme: params.colorTheme ? params.colorTheme : repr.cell.params?.values.colorTheme, + sizeTheme: params.sizeTheme ? params.sizeTheme : repr.cell.params?.values.sizeTheme + }; + + update.to(repr.cell).update(updatedParams); + } + + return update.commit({ canUndo: 'Update Representation' }); + } + + update = (params: any) => { + return this.updateRepresentations(this.props.group, this.props.representation, params); + }; + + selectCluster = (params: any) => { + this.setState({ clusterVal: { cluster: params.cluster } }); + }; + + render() { + const repr = this.props.representation.cell; + + const superpositionState = PluginCustomState(this.plugin).superpositionState; + const clusterSelectArr: any = [['All', 'All']]; + if (!superpositionState?.segmentData) throw new Error('customState.superpositionState.segmentData has not been initialized'); + superpositionState.segmentData[superpositionState.activeSegment - 1].clusters.forEach((c: any, i: number) => { + clusterSelectArr.push([(i + 1) + '', (i + 1) + '']); + }); + const clusterOptions = { + cluster: ParamDefinition.Select('All', clusterSelectArr, { label: 'Select Cluster' }) + }; + + let isSurrVisual = false; + let isAlphafold = false; + if (repr && repr.obj) { + const reprObj: any = repr.obj; + if (reprObj.tags && reprObj.tags.indexOf('superposition-focus-surr-repr') >= 0) isSurrVisual = true; + if (reprObj.tags && reprObj.tags.indexOf('af-superposition-visual') >= 0) isAlphafold = true; + } + + return
+ {repr.parent &&
+ {(clusterSelectArr.length > 2 && !isSurrVisual && !isAlphafold) &&
+ +
} +
+ +
+
+ +
+
+ +
+
} +
; + } +} \ No newline at end of file diff --git a/frontend/venome-molstar/src/app/ui/superposition-viewport.tsx b/frontend/venome-molstar/src/app/ui/superposition-viewport.tsx new file mode 100644 index 00000000..98240cb0 --- /dev/null +++ b/frontend/venome-molstar/src/app/ui/superposition-viewport.tsx @@ -0,0 +1,25 @@ +import { PluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { LociLabels, StateSnapshotViewportControls, SelectionViewportControls } from 'molstar/lib/mol-plugin-ui/controls'; +import { BackgroundTaskProgress } from 'molstar/lib/mol-plugin-ui/task'; +import { Toasts } from 'molstar/lib/mol-plugin-ui/toast'; +import { Viewport, ViewportControls } from 'molstar/lib/mol-plugin-ui/viewport'; + +export class SuperpostionViewport extends PluginUIComponent { + render() { + const VPControls = this.plugin.spec.components?.viewport?.controls || ViewportControls; + + return <> + +
+ +
+ + + +
+ + +
+ ; + } +} \ No newline at end of file diff --git a/frontend/venome-molstar/src/app/ui/symmetry-annotation-controls.tsx b/frontend/venome-molstar/src/app/ui/symmetry-annotation-controls.tsx new file mode 100644 index 00000000..d93ae450 --- /dev/null +++ b/frontend/venome-molstar/src/app/ui/symmetry-annotation-controls.tsx @@ -0,0 +1,250 @@ +import { AssemblySymmetry3D, getRCSBAssemblySymmetryConfig, tryCreateAssemblySymmetry } from 'molstar/lib/extensions/rcsb/assembly-symmetry/behavior'; +import { AssemblySymmetry, AssemblySymmetryDataProps, AssemblySymmetryDataProvider, AssemblySymmetryParams, AssemblySymmetryProps, AssemblySymmetryProvider } from 'molstar/lib/extensions/rcsb/assembly-symmetry/prop'; +import { StructureRef } from 'molstar/lib/mol-plugin-state/manager/structure/hierarchy-state'; +import { PurePluginUIComponent } from 'molstar/lib/mol-plugin-ui/base'; +import { PluginContext } from 'molstar/lib/mol-plugin/context'; +import { StateSelection } from 'molstar/lib/mol-state'; +import { Task } from 'molstar/lib/mol-task'; +import { UUID } from 'molstar/lib/mol-util'; +import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition'; +import { AnnotationRowControls } from './annotation-row-controls'; + + +type SymmetryParams = { + /** State of the visibility button */ + on: PD.BooleanParam, + /** Index of the currently selected symmetry (in case there a more symmetries for an assembly), regardless of whether visibility is on of off */ + symmetryIndex: PD.Select, + /** `true` if symmetry data have been retrieved but do not contain any non-trivial symmetry */ + noSymmetries: PD.BooleanParam, +} + +type SymmetryParamValues = PD.ValuesFor + +interface SymmetryControlsState { + params: SymmetryParams, + values: SymmetryParamValues, +} + +const DefaultSymmetryControlsState: SymmetryControlsState = { + params: { + on: PD.Boolean(false, { isHidden: true }), + symmetryIndex: PD.Select(0, [[0, 'Auto']]), + noSymmetries: PD.Boolean(false, { isHidden: true }), + }, + values: { + on: false, + symmetryIndex: 0, + noSymmetries: false, + }, +}; + + +/** UI controls for showing Assembly Symmetry annotations (a row within Annotations section) */ +export class SymmetryAnnotationControls extends PurePluginUIComponent<{}, SymmetryControlsState> { + state = DefaultSymmetryControlsState; + + currentStructureId: UUID | undefined = undefined; + + componentDidMount() { + // Reset state when the pivot structure changes + this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, c => { + const structureObj = c.structures[0]?.cell.obj; + const structureId = structureObj?.id; + if (structureId !== this.currentStructureId) { + this.currentStructureId = structureId; + this.syncParams(); + } + }); + // Synchronize params when AssemblySymmetry3D changes + this.subscribe(this.plugin.state.events.cell.stateUpdated, e => { + if (e.cell.transform.transformer === AssemblySymmetry3D) { + this.syncParams(); + } + }); + // Synchronize params when AssemblySymmetry3D is removed + this.subscribe(this.plugin.state.events.cell.removed, e => { + this.syncParams(); + }); + } + + /** Synchronize parameters and values in UI with real parameters currently applied in `AssemblySymmetryProvider` */ + syncParams() { + if (this.hasAssemblySymmetry3D()) { + const noSymmetries = this.noSymmetriesAvailable(); + const realParams = this.getRealParams(); + const realValues = this.getRealValues(); + const options = noSymmetries ? + [[0, 'None']] as const + : realParams.symmetryIndex.options.filter(([index, label]) => index >= 0); // Removing the 'off' option (having index -1) + const params = { + ...this.state.params, + symmetryIndex: PD.Select(0, options), + }; + const values = (realValues.symmetryIndex >= 0) ? { + on: true, + symmetryIndex: realValues.symmetryIndex, + noSymmetries: noSymmetries, + } : { + on: false, + symmetryIndex: this.state.values.symmetryIndex, + noSymmetries: noSymmetries, + }; + this.setState({ params, values }); + } else { + this.setState({ + params: DefaultSymmetryControlsState.params, + values: DefaultSymmetryControlsState.values, + }); + } + } + + /** Return `true` if symmetry data have been retrieved and do not contain any non-trivial symmetry. */ + noSymmetriesAvailable() { + const structure = this.getPivotStructure()?.cell.obj?.data; + const symmetryData = structure && AssemblySymmetryDataProvider.get(structure).value; + return symmetryData !== undefined && symmetryData.filter(sym => sym.symbol !== 'C1').length === 0; + } + + /** Get the first loaded structure, if any. */ + getPivotStructure(): StructureRef | undefined { + return getPivotStructure(this.plugin); + } + + /** Get parameters currently applied in `AssemblySymmetryProvider` */ + getRealParams(): AssemblySymmetryParams { + const structure = this.getPivotStructure()?.cell.obj?.data; + let params: AssemblySymmetryParams; + if (structure) { + params = AssemblySymmetryProvider.getParams(structure); + } else { + params = AssemblySymmetryProvider.defaultParams; + } + return params; + } + + /** Get parameter values currently applied in `AssemblySymmetryProvider` */ + getRealValues(): AssemblySymmetryProps { + const structure = this.getPivotStructure()?.cell.obj?.data; + if (structure) { + return AssemblySymmetryProvider.props(structure); + } else { + return { ...PD.getDefaultValues(AssemblySymmetryProvider.defaultParams), symmetryIndex: -1 }; + } + } + + /** Return `true` if an `AssemblySymmetry3D` node existing in the */ + hasAssemblySymmetry3D(): boolean { + const struct = this.getPivotStructure(); + const state = struct?.cell.parent; + return state !== undefined && !!StateSelection.findTagInSubtree(state.tree, struct!.cell.transform.ref, AssemblySymmetry.Tag.Representation); + } + + /** Run changes needed to set visibility on or off, and set UI accordingly */ + async apply(applied: boolean) { + if (applied) { + if (this.hasAssemblySymmetry3D()) { + await this.changeParamValues({ ...this.state.values, on: true }); + } else { + await this.initSymmetry(); + } + this.setState(old => ({ values: { ...old.values, on: true } })); + } else { + if (this.hasAssemblySymmetry3D()) { + await this.changeParamValues({ ...this.state.values, on: false }); + } else { + // no action needed + } + this.setState(old => ({ values: { ...old.values, on: false } })); + } + } + + /** Run changes needed to change parameter values, and set UI accordingly*/ + async changeParamValues(values: SymmetryParamValues) { + const struct = this.getPivotStructure(); + if (!struct) return; + const currValues = this.getRealValues(); + const newValues = { ...currValues, symmetryIndex: values.on ? values.symmetryIndex : -1 }; + + if (struct.properties) { + const b = this.plugin.state.data.build(); + b.to(struct.properties.cell).update(old => { + old.properties[AssemblySymmetryProvider.descriptor.name] = newValues; + }); + await b.commit(); + } else { + const pd = this.plugin.customStructureProperties.getParams(struct.cell.obj?.data); + const params = PD.getDefaultValues(pd); + params.properties[AssemblySymmetryProvider.descriptor.name] = newValues; + await this.plugin.builders.structure.insertStructureProperties(struct.cell, params); + } + if (!values.on) { // if values.on, parameters will be updated via subscription + this.setState({ values }); + } + } + + /** Try to retrieve symmetry data and create `AssemblySymmetry3D` representation */ + async initSymmetry(initialSymmetryIndex?: number) { + await Task.create('Initialize Assembly Symmetry', async ctx => { + const struct = this.getPivotStructure(); + const data = struct?.cell.obj?.data; + if (!data) return; + try { + const propCtx = { runtime: ctx, assetManager: this.plugin.managers.asset }; + + const config = getRCSBAssemblySymmetryConfig(this.plugin); + const symmetryDataProps: AssemblySymmetryDataProps = { + serverType: config.DefaultServerType, + serverUrl: config.DefaultServerUrl, + }; + await AssemblySymmetryDataProvider.attach(propCtx, data, symmetryDataProps); + + const assemblySymmetryData = AssemblySymmetryDataProvider.get(data).value; + const symmetryIndex = initialSymmetryIndex ?? (assemblySymmetryData ? AssemblySymmetry.firstNonC1(assemblySymmetryData) : -1); + const symmetryProps: AssemblySymmetryProps = { ...symmetryDataProps, symmetryIndex }; + await AssemblySymmetryProvider.attach(propCtx, data, symmetryProps); + } catch (e) { + this.plugin.log.error(`Assembly Symmetry: ${e}`); + return; + } + await tryCreateAssemblySymmetry(this.plugin, struct.cell); + }).run(); + } + + render() { + const shortTitle = 'Assembly Symmetry' + (this.state.values.noSymmetries ? ' [Not Available]' : ''); + const title = 'Assembly Symmetry' + (this.state.values.noSymmetries ? ' [Not Available]\nSymmetry information for this assembly is not available' : ''); + return <> + this.apply(applied)} + params={this.state.params} values={this.state.values} onChangeValues={v => this.changeParamValues(v)} /> + ; + } +} + + +class SymmetryAnnotationRowControls extends AnnotationRowControls { + renderOptions() { + if (this.props.values.noSymmetries) { + return
+
Symmetry information not available
+
; + } + return super.renderOptions(); + } +} + +/** Get the first loaded structure, if any. */ +function getPivotStructure(plugin: PluginContext): StructureRef | undefined { + return plugin.managers.structure.hierarchy.selection.structures[0]; +} + +export function isAssemblySymmetryAnnotationApplicable(plugin: PluginContext) { + const struct = getPivotStructure(plugin); + const isAssembly = struct?.cell.obj?.data?.units[0].conformation.operator.assembly !== undefined; + return isAssembly && AssemblySymmetry.isApplicable(struct?.cell.obj?.data); + // It would be nice to disable the default `AssemblySymmetry.isApplicable` behavior + // (i.e. hiding Assembly Symmetry controls for non-biological assemblies, e.g. 1smv assembly 3) + // by `AssemblySymmetry.isApplicable = struct => struct?.units[0].conformation.operator.assembly !== undefined;` + // But we cannot easily override the `fetch` function which calls the original `isApplicable`. +} diff --git a/frontend/venome-molstar/src/overlay.scss b/frontend/venome-molstar/src/overlay.scss new file mode 100644 index 00000000..d47fb070 --- /dev/null +++ b/frontend/venome-molstar/src/overlay.scss @@ -0,0 +1,46 @@ +.pdbemolstar-overlay { + z-index: 1000; + position: fixed; + top: 0px; + bottom: 0px; + left: 0px; + right: 0px; + display: flex; + justify-content: center; + align-items: center; + pointer-events: none; +} + +.pdbemolstar-overlay-box { + width: 25%; + height: 25%; +} + +svg.pdbe-animated-logo { + background-color: transparent; + width: 100%; + height: 100%; + opacity: 80%; + + .path-fg { + stroke-dasharray: 1812 250; + stroke-dashoffset: -250; + animation: dash linear normal infinite; + animation-duration: 5s; + animation-delay: 1s; + } + @keyframes dash { + 0% { + stroke-dashoffset: 1812; + } + 80% { + stroke-dashoffset: -250; + } + 100% { + stroke-dashoffset: -250; + } + } +} +.msp-plugin .msp-viewport-controls-buttons .msp-btn-link-toggle-off { + background: black !important; +} diff --git a/frontend/venome-molstar/src/web-component/index.js b/frontend/venome-molstar/src/web-component/index.js new file mode 100644 index 00000000..370a5173 --- /dev/null +++ b/frontend/venome-molstar/src/web-component/index.js @@ -0,0 +1,19 @@ +import { LitElement } from 'lit-element'; + +class PdbeMolstar extends LitElement { + connectedCallback() { + super.connectedCallback(); + this.viewerInstance = new PDBeMolstarPlugin(); + this.initParams = PDBeMolstarPlugin.initParamsFromHtmlAttributes(this); + console.log('PdbeMolstar initParams:', this.initParams); + this.viewerInstance.render(this, this.initParams); + } + + createRenderRoot() { + return this; + } +} + +export default PdbeMolstar; + +customElements.define('pdbe-molstar', PdbeMolstar); diff --git a/frontend/venome-molstar/tsconfig.json b/frontend/venome-molstar/tsconfig.json new file mode 100644 index 00000000..4c930ae1 --- /dev/null +++ b/frontend/venome-molstar/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "declaration": true, + "target": "ESNext", + "alwaysStrict": true, + "noImplicitAny": true, + "noImplicitThis": true, + "sourceMap": false, + "noUnusedLocals": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "module": "ESNext", + "esModuleInterop": true, + "moduleResolution": "node", + "importHelpers": true, + "noEmitHelpers": true, + "allowSyntheticDefaultImports": true, + "jsx": "react-jsx", + "lib": ["ESNext", "es6", "dom", "esnext.asynciterable", "es2016"], + "rootDir": "src/app", + "outDir": "lib", + "composite": true, // required if we want to set "tsBuildInfoFile" + "tsBuildInfoFile": "tsconfig.tsbuildinfo", // default setting would place this file out of the repo directory + "baseUrl": "./" + }, + "include": ["src/app"] +} diff --git a/frontend/venome-molstar/webpack.config.development.js b/frontend/venome-molstar/webpack.config.development.js new file mode 100644 index 00000000..d4c054a9 --- /dev/null +++ b/frontend/venome-molstar/webpack.config.development.js @@ -0,0 +1,21 @@ +const path = require('path'); + +const PACKAGE_ROOT_PATH = process.cwd(); +const PACKAGE = require(path.join(PACKAGE_ROOT_PATH, 'package.json')); + +function removeKey(obj, key) { + if (typeof obj !== 'object') return obj; + const result = { ...obj }; + delete result[key]; + return result; +} + +const productionConfig = require('./webpack.config.production.js'); + +const developmentConfig = productionConfig.map(conf => ({ + ...conf, + devtool: 'eval-source-map', + entry: removeKey(conf.entry, `${PACKAGE.name}-light`), // skip building pdbe-molstar-light in dev mode +})); + +module.exports = developmentConfig; diff --git a/frontend/venome-molstar/webpack.config.production.js b/frontend/venome-molstar/webpack.config.production.js new file mode 100644 index 00000000..b97d3b94 --- /dev/null +++ b/frontend/venome-molstar/webpack.config.production.js @@ -0,0 +1,140 @@ +const path = require("path"); +const webpack = require("webpack"); +const ExtraWatchWebpackPlugin = require("extra-watch-webpack-plugin"); +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); + +const PACKAGE_ROOT_PATH = process.cwd(); +const PACKAGE = require(path.join(PACKAGE_ROOT_PATH, "package.json")); + +/** Webpack configuration for building the plugin bundle (pdbe-molstar-plugin-*.js, pdbe-molstar-*.css). + * Also builds the light-skin version (pdbe-molstar-light-plugin-*.js, pdbe-molstar-light-*.css). */ +const molstarConfig = { + entry: { + [PACKAGE.name]: path.resolve(__dirname, "lib/index.js"), + [PACKAGE.name + "-light"]: path.resolve( + __dirname, + "lib/index(light).js" + ), + }, + output: { + filename: `[name]-plugin-${PACKAGE.version}.js`, + path: path.resolve(__dirname, "build/"), + }, + target: "web", + module: { + rules: [ + { + test: /\.(html|ico)$/, + use: [ + { + loader: "file-loader", + options: { name: "[name].[ext]" }, + }, + ], + }, + { + test: /\.(s*)css$/, + use: [ + MiniCssExtractPlugin.loader, + { loader: "css-loader", options: { sourceMap: false } }, + { loader: "sass-loader", options: { sourceMap: false } }, + ], + }, + ], + }, + plugins: [ + new ExtraWatchWebpackPlugin({ + files: ["./lib/**/*.scss", "./lib/**/*.html"], + }), + new webpack.DefinePlugin({ + "process.env.DEBUG": JSON.stringify(process.env.DEBUG), + __MOLSTAR_DEBUG_TIMESTAMP__: webpack.DefinePlugin.runtimeValue( + () => `${new Date().valueOf()}`, + true + ), + }), + new MiniCssExtractPlugin({ + filename: `[name]-${PACKAGE.version}.css`, + }), + ], + resolve: { + modules: ["node_modules", path.resolve(__dirname, "lib/")], + fallback: { + fs: false, + crypto: require.resolve("crypto-browserify"), + path: require.resolve("path-browserify"), + stream: require.resolve("stream-browserify"), + }, + alias: { + Molstar: "molstar/lib/lib", + }, + }, + watchOptions: { + aggregateTimeout: 750, + }, +}; + +/** Webpack configuration for building a part of the web-component bundle, + * which will be concatenated with the plugin bundle to build the full + * web-component bundle (pdbe-molstar-component-*.js) */ +const componentConfig = { + entry: path.resolve(__dirname, `src/web-component/index.js`), + output: { + filename: `${PACKAGE.name}-component-build-${PACKAGE.version}.js`, + path: path.resolve(__dirname, "lib/"), + }, + target: "web", + resolve: { + extensions: [".js"], + }, + externals: { + PDBeMolstarPlugin: "PDBeMolstarPlugin", + }, + module: { + rules: [ + { + test: /\.css$/, + use: [ + "style-loader", + { loader: "css-loader", options: { importLoaders: 1 } }, + ], + }, + { + test: /.(jpg|jpeg|png|svg)$/, + use: ["url-loader"], + }, + { + test: /\.(js)$/, + exclude: function excludeCondition(path) { + const nonEs5SyntaxPackages = ["lit-element", "lit-html"]; + + // DO transpile these packages + if (nonEs5SyntaxPackages.some((pkg) => path.match(pkg))) { + return false; + } + + // Ignore all other modules that are in node_modules + if (path.match(/node_modules\\/)) { + return true; + } else return false; + }, + use: { + loader: "babel-loader", + options: { + babelrc: false, + plugins: [ + [ + "@babel/plugin-transform-runtime", + { + regenerator: true, + }, + ], + ], + }, + }, + }, + ], + }, +}; + +module.exports = [molstarConfig, componentConfig];