From 1552fc28317af2d75209517f32ddee2c96b362c1 Mon Sep 17 00:00:00 2001 From: dkrohmer Date: Thu, 4 Jul 2024 11:23:40 +0200 Subject: [PATCH] first commit of full code base --- .editorconfig | 12 + .erb/configs/.eslintrc | 7 + .erb/configs/webpack.config.base.ts | 59 + .erb/configs/webpack.config.eslint.ts | 3 + .erb/configs/webpack.config.main.prod.ts | 83 + .erb/configs/webpack.config.preload.dev.ts | 71 + .../webpack.config.renderer.dev.dll.ts | 77 + .erb/configs/webpack.config.renderer.dev.ts | 256 + .erb/configs/webpack.config.renderer.prod.ts | 155 + .erb/configs/webpack.paths.ts | 38 + .erb/img/erb-banner.svg | 32 + .erb/img/erb-logo.png | Bin 0 -> 28783 bytes .erb/img/palette-sponsor-banner.svg | 6 + .erb/mocks/fileMock.js | 1 + .erb/scripts/.eslintrc | 8 + .erb/scripts/check-build-exists.ts | 24 + .erb/scripts/check-native-dep.js | 54 + .erb/scripts/check-node-env.js | 16 + .erb/scripts/check-port-in-use.js | 16 + .erb/scripts/clean.js | 13 + .erb/scripts/delete-source-maps.js | 15 + .erb/scripts/electron-rebuild.js | 20 + .erb/scripts/link-modules.ts | 9 + .erb/scripts/notarize.js | 32 + .eslintignore | 33 + .eslintrc.js | 34 + .gitattributes | 12 + .github/FUNDING.yml | 5 + .github/ISSUE_TEMPLATE/1-Bug_report.md | 67 + .github/ISSUE_TEMPLATE/2-Question.md | 19 + .github/ISSUE_TEMPLATE/3-Feature_request.md | 15 + .github/config.yml | 6 + .github/stale.yml | 17 + .github/workflows/codeql-analysis.yml | 72 + .github/workflows/publish.yml | 46 + .github/workflows/test.yml | 34 + .gitignore | 38 + .vscode/extensions.json | 3 + .vscode/launch.json | 30 + .vscode/settings.json | 30 + CHANGELOG.md | 5 + LICENSE | 661 + README.md | 61 + assets/assets.d.ts | 35 + assets/entitlements.mac.plist | 10 + assets/icon.icns | Bin 0 -> 103109 bytes assets/icon.ico | Bin 0 -> 109356 bytes assets/icon.png | Bin 0 -> 43481 bytes assets/icon.svg | 1 + assets/icons/1024x1024.png | Bin 0 -> 24937 bytes assets/icons/128x128.png | Bin 0 -> 2927 bytes assets/icons/16x16.png | Bin 0 -> 454 bytes assets/icons/256x256.png | Bin 0 -> 5914 bytes assets/icons/32x32.png | Bin 0 -> 956 bytes assets/icons/512x512.png | Bin 0 -> 12387 bytes assets/icons/64x64.png | Bin 0 -> 1603 bytes assets/logo.svg | 1 + assets/thumbnail.png | Bin 0 -> 7175 bytes package-lock.json | 18864 ++++++++++++++++ package.json | 286 + release/app/package-lock.json | 2841 +++ release/app/package.json | 25 + src/__tests__/App.test.tsx | 9 + src/global.d.ts | 23 + src/main/controllers/IncrementController.ts | 154 + src/main/controllers/ModelController.ts | 126 + src/main/controllers/ProductController.ts | 131 + src/main/controllers/VersionController.ts | 141 + src/main/database.ts | 61 + src/main/helpers/entityBuilder.ts | 104 + src/main/main.ts | 475 + src/main/menu.ts | 290 + src/main/models/Increment.ts | 47 + src/main/models/Model.ts | 45 + src/main/models/Product.ts | 59 + src/main/models/Responsible.ts | 33 + src/main/models/Setting.ts | 14 + src/main/models/Version.ts | 56 + src/main/preload.ts | 82 + src/main/repositories/IncrementRepository.ts | 72 + src/main/repositories/ModelRepository.ts | 56 + src/main/repositories/ProductRepository.ts | 58 + .../repositories/ResponsibleRepository.ts | 38 + src/main/repositories/SettingRepository.ts | 16 + src/main/repositories/VersionRepository.ts | 61 + src/main/services/IncrementService.ts | 60 + src/main/services/ModelService.ts | 48 + src/main/services/ProductService.ts | 99 + src/main/services/ResponsibleService.ts | 40 + src/main/services/SettingService.ts | 44 + src/main/services/VersionService.ts | 83 + src/main/util.ts | 13 + src/renderer/App.css | 62 + src/renderer/App.tsx | 88 + .../applets/model-editor/ModelEditor.css | 18 + .../applets/model-editor/ModelEditor.tsx | 260 + src/renderer/applets/model-editor/actions.tsx | 106 + .../model-editor/components/ActorModal.tsx | 93 + .../model-editor/components/DataflowModal.tsx | 150 + .../model-editor/components/Events.tsx | 276 + .../model-editor/components/ExportModal.tsx | 107 + .../model-editor/components/ImportModal.tsx | 241 + .../applets/model-editor/components/Keys.tsx | 281 + .../model-editor/components/Stencil.tsx | 72 + .../model-editor/components/SystemModal.tsx | 108 + .../model-editor/components/Toolbar.tsx | 337 + .../model-editor/components/ZoneModal.tsx | 129 + src/renderer/applets/model-editor/index.tsx | 14 + src/renderer/applets/model-editor/setup.tsx | 160 + .../applets/model-editor/shapes/actor.tsx | 128 + .../applets/model-editor/shapes/dataflow.tsx | 203 + .../applets/model-editor/shapes/system.tsx | 124 + .../applets/model-editor/shapes/zone.tsx | 84 + src/renderer/applets/model-editor/tools.tsx | 75 + src/renderer/components/Breadcrumbs.tsx | 10 + src/renderer/components/Footer.tsx | 61 + src/renderer/components/SideBar.tsx | 365 + src/renderer/components/ToastManager.tsx | 45 + src/renderer/components/TopBar.tsx | 47 + .../components/increments/Increment.tsx | 143 + .../components/increments/Increments.tsx | 191 + .../components/increments/IncrementsModal.tsx | 103 + src/renderer/components/models/Model.tsx | 198 + src/renderer/components/models/Models.tsx | 147 + .../components/models/ModelsModal.tsx | 131 + src/renderer/components/products/Product.tsx | 123 + src/renderer/components/products/Products.tsx | 428 + .../components/products/ProductsModal.tsx | 229 + src/renderer/index.css | 178 + src/renderer/index.ejs | 14 + src/renderer/index.tsx | 16 + src/renderer/interfaces/IIncrement.tsx | 20 + src/renderer/interfaces/IModel.tsx | 16 + src/renderer/interfaces/IProduct.tsx | 23 + src/renderer/interfaces/IResponsible.tsx | 13 + src/renderer/interfaces/IVersion.tsx | 17 + src/renderer/store/IncrementsStore.tsx | 216 + src/renderer/store/ModelEditorStore.tsx | 372 + src/renderer/store/ModelsStore.tsx | 200 + src/renderer/store/ProductsStore.tsx | 258 + src/renderer/store/SettingsStore.tsx | 83 + src/renderer/store/VersionsStore.tsx | 160 + src/renderer/store/index.tsx | 33 + src/renderer/utils.tsx | 16 + tsconfig.json | 20 + 145 files changed, 33788 insertions(+) create mode 100644 .editorconfig create mode 100644 .erb/configs/.eslintrc create mode 100644 .erb/configs/webpack.config.base.ts create mode 100644 .erb/configs/webpack.config.eslint.ts create mode 100644 .erb/configs/webpack.config.main.prod.ts create mode 100644 .erb/configs/webpack.config.preload.dev.ts create mode 100644 .erb/configs/webpack.config.renderer.dev.dll.ts create mode 100644 .erb/configs/webpack.config.renderer.dev.ts create mode 100644 .erb/configs/webpack.config.renderer.prod.ts create mode 100644 .erb/configs/webpack.paths.ts create mode 100644 .erb/img/erb-banner.svg create mode 100644 .erb/img/erb-logo.png create mode 100644 .erb/img/palette-sponsor-banner.svg create mode 100644 .erb/mocks/fileMock.js create mode 100644 .erb/scripts/.eslintrc create mode 100644 .erb/scripts/check-build-exists.ts create mode 100644 .erb/scripts/check-native-dep.js create mode 100644 .erb/scripts/check-node-env.js create mode 100644 .erb/scripts/check-port-in-use.js create mode 100644 .erb/scripts/clean.js create mode 100644 .erb/scripts/delete-source-maps.js create mode 100644 .erb/scripts/electron-rebuild.js create mode 100644 .erb/scripts/link-modules.ts create mode 100644 .erb/scripts/notarize.js create mode 100644 .eslintignore create mode 100644 .eslintrc.js create mode 100644 .gitattributes create mode 100644 .github/FUNDING.yml create mode 100644 .github/ISSUE_TEMPLATE/1-Bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/2-Question.md create mode 100644 .github/ISSUE_TEMPLATE/3-Feature_request.md create mode 100644 .github/config.yml create mode 100644 .github/stale.yml create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/test.yml create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 assets/assets.d.ts create mode 100644 assets/entitlements.mac.plist create mode 100644 assets/icon.icns create mode 100644 assets/icon.ico create mode 100644 assets/icon.png create mode 100644 assets/icon.svg create mode 100644 assets/icons/1024x1024.png create mode 100644 assets/icons/128x128.png create mode 100644 assets/icons/16x16.png create mode 100644 assets/icons/256x256.png create mode 100644 assets/icons/32x32.png create mode 100644 assets/icons/512x512.png create mode 100644 assets/icons/64x64.png create mode 100644 assets/logo.svg create mode 100644 assets/thumbnail.png create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 release/app/package-lock.json create mode 100644 release/app/package.json create mode 100644 src/__tests__/App.test.tsx create mode 100644 src/global.d.ts create mode 100644 src/main/controllers/IncrementController.ts create mode 100644 src/main/controllers/ModelController.ts create mode 100644 src/main/controllers/ProductController.ts create mode 100644 src/main/controllers/VersionController.ts create mode 100644 src/main/database.ts create mode 100644 src/main/helpers/entityBuilder.ts create mode 100644 src/main/main.ts create mode 100644 src/main/menu.ts create mode 100644 src/main/models/Increment.ts create mode 100644 src/main/models/Model.ts create mode 100644 src/main/models/Product.ts create mode 100644 src/main/models/Responsible.ts create mode 100644 src/main/models/Setting.ts create mode 100644 src/main/models/Version.ts create mode 100644 src/main/preload.ts create mode 100644 src/main/repositories/IncrementRepository.ts create mode 100644 src/main/repositories/ModelRepository.ts create mode 100644 src/main/repositories/ProductRepository.ts create mode 100644 src/main/repositories/ResponsibleRepository.ts create mode 100644 src/main/repositories/SettingRepository.ts create mode 100644 src/main/repositories/VersionRepository.ts create mode 100644 src/main/services/IncrementService.ts create mode 100644 src/main/services/ModelService.ts create mode 100644 src/main/services/ProductService.ts create mode 100644 src/main/services/ResponsibleService.ts create mode 100644 src/main/services/SettingService.ts create mode 100644 src/main/services/VersionService.ts create mode 100644 src/main/util.ts create mode 100644 src/renderer/App.css create mode 100644 src/renderer/App.tsx create mode 100644 src/renderer/applets/model-editor/ModelEditor.css create mode 100644 src/renderer/applets/model-editor/ModelEditor.tsx create mode 100644 src/renderer/applets/model-editor/actions.tsx create mode 100644 src/renderer/applets/model-editor/components/ActorModal.tsx create mode 100644 src/renderer/applets/model-editor/components/DataflowModal.tsx create mode 100644 src/renderer/applets/model-editor/components/Events.tsx create mode 100644 src/renderer/applets/model-editor/components/ExportModal.tsx create mode 100644 src/renderer/applets/model-editor/components/ImportModal.tsx create mode 100644 src/renderer/applets/model-editor/components/Keys.tsx create mode 100644 src/renderer/applets/model-editor/components/Stencil.tsx create mode 100644 src/renderer/applets/model-editor/components/SystemModal.tsx create mode 100644 src/renderer/applets/model-editor/components/Toolbar.tsx create mode 100644 src/renderer/applets/model-editor/components/ZoneModal.tsx create mode 100644 src/renderer/applets/model-editor/index.tsx create mode 100644 src/renderer/applets/model-editor/setup.tsx create mode 100644 src/renderer/applets/model-editor/shapes/actor.tsx create mode 100644 src/renderer/applets/model-editor/shapes/dataflow.tsx create mode 100644 src/renderer/applets/model-editor/shapes/system.tsx create mode 100644 src/renderer/applets/model-editor/shapes/zone.tsx create mode 100644 src/renderer/applets/model-editor/tools.tsx create mode 100644 src/renderer/components/Breadcrumbs.tsx create mode 100644 src/renderer/components/Footer.tsx create mode 100644 src/renderer/components/SideBar.tsx create mode 100644 src/renderer/components/ToastManager.tsx create mode 100644 src/renderer/components/TopBar.tsx create mode 100644 src/renderer/components/increments/Increment.tsx create mode 100644 src/renderer/components/increments/Increments.tsx create mode 100644 src/renderer/components/increments/IncrementsModal.tsx create mode 100644 src/renderer/components/models/Model.tsx create mode 100644 src/renderer/components/models/Models.tsx create mode 100644 src/renderer/components/models/ModelsModal.tsx create mode 100644 src/renderer/components/products/Product.tsx create mode 100644 src/renderer/components/products/Products.tsx create mode 100644 src/renderer/components/products/ProductsModal.tsx create mode 100644 src/renderer/index.css create mode 100644 src/renderer/index.ejs create mode 100644 src/renderer/index.tsx create mode 100644 src/renderer/interfaces/IIncrement.tsx create mode 100644 src/renderer/interfaces/IModel.tsx create mode 100644 src/renderer/interfaces/IProduct.tsx create mode 100644 src/renderer/interfaces/IResponsible.tsx create mode 100644 src/renderer/interfaces/IVersion.tsx create mode 100644 src/renderer/store/IncrementsStore.tsx create mode 100644 src/renderer/store/ModelEditorStore.tsx create mode 100644 src/renderer/store/ModelsStore.tsx create mode 100644 src/renderer/store/ProductsStore.tsx create mode 100644 src/renderer/store/SettingsStore.tsx create mode 100644 src/renderer/store/VersionsStore.tsx create mode 100644 src/renderer/store/index.tsx create mode 100644 src/renderer/utils.tsx create mode 100644 tsconfig.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4a7ea30 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.erb/configs/.eslintrc b/.erb/configs/.eslintrc new file mode 100644 index 0000000..89d242b --- /dev/null +++ b/.erb/configs/.eslintrc @@ -0,0 +1,7 @@ +{ + "rules": { + "no-console": "off", + "global-require": "off", + "import/no-dynamic-require": "off" + } +} diff --git a/.erb/configs/webpack.config.base.ts b/.erb/configs/webpack.config.base.ts new file mode 100644 index 0000000..0ef0044 --- /dev/null +++ b/.erb/configs/webpack.config.base.ts @@ -0,0 +1,59 @@ +/** + * Base webpack config used across other specific configs + */ + +import webpack from 'webpack'; +import TsconfigPathsPlugins from 'tsconfig-paths-webpack-plugin'; +import webpackPaths from './webpack.paths'; +import { dependencies as externals } from '../../release/app/package.json'; + +const configuration: webpack.Configuration = { + externals: [...Object.keys(externals || {})], + + stats: 'errors-only', + + module: { + rules: [ + { + test: /\.[jt]sx?$/, + exclude: /node_modules/, + use: { + loader: 'ts-loader', + options: { + // Remove this line to enable type checking in webpack builds + transpileOnly: true, + compilerOptions: { + module: 'esnext', + }, + }, + }, + }, + ], + }, + + output: { + path: webpackPaths.srcPath, + // https://github.com/webpack/webpack/issues/1114 + library: { + type: 'commonjs2', + }, + }, + + /** + * Determine the array of extensions that should be used to resolve modules. + */ + resolve: { + extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'], + modules: [webpackPaths.srcPath, 'node_modules'], + // There is no need to add aliases here, the paths in tsconfig get mirrored + plugins: [new TsconfigPathsPlugins()], + }, + + plugins: [ + new webpack.EnvironmentPlugin({ + NODE_ENV: 'production', + }), + ], +}; + +export default configuration; diff --git a/.erb/configs/webpack.config.eslint.ts b/.erb/configs/webpack.config.eslint.ts new file mode 100644 index 0000000..35a631b --- /dev/null +++ b/.erb/configs/webpack.config.eslint.ts @@ -0,0 +1,3 @@ +/* eslint import/no-unresolved: off, import/no-self-import: off */ + +module.exports = require('./webpack.config.renderer.dev').default; diff --git a/.erb/configs/webpack.config.main.prod.ts b/.erb/configs/webpack.config.main.prod.ts new file mode 100644 index 0000000..4727482 --- /dev/null +++ b/.erb/configs/webpack.config.main.prod.ts @@ -0,0 +1,83 @@ +/** + * Webpack config for production electron main process + */ + +import path from 'path'; +import webpack from 'webpack'; +import { merge } from 'webpack-merge'; +import TerserPlugin from 'terser-webpack-plugin'; +import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; +import baseConfig from './webpack.config.base'; +import webpackPaths from './webpack.paths'; +import checkNodeEnv from '../scripts/check-node-env'; +import deleteSourceMaps from '../scripts/delete-source-maps'; + +checkNodeEnv('production'); +deleteSourceMaps(); + +const configuration: webpack.Configuration = { + devtool: 'source-map', + + mode: 'production', + + target: 'electron-main', + + entry: { + main: path.join(webpackPaths.srcMainPath, 'main.ts'), + preload: path.join(webpackPaths.srcMainPath, 'preload.ts'), + }, + + output: { + path: webpackPaths.distMainPath, + filename: '[name].js', + library: { + type: 'umd', + }, + }, + + optimization: { + minimizer: [ + new TerserPlugin({ + parallel: true, + }), + ], + }, + + plugins: [ + new BundleAnalyzerPlugin({ + analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled', + analyzerPort: 8888, + }), + + /** + * Create global constants which can be configured at compile time. + * + * Useful for allowing different behaviour between development builds and + * release builds + * + * NODE_ENV should be production so that modules do not perform certain + * development checks + */ + new webpack.EnvironmentPlugin({ + NODE_ENV: 'production', + DEBUG_PROD: false, + START_MINIMIZED: false, + }), + + new webpack.DefinePlugin({ + 'process.type': '"browser"', + }), + ], + + /** + * Disables webpack processing of __dirname and __filename. + * If you run the bundle in node.js it falls back to these values of node.js. + * https://github.com/webpack/webpack/issues/2010 + */ + node: { + __dirname: false, + __filename: false, + }, +}; + +export default merge(baseConfig, configuration); diff --git a/.erb/configs/webpack.config.preload.dev.ts b/.erb/configs/webpack.config.preload.dev.ts new file mode 100644 index 0000000..d6679e6 --- /dev/null +++ b/.erb/configs/webpack.config.preload.dev.ts @@ -0,0 +1,71 @@ +import path from 'path'; +import webpack from 'webpack'; +import { merge } from 'webpack-merge'; +import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; +import baseConfig from './webpack.config.base'; +import webpackPaths from './webpack.paths'; +import checkNodeEnv from '../scripts/check-node-env'; + +// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's +// at the dev webpack config is not accidentally run in a production environment +if (process.env.NODE_ENV === 'production') { + checkNodeEnv('development'); +} + +const configuration: webpack.Configuration = { + devtool: 'inline-source-map', + + mode: 'development', + + target: 'electron-preload', + + entry: path.join(webpackPaths.srcMainPath, 'preload.ts'), + + output: { + path: webpackPaths.dllPath, + filename: 'preload.js', + library: { + type: 'umd', + }, + }, + + plugins: [ + new BundleAnalyzerPlugin({ + analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled', + }), + + /** + * Create global constants which can be configured at compile time. + * + * Useful for allowing different behaviour between development builds and + * release builds + * + * NODE_ENV should be production so that modules do not perform certain + * development checks + * + * By default, use 'development' as NODE_ENV. This can be overriden with + * 'staging', for example, by changing the ENV variables in the npm scripts + */ + new webpack.EnvironmentPlugin({ + NODE_ENV: 'development', + }), + + new webpack.LoaderOptionsPlugin({ + debug: true, + }), + ], + + /** + * Disables webpack processing of __dirname and __filename. + * If you run the bundle in node.js it falls back to these values of node.js. + * https://github.com/webpack/webpack/issues/2010 + */ + node: { + __dirname: false, + __filename: false, + }, + + watch: true, +}; + +export default merge(baseConfig, configuration); diff --git a/.erb/configs/webpack.config.renderer.dev.dll.ts b/.erb/configs/webpack.config.renderer.dev.dll.ts new file mode 100644 index 0000000..614b90f --- /dev/null +++ b/.erb/configs/webpack.config.renderer.dev.dll.ts @@ -0,0 +1,77 @@ +/** + * Builds the DLL for development electron renderer process + */ + +import webpack from 'webpack'; +import path from 'path'; +import { merge } from 'webpack-merge'; +import baseConfig from './webpack.config.base'; +import webpackPaths from './webpack.paths'; +import { dependencies } from '../../package.json'; +import checkNodeEnv from '../scripts/check-node-env'; + +checkNodeEnv('development'); + +const dist = webpackPaths.dllPath; + +const configuration: webpack.Configuration = { + context: webpackPaths.rootPath, + + devtool: 'eval', + + mode: 'development', + + target: 'electron-renderer', + + externals: ['fsevents', 'crypto-browserify'], + + /** + * Use `module` from `webpack.config.renderer.dev.js` + */ + module: require('./webpack.config.renderer.dev').default.module, + + entry: { + renderer: Object.keys(dependencies || {}), + }, + + output: { + path: dist, + filename: '[name].dev.dll.js', + library: { + name: 'renderer', + type: 'var', + }, + }, + + plugins: [ + new webpack.DllPlugin({ + path: path.join(dist, '[name].json'), + name: '[name]', + }), + + /** + * Create global constants which can be configured at compile time. + * + * Useful for allowing different behaviour between development builds and + * release builds + * + * NODE_ENV should be production so that modules do not perform certain + * development checks + */ + new webpack.EnvironmentPlugin({ + NODE_ENV: 'development', + }), + + new webpack.LoaderOptionsPlugin({ + debug: true, + options: { + context: webpackPaths.srcPath, + output: { + path: webpackPaths.dllPath, + }, + }, + }), + ], +}; + +export default merge(baseConfig, configuration); diff --git a/.erb/configs/webpack.config.renderer.dev.ts b/.erb/configs/webpack.config.renderer.dev.ts new file mode 100644 index 0000000..c35adc8 --- /dev/null +++ b/.erb/configs/webpack.config.renderer.dev.ts @@ -0,0 +1,256 @@ +import 'webpack-dev-server'; +import path from 'path'; +import fs from 'fs'; +import webpack from 'webpack'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; +import chalk from 'chalk'; +import { merge } from 'webpack-merge'; +import { execSync, spawn } from 'child_process'; +import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin'; +import baseConfig from './webpack.config.base'; +import webpackPaths from './webpack.paths'; +import checkNodeEnv from '../scripts/check-node-env'; + +// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's +// at the dev webpack config is not accidentally run in a production environment +if (process.env.NODE_ENV === 'production') { + checkNodeEnv('development'); +} + +const port = process.env.PORT || 1212; +const manifest = path.resolve(webpackPaths.dllPath, 'renderer.json'); +const skipDLLs = + module.parent?.filename.includes('webpack.config.renderer.dev.dll') || + module.parent?.filename.includes('webpack.config.eslint'); + +/** + * Warn if the DLL is not built + */ +if ( + !skipDLLs && + !(fs.existsSync(webpackPaths.dllPath) && fs.existsSync(manifest)) +) { + console.log( + chalk.black.bgYellow.bold( + 'The DLL files are missing. Sit back while we build them for you with "npm run build-dll"', + ), + ); + execSync('npm run postinstall'); +} + +const configuration: webpack.Configuration = { + devtool: 'inline-source-map', + + mode: 'development', + + target: ['web', 'electron-renderer'], + + entry: [ + `webpack-dev-server/client?http://localhost:${port}/dist`, + 'webpack/hot/only-dev-server', + path.join(webpackPaths.srcRendererPath, 'index.tsx'), + ], + + output: { + path: webpackPaths.distRendererPath, + publicPath: '/', + filename: 'renderer.dev.js', + library: { + type: 'umd', + }, + }, + + module: { + rules: [ + // use this rule set, otherwise semantic ui css will not work! + { + test: /.tsx?$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + { + test: /.css$/, + use: ['style-loader', 'css-loader'], // Ensure CSS files are handled correctly + }, + { + test: /.(scss|sass)$/, + use: ['style-loader', 'css-loader', 'sass-loader'], // Only apply sass-loader to .scss/.sass files + }, + // { + // test: /.(png|jpe?g|gif|svg)$/, // Add this rule for handling image files + // use: [ + // { + // loader: 'file-loader', + // options: { + // name: '[name].[hash].[ext]', + // outputPath: 'assets', + // publicPath: 'assets', + // }, + // }, + // ], + // }, + // { + // test: /.s?(c|a)ss$/, + // use: [ + // 'style-loader', + // { + // loader: 'css-loader', + // options: { + // modules: true, + // sourceMap: true, + // importLoaders: 1, + // }, + // }, + // 'sass-loader', + // ], + // include: /.module.s?(c|a)ss$/, + // }, + // { + // test: /.s?css$/, + // use: [ + // 'style-loader', + // 'css-loader', + // 'sass-loader', + // { + // loader: 'postcss-loader', + // options: { + // postcssOptions: { + // plugins: + // [ + // require('semantic-ui-css/semantic.min.css'), + // // require('autoprefixer'), + // ] + // }, + // }, + // }, + // ], + // exclude: /.module.s?(c|a)ss$/, + // }, + // Fonts + { + test: /\.(woff|woff2|eot|ttf|otf)$/i, + type: 'asset/resource', + }, + // Images + { + test: /\.(png|jpg|jpeg|gif)$/i, + type: 'asset/resource', + }, + // SVG + { + test: /\.svg$/, + use: [ + { + loader: '@svgr/webpack', + options: { + prettier: false, + svgo: false, + svgoConfig: { + plugins: [{ removeViewBox: false }], + }, + titleProp: true, + ref: true, + }, + }, + 'file-loader', + ], + }, + ], + }, + plugins: [ + ...(skipDLLs + ? [] + : [ + new webpack.DllReferencePlugin({ + context: webpackPaths.dllPath, + manifest: require(manifest), + sourceType: 'var', + }), + ]), + + new webpack.NoEmitOnErrorsPlugin(), + + /** + * Create global constants which can be configured at compile time. + * + * Useful for allowing different behaviour between development builds and + * release builds + * + * NODE_ENV should be production so that modules do not perform certain + * development checks + * + * By default, use 'development' as NODE_ENV. This can be overriden with + * 'staging', for example, by changing the ENV variables in the npm scripts + */ + new webpack.EnvironmentPlugin({ + NODE_ENV: 'development', + }), + + new webpack.LoaderOptionsPlugin({ + debug: true, + }), + + new ReactRefreshWebpackPlugin(), + + new HtmlWebpackPlugin({ + filename: path.join('index.html'), + template: path.join(webpackPaths.srcRendererPath, 'index.ejs'), + minify: { + collapseWhitespace: true, + removeAttributeQuotes: true, + removeComments: true, + }, + isBrowser: false, + env: process.env.NODE_ENV, + isDevelopment: process.env.NODE_ENV !== 'production', + nodeModules: webpackPaths.appNodeModulesPath, + }), + ], + + node: { + __dirname: false, + __filename: false, + }, + + devServer: { + port, + compress: true, + hot: true, + headers: { 'Access-Control-Allow-Origin': '*' }, + static: { + publicPath: '/', + }, + historyApiFallback: { + verbose: true, + }, + setupMiddlewares(middlewares) { + console.log('Starting preload.js builder...'); + const preloadProcess = spawn('npm', ['run', 'start:preload'], { + shell: true, + stdio: 'inherit', + }) + .on('close', (code: number) => process.exit(code!)) + .on('error', (spawnError) => console.error(spawnError)); + + console.log('Starting Main Process...'); + let args = ['run', 'start:main']; + if (process.env.MAIN_ARGS) { + args = args.concat( + ['--', ...process.env.MAIN_ARGS.matchAll(/"[^"]+"|[^\s"]+/g)].flat(), + ); + } + spawn('npm', args, { + shell: true, + stdio: 'inherit', + }) + .on('close', (code: number) => { + preloadProcess.kill(); + process.exit(code!); + }) + .on('error', (spawnError) => console.error(spawnError)); + return middlewares; + }, + }, +}; + +export default merge(baseConfig, configuration); diff --git a/.erb/configs/webpack.config.renderer.prod.ts b/.erb/configs/webpack.config.renderer.prod.ts new file mode 100644 index 0000000..8521941 --- /dev/null +++ b/.erb/configs/webpack.config.renderer.prod.ts @@ -0,0 +1,155 @@ +/** + * Build config for electron renderer process + */ + +import path from 'path'; +import webpack from 'webpack'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; +import MiniCssExtractPlugin from 'mini-css-extract-plugin'; +import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; +import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'; +import { merge } from 'webpack-merge'; +import TerserPlugin from 'terser-webpack-plugin'; +import baseConfig from './webpack.config.base'; +import webpackPaths from './webpack.paths'; +import checkNodeEnv from '../scripts/check-node-env'; +import deleteSourceMaps from '../scripts/delete-source-maps'; + +checkNodeEnv('production'); +deleteSourceMaps(); + +const configuration: webpack.Configuration = { + devtool: 'source-map', + + mode: 'production', + + target: ['web', 'electron-renderer'], + + entry: [path.join(webpackPaths.srcRendererPath, 'index.tsx')], + + output: { + path: webpackPaths.distRendererPath, + publicPath: './', + filename: 'renderer.js', + library: { + type: 'umd', + }, + }, + + module: { + rules: [ + // use this rule set, otherwise semantic ui css will not work! + { + test: /.tsx?$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + { + test: /.css$/, + use: ['style-loader', 'css-loader'], // Ensure CSS files are handled correctly + }, + { + test: /.(scss|sass)$/, + use: ['style-loader', 'css-loader', 'sass-loader'], // Only apply sass-loader to .scss/.sass files + }, + // { + // test: /.s?(a|c)ss$/, + // use: [ + // MiniCssExtractPlugin.loader, + // { + // loader: 'css-loader', + // options: { + // modules: true, + // sourceMap: true, + // importLoaders: 1, + // }, + // }, + // 'sass-loader', + // ], + // include: /.module.s?(c|a)ss$/, + // }, + // { + // test: /.s?(a|c)ss$/, + // use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'], + // exclude: /.module.s?(c|a)ss$/, + // }, + // Fonts + { + test: /.(woff|woff2|eot|ttf|otf)$/i, + type: 'asset/resource', + }, + // Images + { + test: /.(png|jpg|jpeg|gif)$/i, + type: 'asset/resource', + }, + // SVG + { + test: /.svg$/, + use: [ + { + loader: '@svgr/webpack', + options: { + prettier: false, + svgo: false, + svgoConfig: { + plugins: [{ removeViewBox: false }], + }, + titleProp: true, + ref: true, + }, + }, + 'file-loader', + ], + }, + ], + }, + + optimization: { + minimize: true, + minimizer: [new TerserPlugin(), new CssMinimizerPlugin()], + }, + + plugins: [ + /** + * Create global constants which can be configured at compile time. + * + * Useful for allowing different behaviour between development builds and + * release builds + * + * NODE_ENV should be production so that modules do not perform certain + * development checks + */ + new webpack.EnvironmentPlugin({ + NODE_ENV: 'production', + DEBUG_PROD: false, + }), + + new MiniCssExtractPlugin({ + filename: 'style.css', + }), + + new BundleAnalyzerPlugin({ + analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled', + analyzerPort: 8889, + }), + + new HtmlWebpackPlugin({ + filename: 'index.html', + template: path.join(webpackPaths.srcRendererPath, 'index.ejs'), + minify: { + collapseWhitespace: true, + removeAttributeQuotes: true, + removeComments: true, + }, + isBrowser: false, + isDevelopment: false, + }), + + new webpack.DefinePlugin({ + 'process.type': '"renderer"', + }), + ], +}; + +export default merge(baseConfig, configuration); diff --git a/.erb/configs/webpack.paths.ts b/.erb/configs/webpack.paths.ts new file mode 100644 index 0000000..e5ba573 --- /dev/null +++ b/.erb/configs/webpack.paths.ts @@ -0,0 +1,38 @@ +const path = require('path'); + +const rootPath = path.join(__dirname, '../..'); + +const dllPath = path.join(__dirname, '../dll'); + +const srcPath = path.join(rootPath, 'src'); +const srcMainPath = path.join(srcPath, 'main'); +const srcRendererPath = path.join(srcPath, 'renderer'); + +const releasePath = path.join(rootPath, 'release'); +const appPath = path.join(releasePath, 'app'); +const appPackagePath = path.join(appPath, 'package.json'); +const appNodeModulesPath = path.join(appPath, 'node_modules'); +const srcNodeModulesPath = path.join(srcPath, 'node_modules'); + +const distPath = path.join(appPath, 'dist'); +const distMainPath = path.join(distPath, 'main'); +const distRendererPath = path.join(distPath, 'renderer'); + +const buildPath = path.join(releasePath, 'build'); + +export default { + rootPath, + dllPath, + srcPath, + srcMainPath, + srcRendererPath, + releasePath, + appPath, + appPackagePath, + appNodeModulesPath, + srcNodeModulesPath, + distPath, + distMainPath, + distRendererPath, + buildPath, +}; diff --git a/.erb/img/erb-banner.svg b/.erb/img/erb-banner.svg new file mode 100644 index 0000000..f7ce670 --- /dev/null +++ b/.erb/img/erb-banner.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.erb/img/erb-logo.png b/.erb/img/erb-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..97a5661aeb0b6f20fde68d9e6dd1e899d8fda63f GIT binary patch literal 28783 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 gKKK7D8}FFy{Cfhg7$ + + + + + diff --git a/.erb/mocks/fileMock.js b/.erb/mocks/fileMock.js new file mode 100644 index 0000000..602eb23 --- /dev/null +++ b/.erb/mocks/fileMock.js @@ -0,0 +1 @@ +export default 'test-file-stub'; diff --git a/.erb/scripts/.eslintrc b/.erb/scripts/.eslintrc new file mode 100644 index 0000000..35dc618 --- /dev/null +++ b/.erb/scripts/.eslintrc @@ -0,0 +1,8 @@ +{ + "rules": { + "no-console": "off", + "global-require": "off", + "import/no-dynamic-require": "off", + "import/no-extraneous-dependencies": "off" + } +} diff --git a/.erb/scripts/check-build-exists.ts b/.erb/scripts/check-build-exists.ts new file mode 100644 index 0000000..6499295 --- /dev/null +++ b/.erb/scripts/check-build-exists.ts @@ -0,0 +1,24 @@ +// Check if the renderer and main bundles are built +import path from 'path'; +import chalk from 'chalk'; +import fs from 'fs'; +import webpackPaths from '../configs/webpack.paths'; + +const mainPath = path.join(webpackPaths.distMainPath, 'main.js'); +const rendererPath = path.join(webpackPaths.distRendererPath, 'renderer.js'); + +if (!fs.existsSync(mainPath)) { + throw new Error( + chalk.whiteBright.bgRed.bold( + 'The main process is not built yet. Build it by running "npm run build:main"', + ), + ); +} + +if (!fs.existsSync(rendererPath)) { + throw new Error( + chalk.whiteBright.bgRed.bold( + 'The renderer process is not built yet. Build it by running "npm run build:renderer"', + ), + ); +} diff --git a/.erb/scripts/check-native-dep.js b/.erb/scripts/check-native-dep.js new file mode 100644 index 0000000..6286981 --- /dev/null +++ b/.erb/scripts/check-native-dep.js @@ -0,0 +1,54 @@ +import fs from 'fs'; +import chalk from 'chalk'; +import { execSync } from 'child_process'; +import { dependencies } from '../../package.json'; + +if (dependencies) { + const dependenciesKeys = Object.keys(dependencies); + const nativeDeps = fs + .readdirSync('node_modules') + .filter((folder) => fs.existsSync(`node_modules/${folder}/binding.gyp`)); + if (nativeDeps.length === 0) { + process.exit(0); + } + try { + // Find the reason for why the dependency is installed. If it is installed + // because of a devDependency then that is okay. Warn when it is installed + // because of a dependency + const { dependencies: dependenciesObject } = JSON.parse( + execSync(`npm ls ${nativeDeps.join(' ')} --json`).toString(), + ); + const rootDependencies = Object.keys(dependenciesObject); + const filteredRootDependencies = rootDependencies.filter((rootDependency) => + dependenciesKeys.includes(rootDependency), + ); + if (filteredRootDependencies.length > 0) { + const plural = filteredRootDependencies.length > 1; + console.log(` + ${chalk.whiteBright.bgYellow.bold( + 'Webpack does not work with native dependencies.', + )} +${chalk.bold(filteredRootDependencies.join(', '))} ${ + plural ? 'are native dependencies' : 'is a native dependency' + } and should be installed inside of the "./release/app" folder. + First, uninstall the packages from "./package.json": +${chalk.whiteBright.bgGreen.bold('npm uninstall your-package')} + ${chalk.bold( + 'Then, instead of installing the package to the root "./package.json":', + )} +${chalk.whiteBright.bgRed.bold('npm install your-package')} + ${chalk.bold('Install the package to "./release/app/package.json"')} +${chalk.whiteBright.bgGreen.bold( + 'cd ./release/app && npm install your-package', +)} + Read more about native dependencies at: +${chalk.bold( + 'https://electron-react-boilerplate.js.org/docs/adding-dependencies/#module-structure', +)} + `); + process.exit(1); + } + } catch (e) { + console.log('Native dependencies could not be checked'); + } +} diff --git a/.erb/scripts/check-node-env.js b/.erb/scripts/check-node-env.js new file mode 100644 index 0000000..6bf674b --- /dev/null +++ b/.erb/scripts/check-node-env.js @@ -0,0 +1,16 @@ +import chalk from 'chalk'; + +export default function checkNodeEnv(expectedEnv) { + if (!expectedEnv) { + throw new Error('"expectedEnv" not set'); + } + + if (process.env.NODE_ENV !== expectedEnv) { + console.log( + chalk.whiteBright.bgRed.bold( + `"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config`, + ), + ); + process.exit(2); + } +} diff --git a/.erb/scripts/check-port-in-use.js b/.erb/scripts/check-port-in-use.js new file mode 100644 index 0000000..398cbc1 --- /dev/null +++ b/.erb/scripts/check-port-in-use.js @@ -0,0 +1,16 @@ +import chalk from 'chalk'; +import detectPort from 'detect-port'; + +const port = process.env.PORT || '1212'; + +detectPort(port, (_err, availablePort) => { + if (port !== String(availablePort)) { + throw new Error( + chalk.whiteBright.bgRed.bold( + `Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 npm start`, + ), + ); + } else { + process.exit(0); + } +}); diff --git a/.erb/scripts/clean.js b/.erb/scripts/clean.js new file mode 100644 index 0000000..2c7b3ae --- /dev/null +++ b/.erb/scripts/clean.js @@ -0,0 +1,13 @@ +import { rimrafSync } from 'rimraf'; +import fs from 'fs'; +import webpackPaths from '../configs/webpack.paths'; + +const foldersToRemove = [ + webpackPaths.distPath, + webpackPaths.buildPath, + webpackPaths.dllPath, +]; + +foldersToRemove.forEach((folder) => { + if (fs.existsSync(folder)) rimrafSync(folder); +}); diff --git a/.erb/scripts/delete-source-maps.js b/.erb/scripts/delete-source-maps.js new file mode 100644 index 0000000..d14519c --- /dev/null +++ b/.erb/scripts/delete-source-maps.js @@ -0,0 +1,15 @@ +import fs from 'fs'; +import path from 'path'; +import { rimrafSync } from 'rimraf'; +import webpackPaths from '../configs/webpack.paths'; + +export default function deleteSourceMaps() { + if (fs.existsSync(webpackPaths.distMainPath)) + rimrafSync(path.join(webpackPaths.distMainPath, '*.js.map'), { + glob: true, + }); + if (fs.existsSync(webpackPaths.distRendererPath)) + rimrafSync(path.join(webpackPaths.distRendererPath, '*.js.map'), { + glob: true, + }); +} diff --git a/.erb/scripts/electron-rebuild.js b/.erb/scripts/electron-rebuild.js new file mode 100644 index 0000000..0bea327 --- /dev/null +++ b/.erb/scripts/electron-rebuild.js @@ -0,0 +1,20 @@ +import { execSync } from 'child_process'; +import fs from 'fs'; +import { dependencies } from '../../release/app/package.json'; +import webpackPaths from '../configs/webpack.paths'; + +if ( + Object.keys(dependencies || {}).length > 0 && + fs.existsSync(webpackPaths.appNodeModulesPath) +) { + const electronRebuildCmd = + '../../node_modules/.bin/electron-rebuild --force --types prod,dev,optional --module-dir .'; + const cmd = + process.platform === 'win32' + ? electronRebuildCmd.replace(/\//g, '\\') + : electronRebuildCmd; + execSync(cmd, { + cwd: webpackPaths.appPath, + stdio: 'inherit', + }); +} diff --git a/.erb/scripts/link-modules.ts b/.erb/scripts/link-modules.ts new file mode 100644 index 0000000..6cc31e6 --- /dev/null +++ b/.erb/scripts/link-modules.ts @@ -0,0 +1,9 @@ +import fs from 'fs'; +import webpackPaths from '../configs/webpack.paths'; + +const { srcNodeModulesPath } = webpackPaths; +const { appNodeModulesPath } = webpackPaths; + +if (!fs.existsSync(srcNodeModulesPath) && fs.existsSync(appNodeModulesPath)) { + fs.symlinkSync(appNodeModulesPath, srcNodeModulesPath, 'junction'); +} diff --git a/.erb/scripts/notarize.js b/.erb/scripts/notarize.js new file mode 100644 index 0000000..097ff35 --- /dev/null +++ b/.erb/scripts/notarize.js @@ -0,0 +1,32 @@ +const { notarize } = require('@electron/notarize'); +const { build } = require('../../package.json'); + +exports.default = async function notarizeMacos(context) { + const { electronPlatformName, appOutDir } = context; + if (electronPlatformName !== 'darwin') { + return; + } + + if (process.env.CI !== 'true') { + console.warn('Skipping notarizing step. Packaging is not running in CI'); + return; + } + + if ( + !('APPLE_ID' in process.env && 'APPLE_APP_SPECIFIC_PASSWORD' in process.env) + ) { + console.warn( + 'Skipping notarizing step. APPLE_ID and APPLE_APP_SPECIFIC_PASSWORD env variables must be set', + ); + return; + } + + const appName = context.packager.appInfo.productFilename; + + await notarize({ + appBundleId: build.appId, + appPath: `${appOutDir}/${appName}.app`, + appleId: process.env.APPLE_ID, + appleIdPassword: process.env.APPLE_APP_SPECIFIC_PASSWORD, + }); +}; diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..7cad535 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,33 @@ +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Coverage directory used by tools like istanbul +coverage +.eslintcache + +# Dependency directory +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git +node_modules + +# OSX +.DS_Store + +release/app/dist +release/build +.erb/dll + +.idea +npm-debug.log.* +*.css.d.ts +*.sass.d.ts +*.scss.d.ts + +# eslint ignores hidden directories by default: +# https://github.com/eslint/eslint/issues/8429 +!.erb diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..85a1aa6 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,34 @@ +module.exports = { + extends: 'erb', + plugins: ['@typescript-eslint'], + rules: { + // A temporary hack related to IDE not resolving correct package.json + 'import/no-extraneous-dependencies': 'off', + 'react/react-in-jsx-scope': 'off', + 'react/jsx-filename-extension': 'off', + 'import/extensions': 'off', + 'import/no-unresolved': 'off', + 'import/no-import-module-exports': 'off', + 'no-shadow': 'off', + '@typescript-eslint/no-shadow': 'error', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'error', + }, + parserOptions: { + ecmaVersion: 2022, + sourceType: 'module', + }, + settings: { + 'import/resolver': { + // See https://github.com/benmosher/eslint-plugin-import/issues/1396#issuecomment-575727774 for line below + node: {}, + webpack: { + config: require.resolve('./.erb/configs/webpack.config.eslint.ts'), + }, + typescript: {}, + }, + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + }, +}; diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..20570f2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,12 @@ +* text eol=lf +*.exe binary +*.png binary +*.jpg binary +*.jpeg binary +*.ico binary +*.icns binary +*.eot binary +*.otf binary +*.ttf binary +*.woff binary +*.woff2 binary diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..5b774d1 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,5 @@ +# These are supported funding model platforms + +github: [electron-react-boilerplate, amilajack] +patreon: amilajack +open_collective: electron-react-boilerplate-594 diff --git a/.github/ISSUE_TEMPLATE/1-Bug_report.md b/.github/ISSUE_TEMPLATE/1-Bug_report.md new file mode 100644 index 0000000..245ab77 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-Bug_report.md @@ -0,0 +1,67 @@ +--- +name: Bug report +about: You're having technical issues. 🐞 +labels: 'bug' +--- + + + +## Prerequisites + + + +- [ ] Using npm +- [ ] Using an up-to-date [`main` branch](https://github.com/electron-react-boilerplate/electron-react-boilerplate/tree/main) +- [ ] Using latest version of devtools. [Check the docs for how to update](https://electron-react-boilerplate.js.org/docs/dev-tools/) +- [ ] Tried solutions mentioned in [#400](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/400) +- [ ] For issue in production release, add devtools output of `DEBUG_PROD=true npm run build && npm start` + +## Expected Behavior + + + +## Current Behavior + + + +## Steps to Reproduce + + + + +1. + +2. + +3. + +4. + +## Possible Solution (Not obligatory) + + + +## Context + + + + + +## Your Environment + + + +- Node version : +- electron-react-boilerplate version or branch : +- Operating System and version : +- Link to your project : + + diff --git a/.github/ISSUE_TEMPLATE/2-Question.md b/.github/ISSUE_TEMPLATE/2-Question.md new file mode 100644 index 0000000..27d4d5d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-Question.md @@ -0,0 +1,19 @@ +--- +name: Question +about: Ask a question.❓ +labels: 'question' +--- + +## Summary + + + + diff --git a/.github/ISSUE_TEMPLATE/3-Feature_request.md b/.github/ISSUE_TEMPLATE/3-Feature_request.md new file mode 100644 index 0000000..84663b6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3-Feature_request.md @@ -0,0 +1,15 @@ +--- +name: Feature request +about: You want something added to the boilerplate. 🎉 +labels: 'enhancement' +--- + + diff --git a/.github/config.yml b/.github/config.yml new file mode 100644 index 0000000..3708b46 --- /dev/null +++ b/.github/config.yml @@ -0,0 +1,6 @@ +requiredHeaders: + - Prerequisites + - Expected Behavior + - Current Behavior + - Possible Solution + - Your Environment diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..5e2b3ad --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,17 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 60 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 7 +# Issues with these labels will never be considered stale +exemptLabels: + - discussion + - security +# Label to use when marking an issue as stale +staleLabel: wontfix +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..0d8b5cf --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,72 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ "main" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "main" ] + schedule: + - cron: '44 16 * * 4' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..5f3f8d8 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,46 @@ +name: Publish + +on: + push: + branches: + - main + +jobs: + publish: + # To enable auto publishing to github, update your electron publisher + # config in package.json > "build" and remove the conditional below + if: ${{ github.repository_owner == 'electron-react-boilerplate' }} + + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [macos-latest] + + steps: + - name: Checkout git repo + uses: actions/checkout@v3 + + - name: Install Node and NPM + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + + - name: Install and build + run: | + npm install + npm run postinstall + npm run build + + - name: Publish releases + env: + # These values are used for auto updates signing + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_ID_PASS }} + CSC_LINK: ${{ secrets.CSC_LINK }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + # This is used for uploading release assets to github + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + npm exec electron-builder -- --publish always --win --mac --linux diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..c8ea922 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,34 @@ +name: Test + +on: [push, pull_request] + +jobs: + test: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [macos-latest, windows-latest, ubuntu-latest] + + steps: + - name: Check out Git repository + uses: actions/checkout@v3 + + - name: Install Node.js and NPM + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + + - name: npm install + run: | + npm install + + - name: npm test + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + npm run package + npm run lint + npm exec tsc + npm test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4b236b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Coverage directory used by tools like istanbul +coverage +.eslintcache + +# Dependency directory +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git +node_modules + +# OSX +.DS_Store + +release/app/dist +release/build +.erb/dll + +.idea +npm-debug.log.* +*.css.d.ts +*.sass.d.ts +*.scss.d.ts + +# databases +*.sqlite +*.db + +# configs +*.conf +*.config +*.cnf diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..d916524 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["dbaeumer.vscode-eslint", "EditorConfig.EditorConfig"] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..7494aab --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,30 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Electron: Main", + "type": "node", + "request": "launch", + "protocol": "inspector", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "start"], + "env": { + "MAIN_ARGS": "--inspect=5858 --remote-debugging-port=9223" + } + }, + { + "name": "Electron: Renderer", + "type": "chrome", + "request": "attach", + "port": 9223, + "webRoot": "${workspaceFolder}", + "timeout": 15000 + } + ], + "compounds": [ + { + "name": "Electron: All", + "configurations": ["Electron: Main", "Electron: Renderer"] + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4a58cba --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,30 @@ +{ + "files.associations": { + ".eslintrc": "jsonc", + ".prettierrc": "jsonc", + ".eslintignore": "ignore" + }, + + "eslint.validate": [ + "javascript", + "javascriptreact", + "html", + "typescriptreact" + ], + + "javascript.validate.enable": false, + "javascript.format.enable": false, + "typescript.format.enable": false, + + "search.exclude": { + ".git": true, + ".eslintcache": true, + ".erb/dll": true, + "release/{build,app/dist}": true, + "node_modules": true, + "npm-debug.log.*": true, + "test/**/__snapshots__": true, + "package-lock.json": true, + "*.{css,sass,scss}.d.ts": true + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..80a8ab6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# 0.1.0 (2024.7.1) + +#### Features + +- **Todo:** Todo... diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bae94e1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..252c5d1 --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ + + +
+ +
+ +
+[![Build Status][github-actions-status]][github-actions-url] +[![Github Tag][github-tag-image]][github-tag-url] +[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/Fjy3vfgy5q) + +[![OpenCollective](https://opencollective.com/electron-react-boilerplate-594/backers/badge.svg)](#backers) +[![OpenCollective](https://opencollective.com/electron-react-boilerplate-594/sponsors/badge.svg)](#sponsors) +[![StackOverflow][stackoverflow-img]][stackoverflow-url] + +
+ +## Install + +Clone the repo and install dependencies: + +```bash +git clone +cd nextm +npm install +``` + +## Starting Development +Start the app in the `dev` environment: + +```bash +npm start +``` + +## Starting Build + +To package apps for the local platform: + +```bash +npm run build +npx electron ./release/app/dist/main/main.js +``` + +## Packaging for Production + +To package app for your local platform: + +```bash +npm run package +``` + +## Maintainers +- [Daniel Krohmer](https://github.com/dkrohmer) + +## License +AGPL v3.0 © [nexTM](https://github.com/dkrohmer/nextm) + diff --git a/assets/assets.d.ts b/assets/assets.d.ts new file mode 100644 index 0000000..251085e --- /dev/null +++ b/assets/assets.d.ts @@ -0,0 +1,35 @@ +type Styles = Record; + +declare module '*.svg' { + import React = require('react'); + + export const ReactComponent: React.FC>; + + const content: string; + export default content; +} + +declare module '*.png' { + const content: string; + export default content; +} + +declare module '*.jpg' { + const content: string; + export default content; +} + +declare module '*.scss' { + const content: Styles; + export default content; +} + +declare module '*.sass' { + const content: Styles; + export default content; +} + +declare module '*.css' { + const content: Styles; + export default content; +} diff --git a/assets/entitlements.mac.plist b/assets/entitlements.mac.plist new file mode 100644 index 0000000..dad3e20 --- /dev/null +++ b/assets/entitlements.mac.plist @@ -0,0 +1,10 @@ + + + + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.allow-jit + + + diff --git a/assets/icon.icns b/assets/icon.icns new file mode 100644 index 0000000000000000000000000000000000000000..cd41f8c2362c50bde78da8df5f9c9e36da5dbaf2 GIT binary patch literal 103109 zcmeEvcT`l*v*(>*NRmO2%m_-9C?J`U;1DE8&Ot#yqU6i~N|u}?qvRktXNiIY$vNjB zIj0@J`g`x~**$M}&v}2mvq#Rk+^XrmUENi6ySnRh?~K_iD?0!b*>3iVlM4XQ-vlbk z!*TAA-vIysM_Nik33-P7Ixx_X|MSe=&LU4BJ0-Xn@THG(1Ib7jYe>JAlLMHMGzI|j zHv=HQsvr+?S3{=%7WRN(NzHM=e7Nsm!k%r)KJ=re;NoOC5IN+)tAZJ=T)k8t2aY z4l5B)HkfKc&p6&li}D`oyWyPYIH??>|%FJPfBtREBtbH`}Az?Z^6NBBqoU1}rX8j*fc3)T4}nKAX<6;M?bHA*(TjL2ZGUWR3W9X#t@olctocjCZdm`j~d2O~wLV z^^AKe5p{_!NH&vQ$G<+4g455I>##bmAC$za_>hvGP;fHw#r2I?F0pEn>Z{iiQQU9e zq%n95#VDVx5Ao#0m)&J&^P+mVM2{K8B+epVa3W9Pd11$%hi4TRl3?(ty(1>E*xz2sUKKuPv#2nBK&aEf=LRVjbJ54 zM0Y7(433BBs1WdV6oB1}4=tk=J_cK=rlxV!!5o&jX1H;tMy(_#UOnEk>UC?3$&>Oy zNmJT0Y~R@6*Qi;PTR*<}5I0u$^5)RAQnRGsC4Y#KJIA1zgGQYV&X*}GgU<9KU*mg6 zPeC@5-`5MK{4bZSH8T~O!$p7OFRo&BE|fo!wJLC#KN@5qIzFv$g zsdHp^r4;_8!GnDVHrM{j;I)janP3{wJZXcm8g;3vpO#hq+N^m^@X5mK9v-IPZyG*$ zPu%?i-$y=m#rC0Xw(4aQ3&gczz8TDz1jN@kCI9|Y-_<7V?tA-F)V`bgDIj7u7R;I7uw6W25 zmCEQDUvFs7C5Ns9X=)w~-^V8bEF_0oEQ_h90zG4TpT7>pl+K+9n>I+j=f{V3hC#d; zxp5r2ye+n@kSoEgt3^tPO$vp%)@d0u*nov+oHFW{HZYPCBAIlII3};Y(#w9ffy8n# z(XKpZ=6q%y{^f_pj7=f+&dg3wQi>5lukcV%)*Z|*skt?ui9f_1ro6itx)=a*#>i9? z=G9*YNo*nTt=AzweXwDNw1dO}er`fV5W{r4)dLt2|o3Q}*S zR|A!m2HrB7$lS5T{ixA-)El8&ZNF8@kbZz&i@j+V6roolFrR5ktIDPqRJwGq!uZ&i zHf(ES(8t)FpV_Ai$KdrxfPBSJQE30^JYz4c8${G{zr=uJi?8p2UsJLm;a!03-q77c zpg0>f<7PB}J*O~s6>yX^tdIJ<-}$0NH5V;3zlN;`mHw1u+L?pBQ<6kCNhLC5Mki&p zy3JQW{_!_ArD$F2GUsSeO44b1YzyGrL6hIpNLhHpe%BS)r+R^Q5 zbP4Qk#zMxQpy9WMH(*+sx=F7x^l=n-(YEt`A@WRC?B?7brkVk~*X_VIF6W`?_e%c{ zFYz}6&K2*<)`xA!bV+csye$9*V3n_>M)97VHI-jE4gSCdpVk}IJ3Da%c;i1xXSnT6 z65S6$V0os?-5$5FP$`@U%_T>xpRfnQ^#afsL*jnLH)%Z zB9PS(|3unW5yKuN^IsBa5&t35{*nMlg+iQ=JrMpAX?3w|R91*Z>Lx5^CxoP-51#6Q zBVqUJC2$nc@b9QeyvS-VspR4c8s0E4D@^X=(DHwAX=|TBrIn_UjmT7tA$K9g$H0%k zxEqQ89DH9PGJcGHVkX7ziPOZ)_UdfIr8Te9t`|MSsh4Qq`AO5Q*U4;|Ksfw`hQpYa3(r5Rk^AIFI=f70ty23 znzeenboMu6pOS6bM6hE7G=KGyTn)mbB0KsdqAwPkA@yjVpG)1-w0oY_3G%Myp+)DJ zZ51~)4i)D2j@)6|)MM_4wQGk8p6fjbd29&8+ulQ6U@(Rb8Ismz(=f87pv8e}XX+eZ zV`wgd?wRlrq2MXMQv;o^V=*t&TugRddSAGBaM(p z^k4uklZk?{m03pcuoS*H#tEp1F{Dc?C>Im#l; zHjsiE08-!FAY3FOSPOjl9K%8mM$P7=U+3jX=SRm-DS?&&cm33sIh657Pm@G;1UWg%KmaKZ&exYwIw8UYxu1=2=17fw zBKWaT=_1O~F;?DX5KVGBRl-zrO>}5G?gM=r>peutLJj3qzT?7;JD6YH(-t7fv#e=Ld-m$M6ERuU2H*?~W zI}Y7<9(c4Ep#n6b#EpGjL8*7GjiS8u8&c8?vM*m3AmB|^Ag;kuR7AjrlDe>%q0XoT zY1BU9vRw5&&k9RAd;5yhd=g>;)Fzh$)%du_c#EGFw}W=oyWPaJ#K?uX&H2BRixQnA zUEx>$bR#O@ZSoLt+X)A#4Oz_$DaEnF}rw~3|TE@vMJu8qNi*UWZ%Nn4W#G*j;}^n!y=_eE&*Z2OE~OK z-?`6rYDMQgTN-Nz7;X!Xty@)e4m1gNBuV6S0WX)IRMYXLnguhRS(pH6E1ltSx10f2 zW_ABu(HS;mB#WV|owhkPyHf1udah^1TH(QU)autQ^D5__6Bc2P;sbN3Z59(_`FD4P zSc~Z=AF!pAU_VmB`ktKBU+V&Qv$xj~u;jctbq7&ilr~57(Kf$E#TYnvAg>q(r}qkQ zyjGGhInXoGXQDm@vCwFII6>LC9^g<<+8WcvoubPpFRu`X5U>hYQ94S7J|(M$xh_eNVL(cTtS z6C&}$(H5)IdSb10TFy~OcrpF$+wrpjER3LGLDc$pA*LBx0v_K6P!MtZxZjpfPDswy zTIO09;7&MvBDFS}8>^grZnoEBJSI?D_ zUIPiN^t*Chr0l9~+3s_%SCogui#R-(vHG{;R2mPv<}Sx5Y|bZL)*gJ@yUk;3&9Y>d zVb-@W?OaH(`7uE;BZsz^yDfY9Vxc&$Dv!$7Fa0<4**UTw zz3x%H%d$??8LXFl#vwHL1`U{7d}5U9tf-1`F=pIdd9F*u3$$W5HY53}FCHyroFgcl{!Y(Fk zrw~_gp*zz}L(5r5CEeg)T2gxHsQ4IIKN085z(^cfm7`(Xm=SK&CTd4pkEZoMy90&G zSQ$shyUZkza=j>hQB2!g02DxY?@pHN2{$V$itlw8?5wcB_A*2vu9X|hJH*S_F>~N$ zDYJl>5{rrOT z?jo)S%?EV=eLuvN+|Hy|b=|54wIk!X!bB*yZajf4Ns<3q^z&-HD;lm^aUCVJ43ia@ z%%sM;MWH|4WhGztA%J+FuAhkjHT&V|#V1<93Lt<~`VUMxg9E3rr+ru1s0uF^Tzy+V zYls_Tj@2YW3b>l$ZSz+-$p>B;z+X z0o5)>6kot2o;bW*0-%l+wxj$Hiuo4C&R7_Xz@y~C0s9DQ$D>`4-_iE8;!wK&VZ^0{ zPm(~?5mw#^ZkbKT@uKJIVwJ3he@-{?2!TpgpR;r^@*!2^1p}_uWnI4dFaQ) zk41asJ|_}AFles)jT&~h7L|%kcY0qrhtU~*a?d%yM3_@{G)BlhBeYsuO_TNROS3zU zGq&i8u1A#G=jozP+f8<#jwX$SCw;`)UzcJQ7=gF82{({hShw~slC z>;AQ}@q$)|Nd!Yzuii|TT@=0DRPOH8dD_zmi=gGc_p!WgoM|> z2tIrY<|Z8d&O_@VJ{xPHF==o}k_3N6&I8j8p3kXFbNX3|gZGM-m_cuO?BrHBd!-QH zsGAY1v&D_N0yD}I^h`m9wMvkNT}-n+m(s6dy3A(QL)XmZyAS(cjEYl)3T4;!ne`c# z;H`1rA>uzsx+q>7zZE=4CKS#LoIqK5LFO8>oke4PKk%9Z1X~Q!7n^Q#i43LPX`+02 z+m8PumktMZB}s6~eb6L{OYxpXrfr3JdBN}b^IdcQ?)A&f0GGv%4@pWvh6|e{**Cfe zB~*rXOyw>N3eQ^?#awCyzIs>&m|cH~pHJ}{(H(5#(+$k27u*r5rQqEy7tFEkKYS>E zxRPOriCnB{oO3(i{_oahuq7akE^BTMb$zdgGC4|6{nResEy;-OPLaTB|-u6cK`!{;Xi4;urfwM-6m5jZp1_;yOEkTX`8hrla=m$*RIqKf`2 zN?>z{Y>2=P;2_SvAYTF$Q~TmW<53W~d?RC|=!gsZ4*NDr;CXv)V+S8Foc%b9ZWSw&_e-a4+ z#`G1`<|xksVr0{Tfq{a0k)m8%Ol~5eTSWv@#C?U3kpZAo*GnB!sey=OcaH5!iliR| z?k!xhdE*vD%CIyu8LfyqZ@G2WcMOC#ck+ec+U7j9M*FdwEE4ctnt~9TTqNn}zSqjB z6!e@dNn9VTPO<;mlpre{PYD+>5c`yMb9|qL+8zr(ml9>C3j&c(X9CrZ6u}yy^8I8$ zv?C!ufeWuB-}`7t*WxAJGK%f%V{DR7cdi`q$+>dix_#m&fu_V~;E%qr1}BH2L_KWkaLVc^4b|Gsw^I!KIA z05bd89rJ-V0@HmDdY>~M*l!I-h(F<_N)FT3A`Pn>3O9!<46Pa-^@| z=l0cZc7BarPtDrR&+ijVr?dMJc2?{p9zvHM6T4I=nf0tj?AmhtlG;ey1nP zCGoa;$!*9r!}e)$)y%m?tTSIvUHmoKHhk(4#UiXZAEH&W@DieDAR632im9DMg$51d zsR_B}+3uYBMEni`U`WsnbYPZE+@@Tw{ou-^6-i{N@xFH2_T4i;yn<$S!VoS^eK)WZ z4@Zv%FrS~fd(!ngk+BdTC;)cE#~0^FzGj~oV_@cZffC+IJl%hzbrKjWr}AVO9fTi{ z+KkqBA%1eW#4Z;75w;qUbSihUR@(WkAAcSOyAM8iy+e3%5CXNL!!H7btGn!$78&EA zgQ02k-q>neMkjO=J%^wg;ed@rPJl@BtKfG2OBpd*366|IvwtZ^1s{`#%;twzw6%0g2i{D)*nI=4Y3><{s z@|;{summ{c10Z#LzMu-7)*D$C%awHR7&io6CX^B>=o0fPBGG_fW^B_T1^eI}(V&`e z`63M!Ixh!KeOtByZC#3#>f2K|@ttV(1~4-4ywj(n9k$~V67RZTL5W;Xo|wQ$ zAuy;VMi+$Eh0&DnkQm0++4oZ4B7+tHL&N1EMy$9W*$qPOa_fV1`Y=Z}hPBF3A+R)b zZwme_SQw8!NT@Xe0J!x#O8L_LkE<- zSHfUzq=S?**ics4yen6F0+?iZME!sv2bqjWI?etT3TYz@iKIe$5vU)Z@2M6u8Vt)h zYr>QfIb3`WY+&@b6$Ap$(s2YN3Mqa8I$Vl&OgS+S01+tzngO;V(qWt>l%LVS~|-6bdTRz`|e- zV0O!{oD_nMq|oj_V9jn21E79v4cSXlB!zt!IgnF~X27|q|Hn&w4kSg&_)j+wpgq0R z&+SkHd<2L?5$V6PbO6eHgUJ6^9rJ$lgtz8mIaT?`-u1W6Zu6Aez=uRMWZAo0vGOO6 z<<1#NGuZXr5ag9#7Bu+q_eenMpb4HgNzAN-fic0ydLDQgVVMysd@CKMkJ zq%Myhnr+w>Md@Ae{ZV%hYsR7vVRt`E#`9TgOLM~}_!RGs*?i{RY0fAv(I=^QY_YiY zyLTeKEq!n!&&{m}Owdlut!Uuk*I;AAL789dE0aAI65+?4T_Y8+xq6T{VXmLYn4ghU zK&kiWeokR#_(l{Du`?&?&bzp3#c`VTjO61f(_=rcq0*7yjj|$i&#QWkL`uM(msEveB>2JUggO;Vn0F@`|!N&n;O=ksPLo6ifWt5FP7$} z?Tcd%-Nb(8ykh&bxah5mTrD2EN@y5qghibMn6K%tJz15*+iBYuWe^ObR}c!5f2q%D zfN?9Zsw{H5C@XvcW^qjxt|Dv|*ng(5Wf00*_(5f^I(XId;!eZGez3||wQ|qea?|~l z5$=_)vW<||zE63B-YVhBu=g&g_uC~pi|>) zo_7xam>^(|*SpQeBzlP5oR)8*G~4C-fk;KaQWp2wbw-RO{ciB!D&I9?hlIhUyuJhn z5gmb|$<9(*QQP{q)LMQ^PhF}q*8g^7R|D=s10`9NQ$&ya>$PpugO1 zA6~D0<5FI&n6SOOAbYT7l_+IP+hKd|B5B{3t3Dtd#g_Jx_Y?m_O@g~_mfF4B$GfN4 zvd`mEN*QVcqimq_+0PmY&(4CK)&nQJ(sXeI%ee(_h7g~)MA*10 zYBO==>cWGb35J{%6D}B8_A?iB@*G%-Va?GC9nRVv4No^6#E8jih-q15F}Yzu)ueYJ zk2g*CSB1X$5#`cF)c-iTbGCHp5U8pShYPMOFSm084D$5|Hi0!XW@g3_w*A7hXG5G3 z&Nbhu6?LAP$P1;0@*8mV-t66)Ua*9X+e!;tIkV2VOT@H`M}1% z%NuD^IX#!%Z2a2D)NlTiGFvv8Q~mQ8V^xnYJaI)TH*25jOfNntD6>*{gBGHi`oTnx z;yb@Hf1FW}uZgk=qU@0KIk2_^G7T^Dj~n0*Sm41sR^w) zif&*lc{w@0uw!yjcN*8#P_Mzp&$v?6gC*`CZ#S)12T(h8q=?;(f26VrvLxp9_z$EO zd4^Ee9i$Jm4&JCReycSEA|W|4``9-Xy(`*4S^h%QP9H@|=0RyoI)$U%%e>YrgU_GJ zBdKd01*o{#ZuI+G&BHP_o(Rj1)ZZx=DpG9!X6LVr$Nyor`p}qHCS99A)m~Ntj}#$c z%9J#=*0b)2T0B;)ReQcEs?4NcnYY{>gf`%zE-V8dmfut@EDIIzr(Uinet3PEPb2q3 zr;(ggTUXqAmOt^0UkGxcwBbw&WY#fwu5g{TB;H`B#VeF1dY(XH7%zHMI$US$+G$K5 z%%w=!b^i1M&s_KlN@4qT%Tqh6sjCcORSC(`G5hBiJaEGYabKmC8dTe;8Xlamq%-Hr+H6w1YIkcN(kv5JgSHwnZ z1_x1m<|-{M*G7~n+>+st2_b3ye;%Oc z%1~?74t(<+|KSTC+_^WsNxowU=nScr5FhU=pD<Gd7&}ydu@UXX$>vl|9#~VOv_n zWX{tko7S0!P)|nZn+&_c$mk&DL16t=-La(?q4HCIl?wgU)2fQy^sHDkOK^zj`zAff zbIAv-9y_*NiA81#k9lmg+o}#t=9M?@I6qrFR`#6T0huswg;lW`TY(Ztgy6~AY7}Kv z%WaSQgNS4^J5?#2>5a#a%-7bWsRYN^GGdbxU58omD+FBfwPkei>=M3=o#6C5oaA96 z#ZVNtOLiPA(z`@0yjr!J?4Z<|(q@Rb!8$ zwOGzOKI*Hz1M(Nn>6q=NR8XJ3wT63uPI?eGh{_A4xi0cUQ6-zvwWAY`VNp zftyT=g?+E)Ux=EU9*=A8w+}<~u-1)29 zM`>ldA7!?xtmlKDYQAmJQ~w(LCCO!dVU)EioGy=Syq!8U6)b|A`cHM(ven=Em-l+d1lyL{t$&qXn@G>1 z<1zp!Tk>KD&~9QHcS~5zu2)qnSx)u`Yq-~<;?8E>!gfjvAy%^$AK6x9o$9uxl&WH^ zyjJBWcMzOWBf&}44aJL5rj*#QPi;D}O*J(syQjNZ)}yymoV}^e8=%SFe)J?q2aB#R zu4i143^(%CHL`0zCJW~#*(N)QD*O%>GnoZQ0b;jy`ed-DD62MSs)%OvnM`|N4m56M zNZ&<+LNHvaM&h8`&VOw#QF^PYP&Py3tBcodm|11r^i5S~IPfpv&BV?1_opV4=`VG-X0;A@dG@kf zx9yE_ad>6a;G_s6OlB?5l?2J*j=6o=Ozr(0uBp_%;F|-^(A~2Que|Al{jJW2 z(#ZlY8A&>zBmev|m#%zwZ?1?Aaj-470xqZ7x((%S9xtk`H!vv-@Arpu=*$=64m zJ3*k%Sj|(?6qB{RSq5IT%t#Cv;7kSI2_(%kQTM{aTXSzDVKK z`~K?ki`;cq36Zb&q|)AvD4~X3VuNpjPc>?QM2H6ihP|VGhQ(eO(FMGFSp6t4#L0E; zr#I{=wL!+GR$@d@L*zSouE@gHRi|<39N$ld;6e63eIQFd(;M2|m3jv57J$Kiz<~~} zI9zTrTI6om9_(3~V4n7=l@ICUr~;W(pn6oPIyOmP7}OIC3W0>skl6abY6*(nJV13w zq?!audNeiSNvn@$Z1j4H0WT8P>;q7PwO||OD&cVrl|9A>-%?xWtb9>G44Cux(>~by zdR}4!Ue(D#`OhYDs3g2$3Sd&q@hIukS694VRfX>F67;Qh9z*Y{guI=mTNQoD1yc3bZtbPJzwwp|rLikx|Mp@lMLTcWjDca^QIEWmuEN`Cd_F zBkp#7(1d%w;^T#PjU;e>Jbar?M;=Z4FAd;uKWqInr^Y)u3bEd-EB>J!#0XaCkcw0` zO+R3E}0pPW+Q`ziFJ(U&9TWb+& zWFPregg2q^NsRQL4D+4D2=U}DhMR7aqR*in$+)WcspCS_&xC4E#?QFu;?^)AnCd{N zgRAz;YpuR#X=SPUSfS)z<*zK?88{I&`#^C|^;;*~%NMPy6yZZ`{^mh!BB^kKms)S_ zMfBvoK~hh5ceRc=J@@c<0L-8`SWxH=7og8JP;Ya;di~GH<4x+EiZ~-l&JR^X1%pbtN*RmNLb4AY za-s!^9u70NhP(Lqr{1I2Y_b(8)Hx8a)G7`9UP_m zLv6}$=*VMYq@m4tzo7kw(vcj)Uh#2Q&-%9M*wM=vqZJ2nxTXG036V$p`@~^k1wO9) z)YvysV~!u{PmJIu@F!FiR70Y=PRc4_2Dqov{vTL0PjjGw7(eDFQac_*+kG;XKIY3K z7mUbz6Pi)l@`{m;#lQ3n@_l|R5KI@fyJWnzWP%|gLS)?76vBzI2byV7Cy}e;9UQHY zU9Yny89I?;$rxGM(?QF(}b{`gHlj2&MJ1R_P;g*_vNrZFQ^ zbgFJ>uHLXa7>tJ`&^p_@E1?41N4O~zUz+q|3V*)$$Bx{nr1?laJ9eOzDQ%d4rf47L z%6j-L!Z1cXI5<+2a;8vT*UzF|I^~OddiY7|twX!H=I5VVwzZb6?;Xfy2E`W3Z(VB} zM-D%p9`h-eP}i=1{l2n@xyAK)r6R9Ro6PR1e8Bif*_$a-vmc9f#PSAfAKLA58Z|$} z6hw0ZHJ|Z52ifi77FE%ZKctUiD8+56jIn8Jv=3=BwuRwsxm0-EWEah_@9Vxzw|z#& zsvn1KS5Gk7Bb!V~7KF!2Vm16N!d2Ln-?Hbnc4w=UcCpvRUVKbfFGqw`zuKaT%dkdi zR7d_m!nFY>V!uNKJ)~IGg*E0-V|i&?xckl9toqWTt(?q#(OiWjy&@7^xMT2;?fdSn z^UqdtE1y>}d$3GKPCmWw<@(z0y8NV5`@N`snF<*S)B~AigU-J|=ESIXoVh6=?*MEd z6a{~e1F3I3Cy@kPWCc>`%S#47+I^chS-*_?z2-P&*vI!*?bK0^`@hAmOPm&VYqU#t^BhP#kk}?C zKMvW=&A+b^1`_KSn+SeusumUB~V%0$B!N{?(tv|@Y0Lv2~ zKsG^-mVFRd$njODMWxYV@JS*^#8euN1!hBzao$JXCkQ%!7pa!)E-^NYY6LQkj3t1{ z?1NB7s^)Kl|1Ub^1a{;x{dJIe^GwY0K#-}DmL%gZH@xfpj1%}EFa4*;6wRP)kXei$ zSuY#IB9a9W^KV53J|M+fuQW;wzGrDs4~qy;iU&%Vp-3bIrV5tTEOF!n4kxPe@*W=j zviQ4ZL0VO8&Ol{S2_vE0y-)2=C5I&H{wHRwW=5UZxhp zk;_)-ycT%3Y?Yzp6kZ8EAb}~&wSma)*_2XyBc&r)Fx@+~dR#1Oe!{s?psdOL)cq*$ zAe0!@Q81Kzk2{w|pL1z?0I82v6AA|UEP^)3zJ0k5Ro^=pU|$tVoyCTQqt>^1l3x0b z{{o(J6kwz0N!@yh`}bsLX0Z{`IK^Hu9+;P(f0xR_n%3g9&-8SK&|vpy#WCVaL}NTs zr~`j>gbOljBDZ{{Lsj%lZ3%c86Eg*Jk*tQQ(P#Wpb2I|`peFg+=)@Kkzbcp)H|+^X z>F3K6yyBuw*2jZL<51E;PtThSn!c8hzrhn>4e>0f2& z=obOBEUfbZSQGkRZ!}HA` z6E0VU*DKw^*W@Rmp7p1PA||DwwO|D(#>$hVNQo+7`?5v08xcnjWC-44D5mP2lVv;X@8 zbha6M3tm)R3A_a@DKr6K2sy^48WfYuu%i_ zjFBwS2W-Hf4KP;*G>wofijyD7ANCcJW#bnWcq$?+CMGJ*k7T8_v~~3j3}3!7GE(|S zAaMjHQlRyOE18*~vowvP-mejAPv{Y~=j#nt=(PW85;}ncv`YhNE`aX`BuhO(2(*g< zAMF8;Uo2`>5A+WkjAW%W4b=6uH1u>ekWVxMfUS2BC^* zF!Bij@b5RukDP}uklcU88|C2t@J9JB2>^g~R`DJHV8EX@%4g8i9!P#{-rsHS4eWJ^ zd&r8#0(}wAC>_WQ#c+mFe~QQDzw7;YktvPV)j0=h%jhE&O3QdhN*IBH@p|jbQgU2;R$nCen^G6lq^@2J zXM2X@!vGKjzl*u}=^D5BY>taDGy7=2ORkWv=-hC&=;66)=Le z-p#2zqG=PMPzeD^e!#h@J30USQLiIk>bqZ!Az+jcUh{`E!|sWzaPBJ8P@NzxfJ5v( z+pv4(YBFuMhCMIFR)w{{~(*Q>P&IOT$P-Sb~eT=GVBV%22x_yWc{ZJy*PR z%cwTv(?0%I0sz)U-Daykyv?gwhNH-MK$?Hf-4?Dc@kIUB04&YT`(8yCS%U0^ zeT!0xZE+T0yi=xNA1UkY6jCuSL8LiCjLp7eOZapuNM=lWC;o&m}yhEn$I0~ur9{*NQ2>btrvvF9-H?QoJK8n?=fyVfZFTP(q6DQ z<*zE3{&4^VY#*}C*qoa%cF#Pf{SL65*Dm@-tQxF&crBNk2m5cw13|i3I9@!d ziduE!o(g_{Aa95Q)b-y6)mL@=9wX9;A9)MgOM38#Qonw0$ObMC#@lv$SKJ~V?^=re zr;ZWHS-kv>@~Y-U_9_K{J)+u><)U(;%7y-qO_4Gfi=S0hgss-kQibxPB+gtdcnLPs`8?aAJ9oGIxKE>d4QZ;Il@y z?|q_i(8J%w0kJUa!cgJDCnntv5Q9iIe%-PjGoK_1L;62ziPoJrm{}~Fs7%IE@9s96GXnBhxHPgwG}Zn7bOI+)UDG%wp`wLHc7Tpp)}( z{M^a#CFHlNHSUai-e7%vld^$ym@-x zkKi9Q1ymt~hj-78=rhoPwTycPlz&X~lD&B5M%ejIS~jnB;Of&7YkHi2>LYLDG+0#V zxEUhmrfr@85EN?en~Pf@`rV05f@1AUQ4$Mz(F5{EASuB0Km)~ZFe65 z#c-5=b3-!ltmhnZYWQZ#UifE}Ama7hnjc`m4bJheJ2{eW9u*Ld9MaPY`d3Q>t)am1 zQ|~`)Afah7fcV!uib(_oq%{18bbhPrC?NNHa`|=1pSJ&A@>gSj9p=Bq{gOuQbAU0-dlW6QbQ+nE5E`FPZ&_B;F|-ya zKW>%qg`JO;&mvKVW>=t4SB=$KIibp;_}lL_8U*yco3ff5Q6S*`=4n3 zw-C9c`R||vSi>v+pkFaoNn4u%vr!9;hZMYpSkW(w6}=}Dw8)07!?6b&Npr5big#gV!y+3a`bAmX@VTmoJYmR7-8IWi$&t#AQ+d5bWS0iG*&T5a!|G`<${NahuyJ=s9Uweh8(2 zdz}k4xgP-qt>?Mk)DXctZt(s30pGVCtzrqU>}H;;vap1XzI)wp$)Qtq$vDw^N@MRQrOT_);Dg1f z{w|iGlp+0mbKhY4*VQjRoTQXjQSzNbC*YUH{rhfGO|#d6bgY*Ttp#nT_Sd4gcCIX4 zwx;$;mT{=*{C8Y5OgIduK9-pJ)eBt`yPPDiEtB<{ADQCj3P7&B7Dj%MYa!PSePA3M zVWT-=+&J-5(I1x^rv^D8A%woQ>=%uymN{T8<^h?R=*XNm^cs!V^}W zJmxqSJe-Tp)^nA*Iam}gb?+T~X~A2%MJi%iOwo1hkDq{|NoZKht`*_Et-10p!Co>Dpwj3SGCUiFwCoAQuhK=>! z)b||0&J8qKmTu1#Qh)BaO-`+_J9)upT^ICNv<{8}?TR9pl*0}tUs1>wMTye!&G@le zUT%}#sq9HiWj3Ih>b9czS&JJHef_$ ztslAJ@Vv;&Rrh+|pzg{{SM-{YS9R*k=bLDYRJA@&?@9SCk-7NuPt&JIR0qR7VN$Z@ z!M&j#=T$?(2K2$2#uQnPw zd^Q(Xb+4Yz>te0Jc2|@p+}J$sJaP3gHJGk2O!iQno*I}MDec!|=$e0Av~%UZc*}|R zlLM!hLg5;#By8AVEp$X}x+bI#J9gi{&K<4W{$q+(m1yti*6n_|;@8xan~93)${lTf z*<^{)!b8Pvo(t^HX7j~h2+4HIE zvGIb)Y}v;BVr-fk&QmBFkUd6^_|bWIvEx z88$7R&KyedZ>%30clTXxHC=@2pHuP7Hi}yMCLb!HBroMoLOOk0bz^rPZN;s}&wKel zj+0{@uCeGuP!Z&ed`4qYV~-I`z4~wu+hV-F(R?93L@xPEgkRa~g_lNHac052JB=&Hmr+PVVb$JoUDB)b*`r52XFbn$hCEF#cJ{Vbt2${EZol)2@(J@%>dc1n z+P`CK$(^EbN~TCHvDm33Sx&fTVfb0E#ZtZh9-UnB73h4KNk1mJV|U|vvdRGsZ~xva ziWLq2ovWR>#c*%&mBlb!`cwhrZ$ccSh{lLs?>IIT7uQg#GCEWEKR-`%zgcGAEV^zG z^ySdbrCJGiRhr!Nuug9|<60p+3Xku_Y|?4g)$$F+a(|I1SttF&ygmpJxM@XBanGBY z9JqTi<+!{Tc<}LY6O*#jB_dhsB;hAb?T29TEZ5Nt$5@Z!(N^}r%-wjxMo6Q9-VS+HMTUI-dO(EI% z*y$v60uWdtg-8hcy?LnJ%m%iXZg4$`=@Ge=<-Zsxt6$`)xJlKD%gir-zPVT{epG+? zA#V0d|2G<)1HZ|`yPobp`j_*wJ>+O&bc&v8?9(Kv96XCQL~$f<17{wJ9x=Hr{}1-w z0xHVreHZ;^96}Hz1Oz3NkVcS@9usMlZlsYE=^Si9Lb^ea?ixB25dmqWhElqbu9>+X zsK3APKWE)@*SdF|yVha35N3A0`+48}?sxBR@8`?hGnT4W3R4jVgT3Z~A`@64LH`Sn z;glLr+^?$GU!qYJdzXeOBQ+y}3vIWaZKe(r1OYZbF zrl%UQxKH1k%q(S*csKJcD7DGZ06SC|r$Q8JAd2Ov+4tu2S}@iNC#Z9^ zrDZ9oa~B$CnAS9&HggH?gEBLIp8yv5_e(qWI zhsIjw&d2wCQ(*gqOtqMTyynu43c&kf;_5*h-WZj`5EKDN`T_InZ!Go8SEl*&^gBMa zjmGuR(eXRf;q&01&!$SEh~6AsgqP0-kILkI8CfVM_`Lq?N+tJLT0*(t3S~1?{oBuB z0ulh^;{x~Lcsly?(YnCqtJSB9UW%y;Zb53VhrMg6A7oM8BOZMis)K!@FP%qcL#1gt z_=S!c)o%HIOH&(h+Pdv_>D7XX$ffw$^^nSU`(9MPz z4-`=(7N1GxwYb5bWkEF~-z)W94;?k{I30%#+a2HdRC1x#zKEZH28~wTc4%N-AC%e@ zSMb`-SbnUPawhHupoD8I=mVF4ZqkgcD+3`5i;vSVX2@|?fiCg(7VXTPFS_`r2b78ZKtB=d))?57YS=8RiA^?U6;x&?V1frUY*M$n6 zFmh@_Hlh6ec)Db1Bt?!?o5WPNeUC(=a85fN(xKJNHi-1uUHi6C>Fkx83Bpri!h8AG z2=z%Vzp}%Dps<(J_$v3{qtqA0pmuGu>R*YU-CePZN^+K}^q8-r_oeM!=Jwn%!m=%o zx=IquI^(H+-r0;^U5-P`3mZhBeaqC;D8Nk>{6|;cf}1}J=irTZ9x10?WWl4i^X>KZ z!}tyhIGMrEdR|;~OxUBh`1WfoQC$C ztgTP8W-LHAXU2To2o`n;b0>RbPp_W_WDw2lq^$Sg*qH$~1bJZfJzS!TojYC|PkWm_ z3FEZwcDNQU=i*tZPc=WONuxq{hi+U_ zN<`2u&kYtjY)mcn^5$xy=LVWEjefs?&$?h&=oX-a_LL(eh1cD$^IF#T{1`alKm=Qu z@rw(%bVn)?TzBMNM_cm213Q8Us2Bj&p&$Y9u}m0#e+D988k#>JXc(b|Ju`PrNy2>y z=YF={!rX0uq>?-N6S#~1$VWtcTFy5WAjM+m0>QSRC;okH)Ta6;=Wmvi>^t^O@|hPzc0X9}iQabfvUJbdRJRniRE@I! zUffdtDuMagE^+p^%`D@r4b`rIB!OhdVZQ1ut%Ry@x0P45S*w!Pw=i}qtPiJ)$M)B? z2Dt8ge9<+nZZ#Co-zPx1jw;d(D{Px#rH-Y&NSxc4u;e{hHI}dMR6m%4VMt)6G%sDQ z^1|ECo8I-eH12eNVm#1%r?A8##HznoFFIOq-ox|W{aeZFOWzgU=IVW4o~2_ZK$jQA z)?BByz6QU}7orPSjBo?PaVx`ALQ1(Wtcdo%G>TiWh!UR&dF6G}YjcIia5z{-EgoQy z_il-$GVb)AZMkA!#Ua++#%?Wu@(+-}aPTeEnb!<7w`Fj-Et0y<=4K(YoROy=oF_PU0<5`l_yj+$)fuuuGV=qxq2-A z!@5oh#ieoskLiUC0_#6SEQJnk%-oQ-PNi$J+<3!gg{8C{{4R@?H2US>>b1MJ`tvQ- zWSC~&*VU5Uai&1ykM#McHl%JJkVFQR8U;bYPm?i&?SAiI!BFu8cHHVrqhF)mS-F(vN6VJ4U4D-i>a^YN1gbspn^xU241r}uGnQ^BxsZJ#n&e0v{lzb_OJ?!FOJyP?e7ReYy=;=^+6Wudtj4o*+MJPj^m7A<+) zg`t0=UBY-@ABwo=a4HO*2!rl6dNgD*+wYuJ2oa?#)6-(Kf8UebKEkEH{c*O?4NWlo zL&daF9crDXI(W&lQtzj)b}e@VW{ym=#4D`ZK84db4cE(VtHgf5wq^v;{7GL(gn_i5H-U)w%ASea8Z3 zcxh#*&2iSv1t-& zZ87plvX9n`SB|XV{dC}~Wy-fN3`qQ`3&$a0l><>geQ2MnT}t)aC`ZQ-YHQ*|UBZ&!Q z@1s?%S1xuV!enyJIa%ks%{=nauzmRsCc$NK7HRjKu%Gt~VKXIX43E$Z`PR=^(2@iU z^H^TXx{W>;AAj)uUJnQ$*)W`$1pi9no>%#Df&SME%lnK&1ecLL3Go&3YIC}f$C3mF zHwIKo^|-Z->@Jz+=GA38o3$|Vh|~C0@(&8kMDrUq>a;%8iw5I*8vJDZ&v)u$}p+HbX z4iOA6NjANOe@?xQ4zW5vs!QRALa$ovcq(G`kXHW7C1;#2jr*V7=S*Ocs#qZ075O>q zXLcLIim0YCF!Mz7Ht8aOx?$g7{M&cya(BTUw8qS-4sQ~tth0?XU=`i zANuPhWt%ly;6UHP&P!p0Y`!lcYXWOlT}n-olBf#E9$NURxdQA6gTou9Ym~`nw}9qTI@=2D>hLKK-%aJpEzB z==@?YQD-v1Bm{v1LRVxikx)bSOg!4_zds2OCeN;Zzx1LMOS-ex_OSwWY1KWUT=aTI z=1c7R8=4pC&Wc4c0&SzBP{53x;Ifh{r1HDP)R4MKO-*Cn7gKbHJdAzVC5do55z{0*|Gg zwy_%nc};`w1v6=SIzo4Ut2suo zd5Y@-yH=pR^^i?QOr?wIge~5BLg?NQ$}OO(xqE@Rh!Gq5o2~0tG{$a7YejA?-PCXeqs#++RVWp zm2XizP*JFgB%FTfzp_?`{89I;Udy_xtE zO1Lieq^qkUa!9?_!+QO!Kh=0;5eqK*p>s>n5DXs}ie-HPzk{<7IQX=o>3aLc=Ocr~ z%-3lKeq4{ez=J!|JC$mfo%&&Z3?CuN^G7q0brnQeCiA_m6ezD0!J(eQk_RzPBe~V3 z2H?(r+vK=Teg^X{1fYUcc-Mms3cv(8_zAQ;)Njh3IQi{B@kM zky|ieNiFnt;$`S&?2c+y$OS+JCLZW-^X8+4uUItsUeZN~-7bf2@7HYT5^QUTFpDC6AK;=vVQKL*^jz1ox-03_7k#%m8Bs~!> zYq`E$o6B%E=5C^LqWCHg=Ti2g20VO#eFR74@N7t;22|(N8229uz$a!tuL((jGG~(C zKp!03xXfJ#LPLA|w~+s{ENs9Q@nyiSG>PfpxB&b!j?0BacRWyjQ1*ip9t=OB2Y@jA zmipk}z-^sG-O+eyd+-5>-IJtqhsDmo%J4g?Lw>95;9(xgV~7Ie|5hA3SY7qABZYF0 zw}q$#hD2ZgcE$(i7D%bgZ3A6!7*)if2z*Ce)f)$Ju*xBnfhDisnmzd9b=iRp9Ycfk zcvr!e|E>By)!1eDG#!XWY7)a?w|a1{L;qtj|LgU-PzN1@@IdiLAVfI-H+24+cn6Rk zMF-rSJFF(_lMJ%-P0u-`Z!lMmVq0d8E$6_TCNC(n688b_vgDxtC{zk_TrF?3MA-j` zj;6_29!Lv~F&I8jvL*~12yJqpVW=uKZT6-<4d z@$G=RYN`Y660i?Y&ME_!#djAN#P^7~)BQOQP8+Id9gHGz&^sN-(c5~VYLd~F5k40> zfVf|IuIKLIsW*164x3l}(h8tgQjmK=^+>OFNL%_`ZM0V$Zop8<%F9Ar&`1-XLanXc zS_GP;!D;(V#>!2u41gh63Mh76+zmAC39TozWwksQ6YQ*YpgsLM{adIi?g}X&`=LNd z37=KksSkaKhd3o6hr-JctT4fyJwc<-dMbmo8D_PX*Cx=C%Am^4$OtP?4&>S})sQ^E zi4PJFn^BNG=z^UzRs``>T_uU4|9w%Dl!w-%c^a8w95p|%tD$NLKVaDNuwCwQlO3H5 z3tKK1@f0l|TF8vJIY>_5V$2LNpa25-v3lbt8iY{pn zw&pt>bQ^Zy1OjL_s^7WG8Y*=W0+;t>;Pgt%${h@oD}-K`Ze3YeROB3(Ca!l5ZQ6^w z>=^6B8pX?TmqGfV;0S7C=?AR~4=IQ^KFt~A>zB(lz8}yjZ;hQnF zpp7Cm?~*5<-B*nQSIU&WS#5l-0m*(|(M2g>j7jzqcyN~)^lIe}6>W^b%-sF10%Ukj zp~=9-Spkn=I@3T8{6tDx#|2TBw+q-#j!A@aUeE@|R0~aY_`|gdlddYq5cQ;2n9RH^ z+jTv*p`v!UZQ7`!Gp3|uL+_e37cwO8J2u5@X?~q%*(Xjg?=DuzvAGPBwUGb#!%IV&o!FBG+P3{K!0CSS7rj1+EoS)>f1f5YZM|nUI z)|4jHT9VUumY-GxRW=p&6kNX0X$igiWd7lunE_Vlccwbf;g2wZ4xe2{+MQ|TXtH9!50AZJ4+qtxagPD;)AirQYQc` ztsj`j9gcxwr;O|vbd|HEPN$j{GY3uU3xsM{2>&UcX8hvEZr`cnfx4*7G92|PkGv70 zItxT%rZ|VedVttj2J=r>q4*P5>XH$|)d$|iSIho;OrUI*#JyMUYNxWD2n>Ge?TQ%E zDUvEZ1dpArl8o7Aic*5}qUwEFq=0pJN;^h>?w#-*UB_&7wb71SF9V~<<^`2p!P6G8 zaQ6$&8s&4K`;-Yw915--;mo1IUy(!PmKm}9V*i-q;nTMz^_cwfB*kL5@Usq;0XDRpJn`b_RiqEx5kG&gJ&*o0 zu)3BBzVh;ke)x2*_!6cujr5NjfuK^nw%sz7?up`L^^D zI594%y<;6HG^wt7vL!S*Kp)T0GUC>irCj1QyEu$5P~ymEwLWpLU->i`7a@UC$W))? z#tucAg9=QLJBBfDWYv|L|1o`(!+Hasam2HAbHtY?0!}2HHH|o&kp=2dZLJ#PifIOVR4mka|iz)#cV;3cr!w{eY!y z{WS^HI`J#k52VRX?;h4)aa3de{@Hrmg1qZ)wf$^&S7VOSZt?nK?`I!pokAx{ywR%B znLB`8OC#i`H_)`WQ6q?moKSx1h6D&pW_aI>nx0h0sz~8UgOy9mi7}bGw+$57n4@ z$3fQFPBXlW@985oBpElY^nOEZu z6=<1iuAm@fVi(;Dh+fk_SX6X^R{LfN10P>}v=@(lX%4@7d+x&CJ!{=+=i)?Ut^y7C z2zoGD#KK~b$vWfKdh0GCDYbPzMRQpuzn$xX`g~P*9S!y2>FL+`;C9h-(N~$j4}mMO z`@DJ7_&mJrd;E7dWrzST{ zE&tzWc8>AB-)mLF6$^FQ`h01W@UV?SS zs77tJWIO%YbHDtYymn80TsF+FBGO*%n?37Ju8jRPzhujUzE&oe>RJxI3*l*n{ zn<$kZR^4bv9Lb_^`IvWtG&&7V8!Kj}+AQ7R$*27d|2hCoVM}^UNY0h#_ z@)X^6#x^Uz6_LuLtT{^Hc5bEfU-RYchH2|*Up$@PNW}{$;tq)((vum@%72F|2ddF=HsZ4GeH@P{>e@egLIx1-}utkC*)K~&Tp?G2wOh@6{)PrYkxr@! zpFE)r18U!@`^ooKZQFo~N>1%u$1yG$j}=-&5h;Q#*Q0@};xN^H9LZ|D0SbgwrH{$AAkMG3lMXY76V-> z`1I(xq0yz^pMG+|0g`1*^5)-G!2=i#UvB>X^jRA;*b%hU;_u5j_{?BlU;jUMC|{R? zwq3OsICyB=3?wpO-g6fS|M+lQa2U93(U%+!131Hh17Q`U{C#bRVFVQZ*OKI;z~8e0 zE0|Zw>ZGG58U>&yrh5=B{qGs02pk~ieYo)-&p`4z3tof+$Un{z-}rk^Rtc(o8n{{h z*RvE*u0X-_{cy-@4`gURIo=oEe(d1`K8g0?uL%wge9{ zt8%WyB3ni0mhk{Z)yGB_f8tks2YiR6Wi&8$+W0Vl1>?{;ocMKZjq$TH(>kr>(D5?| z$C1D);2Zea-&4=@4n2}z4Fvk_%v1~*|K43pXZNYKu&j!!Enz9GsrZq#bXGinA5meK{2VvtHsI?W<~Q?q0G_r2xUX&yqXW{_EZ*sf&(wSNU40 z8qO);LTxMN*5A%$lJ(mx&ig+G036K&E&wc@7>)r~3Bn-WR8$WBH`g{{b~nr0o+`Hf z&~-+@T4Zh00P^SlDx9Gg>TI!Cxv-xj0A6mjibn4yq?C952UAczo+X<+X{8Kkd_=2$ zdQ>tn`{3;#=P&7lSJI4H+|Qu~_wV}GrK8gvVOoXU4$RgHB zABZRW&jr{S0-bEtd8cXH@5@W)5Tl=&MLN{iK4M@Jzs(iS@BmtBZk_u$=UodM;H|qM zvZCG!gVf+B{FeXrtugDIFJ955?o-~#xk+-MUt~cXl4nk5_+K`3aQ)glajI`E<4ubI z@Nt8y=bfU3%~=KG^M{lF!49C^I~(CV5QCl#8iYZX>D)b@)=iIxf8keA7&9GSFRizd zkOK@*1=ECqeN_?ue=hpN6BnS0GnDOJR?hR2ajVt13}rsJwB?FxzdpV>^IN+JcoWXT zj+oS=5fUfa7ccQIIy z{~mbXdaRYlfpBL8C&n)O5>x`x^ z`A-|?RO{My=syfRMI?R5cZL`bx)do?$*w6xZ+%liSo|@Epi;!J>(;~8tTjEpMrgws z!0MV4$0zaV#cBv;#<_8tQ@TXIMe?~#(C>*cdo-f6&>LZo=UJ%Mt0#9gy+6#<^LJG$ zoJ3<&r>%<2`EqSc#I z{kyCujG;eZM`V?wl|um435c@)8M|QI?}QhJzK%(s>T5oIAKa(^=rm9Qk?iz%WOw<` zMR2BjW9@^zegf_3w`2S^7!p0^Yv5G*=4SM*n+pi1)<5zDGpxK7TxDu)G|&CoHX6j? z2&+TV%59D%$_k(?iCSE>E^FZZ@d>Oci0Yax_SSbU4qhryfZju$cKazv-9WdXIPvGA zdL%)1w;Sq(r;s`Kyf9{|Dv1)<-Y7{1q|7DM*BS-3y8gId24bkSR?`&$6qlzn$PXfH z&z1>+lRUzs6_zimwwkePy-2MDJG5B%2iQWnkfJ4$aBr!nO6AE1<%>`RL!xf+wgkwD zF?O%jN%RN&Z)cj>^7Vu^6SDXCg?Cy@~qwBrS`Kq^oM0C)#f&0%O!m?NY^v)XU^g}P( ztJOBEVy^>x>Q@jc&#g;xdI!WS|GfT1_=E!HgaYP-0_KDQ=7a*~gaYP-0_JxBbwUAi zLIHEQNIzk~IUxW#bP50e;y*f}fH~oZ`QJ^Fb3y@gLIHC^0dqnDb3y@gLIHC^0dqnD zb3y@gLIHC^0dqnDb3y@gLIHC^0dqnDb3y@gLIHC^0dqnDb3y@gLIHC^0dqnDb3y@g zLIHC^0ds^!=Y#_0gaYP-0_KDQ=7a*~gaYP-0_KDQ=7a*~gaYP-0_KDQ=6}jOb3y@g zLIHC^0Ruq)&tjZ8p@2D|fH~p1Ibf_fA@w=9m2|>hbUC{X<6MzN(!2rDT7xAKiQ)H3~ z8Ea*YZM4=+h@y#^>LuSzQDScm}5kq@31SJzq+2lb8oC}4gG zP?57qDk!L41so$I(nGT9o728mm;V?qhraw>CjvO@7@2q-AdG760GXnE#wSGnlLB>& zbVC5A4VpW60YG$oLh0WWb1+4{x#JQ5@EuDr`!_`aEJGrxZ~>ImG4goIX*>x9Weo;U zwj(KWuK;`oIUNhp;|a2_0ld@ash|J}IWgGC8R`o#0KlcCC3pc)k+SefNGt1^*|{QK z2ZYDGPtD9NC@MiZfk_}Z^4jK(K5ruuGYcy}HMRE)43GVs2nCaHiAX8VU!=dx%*w&V z!^bZuBrGB-CMJI60Q=wglV9T}0P*L08*mZCA6M{g03!j;A^r@kWMHqTIOswA4Se4Q z1irfmc!bG0L`H=_Ah3vzi*us^@mF$r8{pz33a0pnx%)=Pc*MSX8W)FvfVdpg3F7Y& z7RC#lc8!TKJOyaQ#j*Y;1?my@80@B8ObinMu*bz+|2O3!m~uNN<~#r}9!oL!H$@06 z!}&IV4V2U)>`02>OW-ucn*bkI7Erb$DFPt=w|xWONgYq%2k|FiVL0^%|I_5;r@&D} zPLBHmAd|7Nv$ucZ=;Y+=;_Bw+?&0C->Ei|52UBzpun7td2@MO6h>VJkiHVK%i33c* zcP5-?W=60et{_;SvOQx5F8mkhbc%{3Am|GH1Dqh}1giZ5g2Z^hnX@<$ZqWl%Iy8D{ zWPd+mfW#7f#gJ_V3f1RG5}7-p`il<{#^!4@dr~3hlUsdfcIF+ z+kaE!z%sY{2P8pBk*FgnvLNV}x(7ZMi-58nNs$3Tx9Axdu>5ZcAn4R0S787(?K!X! zVp>|*q0yfP0d&a8d6xS$?`1w<4}J>DKoDIx+I0+0@iNc!IG2cY`EKS6(j3;yz^<#-1Ef;<7eB9Pm5aTfe=+eAa!R9+rn z2mi(gAg?SA3qZh6G~f>aoJxcMpb-EN@E?!}{hJB{5>Nft-v=4Hhv#Sk01g~b9lAgk zhVf!)RjYxqkRS!8kRRB03~QyiZsjb&E3$-BoQ!vmXcBLD~#hEKu(M*u!P_}^aRwd#9}S^74Yh<)AM-~2uHtuH9RyJ6 zv9YE|mWFjDxh*b*rq!xQIeAJFzS4I^= zsVKt=*I%nouL}t%!GXk@{wCWk=hw5Xyo+SY_CFGazSv#{MgA*0{2fkkC63HTM9j}s zf8JI$zI%+j+(1yx>T`_=I^IRvZXezpvXD3b$$#*N8)YP|GqW?U4sG`&ulV^8HWLU0 z;Q$x%ZKx7Tb#5rOmeXN;dZfsyb1s~8Thoykl5TH2jhFT8Fr9QY#JZ7VPNY!zm?Tr` zM6Xvk>Bl3OhT_BrOzKj0H}En$pDu1Rra>V5dNJ?)0|w6e&!$H@EsVYg-<$PsSNx%Y zpU1t)yIpy!Rg5%Wi0S}|wzn`ZBNvT$X(_uSYiKW1{q6Q)e|n@19&&CCMtV_qCm71~ z%FB|H05jC)8bceHNQKvIJ30wRIsq%ZvSMu2)ov*B6ryazx52;wbkLfXm(4Qr#+~b? z8Fog2?D+pQKz;6>1XrXOot>JTqDj7|ylpU07kufS-du#vx;KBSNrV;h-ws2dTuk{4 zNCDS}W6p*ZX)gwKw^9j!=lKs*FjjI+IT*${?p)|!i#u$_{5gEJ1i@h_B9K~n;r_$k zc~*PCpyB%UCfj{Uitex3XG1qh{{^TH0UP{zKjO24j9egb`t#U}DxU$ky*qZ=NQ9TA zba#5u<|cRlT6zYp{m&Q;-2_wJ zjUMf=?GPJgDM+JgDZ5*FbLfxb_JJ+mgLC0&WShT*iX4}C$s8ll#D$%1TyG2S?Q{88 zi6rI}J`>!CXGYQe>_oX%W*j4se8+{`t9S2GVZ)Lw;*JP0$DFUqd3{Hwu5wQGMsN`*YL4S` zso))6V7k zq*cR4#?Jh2w;|9HLZ-mMEBd%Dmr_M7dAO^|3dw+eHm6xzUVrI4OPPNiH>fvx(tCPk z*nr4*KelT(5S$=MYXF0K!-Np_s3(O$%SrA%1)8QI^!~FL&h_+x1jx|!%S^U=Tc2t< zV~GZj%3wkGEf9x=2XEhU5NE5j$`ls}R@`SEy{A)B>mQzQ#9Z);gX&`Yd(nm!$S7+Y zHGsjj1zT%0m>w0U4!$b&-_dIxR9CFgZo@l_O5Ckb4XKLD@9ci9@gu>={@19v>&6j< z!HZzweiT=DYW0&fiOd}UhVt>Tg-9n0wO8L|k7yqj&6Mw!EwuAud&ab9bOxv^HM%0% z@irhc|eU4*Co;6*+Z*LS26Xz=~GX zQB&^Lg#ls5BjN!*ZwVGIqBfM|&hlq^`fn4|5fof2Z7kMH7D=Hy(rJbcDD;})1!v!k zOE(a1wWk=^u%9Az_N8FQOoWyEo*wRYT4Xp6O0BfP4G*Xx)2^`{*2*(DR^1@bwsS`=`4Lwo&7sv90P&5sYnM>8t%__P{+Y;SZht7gB~oYN-?1f!^y0xaSp<^EL) zI5)tTq1VQjgg&p|TOPozDb=fu!&+E%iJYi=#J~A5@=I@WLGzIT4uJ|&nfswp0;$?vOJ;+C zz&?{;M}zlZ@&~aaJz@2Q+s9#IB44Hr|KLCH_<~FG7DC|r#r_SN;E4uMjxQMQ*R#9) zdvU#>C)CE$zqZ)mzmUdxq&5a6B_G#htl)U0vl#Rks6>=S1sTuNM=?c=2|)>3ej3VTY``Qp)WJX2fOx99ye zm=V_=uP*b~N}~}?$%pf@NA-b#pMq_^b<`0Gay!VzR&W`ts?+Jr(W=tr$JTx5Mn*y7 zjKGM~bg%fR&0IewQzDB`>6hd^v}PS<1hP`D@x~7u{iW&S(dNKRA$ax<-ry{JNo~bJ zE*bB^JEJ280&27e=H$yf+?&v~`vkA9pum6%i|!0N25FDfST~vrndb~Jm7*1W*><3a zqX8g3iFt0_Ck^ynUh&R8({)ghTa8fg{m81S5=RAB()Tej{FShvNa0z1YAjb{Mi9-W zaUAf(Txhr9Y*r(GGEd3+Br#&q=ms}tFNy8!QJl+B0Mw>C;DYG6RXlI6qIqwWX- zC8D^VnODNKNQ#)q!L~Pq-lq6(!+aAKT)DZdsZ|v2gje^l0HDIkDiMwbPaT@KB6LeeMi8M zAO;rU^s26_x%60bB4C?o7hhlpp-gQGc= zTzn>Y5fnz5y8?(u&OkQVHCuHTLExB`mB4}<0jI@`rteT-@AEhDVd@TLVdPPXA<$N; z{?arS6+&P=vOMjk)s>@D42ZU$bYLMic;eWaw(&kQVk5% zZhag3S^J<#0UY?Ms^gDo3jtKCq(4V5kf;v7F!b#J2nGvg? zmACLThI(An*5>sI(MZ%9w2bKg?8HEFr5TF#RKBsZ4 zn>lP9i!`-jK)#XXrgYZPl7J6^PaH?@Emy!Gra7+ncw+du{>w{7J-ol4E%K*q^}&;xQtJmC58#eH=NX)Ki(!cOeAk71gP8opB40S22{F^ zYj}qgT*`QTd7yZ-DR>}s37C2J zxIkVpKC%mNVD=La3^cm3z>XILwQ$d!J311;MfljoWA=|jGE=rT$_U_`x6nNjcKF;R zbif6~ph`1q@aZF#$1n|z3k1$Ixk@<(9<_*bnu*r{C1aT9F&lqDa&H7;a4aH+*>f`h zL2Hm+@uMCl2p=D~e)bqv5Eu*~xcar?=#mEfGWOI_B_#q-DA*a}qn&|(U$z|sLkR$P zVxVUVxyg<~0s*Fv_KJiRfdJqTTurJYFo0hoo*Xl+b8v7M33!(6cT^}iP$ztBWDqnl|3eLt0IYQk^OujxPXgExAGLZPD2UuSgCNIuN970M#5;lWF9J9uCvcuv z=U)U)2KztG@5FbW_|E?_hm)!3->LazWFKvR zuFvxKQ{A6mHCH;XlCnIBYK{oW4x68RrM{#+=w{|>Lft|s>bEqHY+Drx)G1c-^4PI= zMK&)E_fpwLip{pIG?P1r(m(oVCF~Om2J{og430+c>c%eB*MCVUyLyJY#G~=$D&cUK zJs*$00-sZMqofQdjS?g(;aMh^!TGPXScY^Gh#z+wtiBfZ)Uo~DYYxDD_LsOmS zcZs@c`e_g?*+KeW0|DPy4-PP_-TL5Tak^NYjdeh+rrM*N&)s`1oPKnpKexm|SKC3Q z#JVYdlU+2^YL4~8;N~Ng+qa>DdisBAnYaVi!o!$BuZokYyTXE!$#77Ts`33cnHAO& zHZLsVI8734@X@xU8%2%lSuQ zaOrhY^$8$<&F92IPKL~%(E0ypAM#RV)QaPeM@Mam za^!4}zsAUErG0+tTO4g_s|QzVUwzMP-ph<@dW6d3tHsw9k<4pM32)$PICqKZsns-` zUR-rr@4w28v3lz#$SbzF!_HyUXdD{&B zbd_Ml=rDDE6E6Dn>BU<8(=zL+*eF_5YI`&ti(<@0y*P}PT;5CdRK?SIa_-Dky#*2} zjJ8sDy-65?EWw>bowIpuhYy>4b_tlMHnJ2nII@vlgAc>5>wA70q@8a<7PRE_KPJ^5 zc{-6)!ym?T1?8r_Y(1J}#PNhPlewJLZE}OEel1UoTrYB8&c$n0`Nxa0eUHY~ZrU49 z?+Bx%6D6Sa<9GIGIC4pQ-%65O%4=L}>wCLaB684oKuJPXGK6Y!##-N%y2;*qO(9B< zS&Y_OkfnOv*o80E7}L|D==d$IJzh_<$`K0FQUPbQJ9r93hg+KPWSn5aU825`%c)%T zxYAmdepkH~o^!X(wBM16I5l4!yg%hI`76u$gSF5|MsoP7phALxfSkwF`<1WCTd$;y zWTx617;d<`yT@sL=&vF;L&Kjw{>iJTM368huiCZWDyOynZkFviHJZu?`$XvABAccM zNTx45LJ~|Cs14+7Z$8uYtG^nqd_w=49*>vaYH(0=;lsrPAIufUgFCPD{!x^NkB)pQ z2$`rjE%T6%`%Q~5}XZo0noIg^sXWhL&Q{Y|e*BIJBo$EcXz!WAk^@^~@_t#Y!$*eY%qSDLOT z+x7hVyC`R;<&Evv@@(hr+CRA0>naY>rhb+p1cfrzX4u)g@mdsR^uZBLa$eBsd;a&P zJ}2R%efp1G_9d>3$ZaVL{Rj6-CcBWvdNo7Jn6^dUwO}J$M>eo5h{CW}&{^^9z`*uPdMGg_tYBCeFzjyqIKpZY?;RGM*$Eb!EOuWmh!y^Zgn< z%vR%rwQvFrF&>_@)&7x9)hXR#J=f1aWqxM&3bF)}ie2ov(mtCO=oksF0)IJWQ-&*n_usJBs>(a*SFakOi)uOi7AIy`(94at{eyu5ILXvyz?y-+R}l_aUo2TEk@Q` zF|?us<+d|QFOAUyd!-|$$g!N{#v!ZyK-1PbTkMg=ymUsfB24=qA(RrV- z=C*Zna5LxRU4wz`q-tHEQLcrHJewhYm<=_}yv7>Uc%fl05=#03F8w=isu!27_3!YC ztLjJP7*$J7h7-)R@Ln5lZ{j*TN@G)oeHnm2Na4!3O~ImBz$1$MZWMj;aKM1ndX|2w zOKd<(D_4*Q+g<>`hZPiY$iKd=d;U1<)i82YQg54{q*v1@q^*`-hKLg_-Wjp6S}Pg6 zUrmcb)ifLJg*bN>gh?@JQ^{AC6s)GFs|G;Qt&)Zbbd4~*_N2}?XJX@(b>nZfsxBa%d0`p5yEBZA<1$xN$ zRt4AecaZVT`YKDou_-BC9-SCwsfdJ1StPe+rjw3^wuN5vaJQSbyLQ=B1>vW#zIgTK z!Qi!bze=Or7hIHF)`;<5`uCv(y=-iy10y)O=Cr(fTYP7)mz5g1qarTq)YN*E+v{&^ zG&2V4_@#~vYPj}v^~#!rPfhMjH`I#S)=caFXvXfRj4uJDk`bYW;)>k6TfS6i+dTVD z{gKtxf+fcT_1!p7U*VzpY!wS*UsR1ynq9veQAJd<+B%&AJZELu6u*0gM>$V`>8lY_lZ~n5V^?~+If=;&6J{Rs;Kab5pud)T$&tQVN=7a;mhf)Y1$*kw_;^pg--b) zxd-&DJ#TmfY(%zOQPgG)yS01fRdk6wtQD6yzvD zxX^%-;D(y5?OyQZisiha!VgJ*G!PM5VV)u8y|Wsc!ShNsx0*r63B6q3vt7uqjD!VC z={k+9%m3&YK1=9sRjqzr&{(7NNoHZg(nu?;Afn#*hX9DM>{_Nd={0iU=yDbdFFO zh9I3&0hJVxE=B3?W`d-Y(m5sw(p`hG=M41o^ZR>V&+|7s=iFDnuedL6eS9ciAV9-( zy^;BYU%F)Ntk2C4 zHvG~^{F{FLaQZ&9@G1+I7-KL+b}=5g^(~x|c-`5_16IEQv-;(FWTXtYm|D0)7XQq~ zQQ@bRlsn42D*XA4Y zZcC=K@`qOxpx@=G-O)KRaL>jkHQV&DpC3dyJj>NHF8`h;OBPcXd*eMk&q!@cOH}CB z@{I`o)$1-#PlP-fbPdL1^J9f|3*A=$m5QqyJf?Tmninq0@PTbz-RMHG3khA@FB76F zsp@2kg)dX4%fJqu;q5Vd73~JK(_EV4nop-u&3PBTkEq@cxUx(TFn7nl>flb({))Si zUPc^a>~2Nh){v0M<#XRr6-P%c(kLJ6>fOfWW;pIJ&uQNRSI}U}z4OpCZ?}>vcy$v| z4D;DnJaoZguic%mB~#J!yK~TuNFz&|TptauBj|0w96MPZm#4o0A)W(S|Bu~nUmIED zue-yWbGU`h!C#~7Cj%xo*FUz@9gnr3jkoleRDQ+yy~UYp+}emQ*Coon>3F+-N?OP29xQUBD5Fh0 zWQL?J3~O^9){I)@$+nab``oav>D6JAt~-W(67W`^_*SZCABpVuXdk*Q%|7~WE#)~} z;waapMjfm(!+!6-Aq=Mm0H9)(8hNBE zmrVjCOMb22!IyVdK^A+G*L-k&@?^OB<=jXgRpi|OC=QSf20l-MFTL=kBR4{2z>(#% zk=O|8b&qdK&5@T*nBng=OR_@x-nA$NW>CvqVy&LIgbv+qVs-SM$<$eVoH<^zJYN^6 z&f)X8egh?=x%wj>LAtZEUD|n(B^buGU*?3;q<&Rq&N;JmFs2F&mSX8PfGlvchq>1CluC@o)L+1EV|)XvC%@;OB#oI{_J40)#?>#b6`O@IX|U?uE4CoqclH}Wz}IhZ~|~+qN7{G zngpL7J<(535GG)4YQBbkt)NCJ-8#{#dPuMAXeRGewI9Sb3omQ({nCk!J%V?@t?X9D zULR)UipPpr}j;o9V9Cjj2x=R|7RBc7fUrjx55L8CEnV|uEvh#yzhM?`2i`^y5-B2yh! z&T4BZ;4nW3C#eK0_5}WlPJS=igQnWZN?PE8(hOT&J#X^%FZsY-orz+Jl(o-Ud0&wo zMRG2V2j6-9F6!iMF{!Bch3!B7WGqR`ByVXXvHe=KIZeG$!oH$6R&pt!@Vv4vP$D!| z|BTPEplU=H4{4D%b*4momP6uRRjs*MtKD?XD+1dUm6{x=Qh-;=S_ph)uf!ehg~vp=J2ct}9c5`QlG>N84WqX-g-EmN_e0DM`q7K@`B%V_c zeAKV5PB@ldF`pOQX#wiwB`kWqPCV*Up!xwQBmy8)BgpJ*Kx5~Mi2d)5RJYHivYz3) z9W9OQa(jpYg|cb!$OlRn9*ZOP*LFW_ghcx>@`M`KIJ!Q`nPIy%cGc*j|8f&9oY*o) zfBeTCFiTP6qw3>1`9Srx{msZ@HoMDE&T}1{r-H{1$!0Hbfw+`HsnX=vbkPNHIr~M* zcNzU)!@?#9iT$~UE$8g)qYQ&DeWM`dW!q|X+IzDQJXhmShcE!9AT1j=)}os^nl_G# zdmq@1JdUv-ox1~wfw3i<4qpq^fFnM%ENu%czTG@p&q~?xH(Ty;%X4RpL45?juc}dJ zs(XC!Yr&sm`nk6O-GwYI|1uSj0z#j<@anDc7eD)8}v9 zU4 z-Q_vMLH5;cZD^cYjhKDYW_Sg|FAuOb(Y@Avo8yh_^}r$yH(TX3vFkK^AAy{bM#(r0 zpZcbwz&1?~r#w}6$}GRVDzg=5I?NOU@p)xP5G6B%8g7)jpwYqS zkd`I>!tb9s-n+{`AF~NWf{5g5_k&v$d5zEO7&#t;9y&20hUtM@Xj3Hv&UjyDosKLv zTWkP6;!%gY-+pp=aJvCa`RS219Z}T8oI2n>oQ~_{QD1c^>X&Z6JQo?d98PMIOy1c{ z3;xikK9&BC|K3dwucP*6(qNyQ&r(VC$*bKFSU%SMUb;K9BqB7{<;YzAeA<%>Fe;DV zg~4LAw!1Xei2!Q`erunO0Tx^l@fm%cm{iv@Ul&XlahL$i6LZsRsLpIuu`!2BAAGW{ zyHO>0=!yCMOrHA4J}u3i=?Rto%Um+8pv0hd)0KTW=X(dob#jI`o5CPlfZ|71(F}3m zIg%ZM?Eg?f1gab}kJw0vs5>b7Hp5r0IrG|Ao;_T0<5lmjfY6mH3~oi!3dpr4xk7pd zGGCDSEU~4Lpbq;N%@V$RyPyTF3IV{fM$Efm_0xCWPmf*L6*s_9qD485?lWD4jayy@ z^fO~tbXRH3->4yvS>w>+o*?6ixZgZHxKy1<=j5Inlt}tDlnl%4LVq|kT!j;$OdTu`YN)EJe6jfsd(E&29vlS|3I zKZ(qicdL4|>coPeHOLdVkGBMFz$*AVSF9k)J^`3kgn*nyW28=Rz3pCL>Uaoh|4N=J z?6b8J*{uq>D2UeqMyknQvSEdlw!X7%q0|dLC+=ng72-v;sC!_2+ELd5@j!W>wJNjY z_-FdIv6bhQ@l6x@d#CgG&}pKe-R%Nwr{Re_i~n}h)~kwbwG4k|+U)w2lW!a{vMbeN zg{ltd(oOLk`JHB@gS0&%VSNqJiXglfwHJA@pCd69^ zCpq}#Y{&-;X0h@1=EO=n`!h@BRIE6SbtW?MY0#^6zhnPIx6KrvrS*LEV=?>6J%$vD z_qX5nvN4c6Q8A6ad5eni>&*Lhf*ZF)5;dcN7pwYE;rla)%cK;`vvDA*Y1~2atlJU8 zn|m-(0THjc_>GK%VJv+dEayW3D=VQ{mj6zj*#Zv=(ciC@C*TgAD6Dcl=-I@v-21d~ zb#xN_TjL=ht@62I8!^1Y5K~AO76wn+XQVXWK4PB;ozIB|CN1;AVY254{OF_9H*VTW zZ8pHjj@F!@8M&I&h+5M6t9}(fN79Z1iwFl*^}d8%0Ic^@Wi5VUEd4W4?A~Q$$v1V9 zcDBQpkupLWiQ^B+fpURBai>92@IXZPg4J=4PeT^hKGx%4#!&w8x^0Ylx*50*-e`A# z2C&Z4t`k4F-mhzyBR@j1I3neelDB7*kUbZeroRcMcPiqZabR!j`PI-Tjoo#n`+ZsC zupYZ+*u?Gg9H;)gGkUK}ZepE7&UNFB4P%}RSd~%2DHz*g6Pz-><7N#495n=F``twV zPyB@k=~ciTfrS(CDeLw-p1%X~@Zj4ouPIO$*nA#>Tq6n} zUEbLEB0CMM8IwZ90wK^k;lmFNyggZ0B8xw8<=rydR-L{uy;y_Gy>-h{ozoLClcbbF zuftwtn;T~6Huu|U81PhF!MZrf`xQ3=X{ia0*(J@NOJEc_;WF6hamx0fZnAt4e8``bC+)Pt{D_Z29r$Bk!-FeyO~k`~ z#@yx{0Cz6j?2}ttFk5{;-1S`gW;paF0nRWd)0_oQ_4(|}8o)rm0&4eA#4qr8AX0=EQ*|NarBdTa91O3lOv<4XNY{SUzF6U#5n(pFKAG^5=ofh_ajrJSZF zGZjz&TX0fg$^8TLBP*{3MSdz1#DoAyW9G{UP-!JO|2qwO$OdXL7n#Wj_8;&+#whW* zpCeK`oLMv*+RUTQe#+mb4)a_1&Ea;q^DBVN`86rxA_rV_M@U<(U>BjkbFP0 zmqqc!QYfd(fSfi6cwcGj7+67nNxX)}LZagKQ}*7i2hIHoz^15494JNpEKsn6wRfm+Mu1y_D9Gg{G5I1s*87aD^CeA~!EvC!S|ICZppM7T zloyyT;#}hDSC2Oo)Tq8um}DYu=DmetiNfU%T+CXAj`j?@NiB5A(&TqyFyap=AqICj zYY1l^uFK^p8ssG?0=KvMwtg>5;|T>4yo2ILX2Gj_dCvexNjF1`5lB7PiFt}{$|O6XeMQ?*{3nv?{OD2YI3cv04&46uD<;AmQNy|i0xqf zMk=BF#8-ywM5r&(En~awjS|A}^@=F>Rm^npGDF>dV!Ikx@q+RT3wfC(Z?o24ZHy&H zn90ikje<8c67S<_>|s>)J8Jszsv;3}UXW8m2@$b&v{~F*Yp7dr>CgcA1_-xHaxA3h zNz9s^`GYi3%T`}&B8>qvSP2h{Jw>l=kSKRhJjt9fr)QJmmJQN&z2@NfNR6~pmk`L> zcLba^)Yd7a9qJYOm{%_K-vu7!`I(o9w;(`lk@Se$PbtSddQ@AEP(OC_K+=x24@X@l zs$zeYDhEJsBIX_iz}fu9AEUA!t?EsX3>re^LOqBjf zXCh_g&JRa0iha&Gc0~NRp zHmdR6NT(HP^$uIQiV&zJQEb@l@**}bXUmB!vsS#q&sQ(sJR=#Jt`3GB_E$AKXT+{+ zngCk>eqSp_u}rhOP1wg3vJ?Pb2QXf`P3_Y>4*!W-=++%kAi*PKJZS!sM(G!RZf&9C zEcw^E_~)gkty?LgN`3d`jY@~BsFfs+YtyJ6%|4 z6_hw7P*6lU@t;9-=rWmoZ5t0dV0GVaiptvae`5Wqr3CZK11$<{$ez}iu8!lclK0Cm zyB-J)JxYx05|+>ONh^ZACqJFAKs-R)GcFg;P3=0-SJ&mNAvY~5*i)|3_)POV7?6j2 z@!P}-U-XNQZVe(>w|5h`4~}+*qqvu>x6?VnF7v&GHCaM#wme!;a+2;u={zEXoHsV) zfc*v!2tD?MU<5=y^+`Sz$VcYa;V#~DthHh)4;}bi%!>$jr}0>6%xjq(8>qD}yTjQB zCO79isEJE`ZS&Z}v&+S7E3Yq*5$1WTJ6`gpO4_bhyxi=rh+S{D2>c{jh(h6K6AM?6 zFiQ|M3r!FeGeaz!Bu{TJzDpUrX`xFs8wb0ZFXmTK+}5=mG-P4mH&$XCUUi3)AABF0 zd%RYhI=(v|I?`;>C(FRoAak|;U_1nUc(pG$4(5OL%0yOAB12|RGDBu>;`r(Y&8F3p zgGjVlclLp3X?K6|%Il{s9cZqWuFZufpG)YP0Sh6w1Nwya#YcTA(-;9k8mx$paT5h`Ex6}8VWW6Lh=FLgFYuD4vdS|O%ec_5*FPZf{ zR4QqIIU9~(MLkn#MJU7>UbWwPL++i|)%clYa<5J}s8fBiF~(@fU6(>>SH*YIz)rt{ z9afNVKLKdOWHs#hR7_RUbOb_yCZ5MFlNI@$12*)RH}0=^(|q}4u+6h(UtSzy*I={~ z@ifA2QG;eaw@IZIHO~D^>~n3o-6QtVcFABzZP+~eBJr7RAa>L z&Eanudvce3*6M|=s@@sI8UkKulFFf$%`T*ARps$8Zv_9K+#Q!pbt=(J8BOoo4*ZsOG132Y3(7|oWXC%C@ zr{QT*!<|ycu2ksOXgjf+yx4Icy?md^Y&qWuejbY5B<1Wvw=q$w&mP*TwPGPS$q{F# zJp0tw_+iodc=y;q%grk6XRa`gy2qnd3+}-$_atN*)lENRbn<_~xMr(bxYVf)8Rt_8xsg>!ciSgi{P%Cv&xrz8h|2ED_ww5hszPjOJS?|F(UW<8bV4xjS_q`;xqOxa)Pr1qTK!fTJFjQgoQS4ehO;>OANSgeDf5$E0&>aMX2bXKo}cd{ z)ESLS^DZRwul|{3_Cu68J9AYQ%fqt(d4)p z-E=H*d>H%f#-W5t0h_v?noyW;oyP~M$l^#Zq5w-OTAnOy63%Nuu z$%hP6&Mt)$(Rj?gscU9z+D_d_fw9I-gy6P5*hdIk9O?R`eNj@M5I_DI1#j=8?d3x` zBtWy>qFuLa8byULmZJ-E4YPu{xVf#LO+LS)p-7+uAhhD!C5L`tCv4yKkmB2fh2$&3 zN>txB)f5s+d})HOstXSQ0{{?Y5+Y1^^kpoK6ehRri!R|^FMvN~7Lct$9=5!<3a0k| z<$#{|F6=cWzj>7$+&OhUu8sV}SKZG}Vm;TT`Ix|G{suXg$(kh!*{Dx2`Z!{HDa z)dY;Q#I6+wwNmzU>+(}{Je>Uk zySG%@I`sDseg22^)dy|zuLzqe{i|2ehH;5ie9V@;3CwDk9>(UYo8bX-R2Ma8iKZ)i z44Z$`e7n_Xev<)j)R8TP19(~@84=PyC$Q==*Z`+>1zhjLxX0`5+tF!MX~(^n&|QW? zstxu;l|jh-nzH8mO~)z{yY)<0LKy2a*T79->kx_KBMz$0S%SGIrez6FOp0!%t~*RDbBwQq_m`kyzj2a6g=P zE8&Q-Ch;BMPdI4)>eL}VO<#D>_e&N2aG1qunX4*Lq3;;#@pPPDA8xxgz90*#VfoSR zrVQdNQ^+to6-#<8vRhxXrOMA)>)@NVm3vKmLF&YC6m-kvm5T*v=BP=wb)xSfpJW;e zvmuBs7NsIpua~&KAgfyBO)ZDjkeHhY4(!|v{FvEB3J{Xil79Q;McogHWc+}2jeZz; zhPN)@>L;U#-wmIue$(rz!H%}A^Hv{w{2MkuI?W%#7$6;Atv`*t?y8fFsygPtzKnRa z=xDPpzV#`NCy+YT^{$8S{4!QAHTf-uw-k+jmG0mAb zSsWx;e(U{_5CWA7(qrtre9$_~>8&)Mtws0B_l0)#qZFSt#)iSdAR4cOF{S2r@+W%n zRi-9ZSKr@`1&SAsX+|x`*9nw~9$#tz$_qPP7QCmpu_Fjc7%|Pzxc9Q9W$=Z6r9jX3 z>YthN&t+&MEfczI8J=F^@d2WAd7CmyZuhIWF{m zNM&oBL&XK5jC>ts^ECF%5#sqx4osrX6x3i>Ky9-5i<-~IdK|#ia(ihTDF>N2&+Ual zoyZLD3lhuCMM1$lQvN(41P=q#^e2mY5ZW>)YT`QtU>tX+63LTopPCwt9WcC31A#f`5)bac2rC;wY_N+-GwnZCg87Dx&RETq*^s zZYN)A~tBO>H|wxiq>_@1ZJYlT=&R5prm8`<{#6^j$22){Q-E z%W`$$@{r!zxjOXP8~43g68(Ym9={WUo7dq^St=J}W#5-fc}?t;e{%!h1ahrGm2A*y z{t_9Ed_RJ_W#kf#)62?`+<5HRuwLu5EjvO{4^kR7o(Yn;w*Yfhn_7N!+Z9nJbYvEP zeZuN~-tu6h>%?w7ak`r#_s$i-qeh3Wp0N`FR+sVhm%v4!Y)!**msDpK;(U0oRK+Ki z@`^YN4{i)?H?D-?R9O?R4!|gzYA};Lm7FMT_^e{UA^Qx^z8WaKlQ7-u^lT#1({3lT zFn=BaJrRz3_aLc$n{PJaSp3r74O`!7pPhVU9q#GYa5(A9%#F*)wUCj==aInhJM^dD^E8xP_b7VL&Hv%KW z)negTS(TF*qRd_&+2bv^yn2mR>*q^O(@jFk8B9;LNb;*nr9sz}^D_ZyM$&#VKa2hT z5cUKQrRtMm`Q3%{o=I1nIxB>n67Qn)SBr3)c_LHf3sSPBz_R{^#c@mXy_f8{^p2MCTqk@O@ zz^|yA8rIw&_V6m;Ad>|B^1?Mo!2R!jcYet;Uv&*UGVSv$erJa;C+2fx8;Q}gZ4MUA zcLuejMovRDX1(=eQ1|*ll^`M!lcX{hz>`S0h81dYcHZ}Z;<8$1fVSNsgDLa zE|WE7Ev<35Y{bpnYm^8($EM5ON%G=hA7j2#BY^g8a7f|)#4o?do7~F}i<(&1{F;q# z*!-ks7n8`Bu=Gh(ycPllQrG}G#927enBf>nWi&~KGS5_)mI1Ez9k7Xy6y(1w~GLaWHQOY6`E5Z1H-}7mLgv8)$|V$<^tl^ge4QJrPC;7Wo;S}QKto1xjsIwUB$>ssJK3PJ z)tsMn(i!E-PG~(7Fy(^_L)Yl0Isk^5t2mP&p+hZuzyKygxu8AZoU@<2kOsXK>84!I06|+iwNGm? zigeWr2$tq=MKYS@jtiwtbZNdZ7^kNwwjp9F6&qCPL=H=k zlAJu`o7G`!p5SQ8C|mp`e0z1$`a>U>D=7T8iwQI7jy4d{iXNY>okrMGy?ST04gJo$w+UH0{V@h(QKr#A7zQ#g|%22bcsq!vLq|81z^PFDcFt zu=tdlzV)_>Jwvc1(t#GlBx0OKRlk<%zk4-JW$Z%r?54Cd%REhh+FJra3YKdi5l#u> z-D`kl@kgYbx$RpBfA83uTSyA_lzL)Qz$G%<>o1Gj;PW+xGz0rZgwM$kV{?p+ra>*W zzRj_dJLt(%KIb7SV5XTetM@cdh=rtjuD#pn-j1-$xj!ED0_v>P4n+2MckaKRu6@n}=+~vTJ3Tz-O@#DXjZ{VHg&08uFYG)>+3s#v z8eJ3iJMNQqzH=f_CX1wMlm`8Hru9G<_*NnN@Y%PnfrVB5q-2&aU#I^j!0?kQU`L7D zv;61Un};TxaekB!>|>C0!fLi!+BJn%qmdtK*3x=!;>V>V*KF|#86uf{(lt#yVZrlt znh$zY#=YpOZ_>f>tl8e=m}-vU=S4Dn)>}(-EeyXd2?BbYp>_V$_vl@A+Q*Iv>zBkx zBNkwu!*QU;>_fzkyK`5&UcYM^HV07fQp}-iEl}cLx;jIht*&3jt+&0 zolE3^W$H5#Ih>|GMx-h}Td5-ORKo<9o7vh@+e?F;+LhyC8VIE{-zVw8QbI4mnwjdI zrg;W=_Z=M8K-L8`c45P0pz<~e8*V%uz_PlR5!1tW3Wf#|Wc5<3?-A@v)z`r49z}QP z-w#jibcqoJ7$_CVRuiV{D73pX0;!#&Ir%9EvhUA4s=@)G=^C;6Gh(Q%!tVHvZi}6$ z$-@E}qMNW8dVVeFnFyZpskEC!*V!-My zyZkiI!^QHqkJau$>Iu{L5F50}amx4oc;H?4M(|X*Op)MdpDuf(TY+1894J%VyieUz zsG&I~h7@sinm}V)0-(Nd|dVzy%Roy&ZWO$mclRSg(4#+HPr zwD0wi=OC=$XXC}kRCNFgbE>L7J?#>piBi4MCCw}sh)k!CYZMo4r;a2KUDq|UrJY~$ z$BX-$ytM0vxvn~xfa9AUIrv2YQAYlp!6}NCq={$rpWWT!@0j%boV<0zdZbjUIL)&G6a6~lQ#XS<=7Q6ad)RF^`}gL$t6^PV7m0pJ6B zk7!`|QyQdGfU49cjh=SiA?L1aj1R`0d!GE#Ko_Z~wra8P=@L)J8+t-HtfZn+0qYL9fvU$&IW&z~(as~B+x;W5q zc=jttJQtP!ESMssi@#+IGBtG$zgCKz^mKVU>FdkepAjGp^7>SgaSmYH#SPXo+}Z^k zuYLeLKlDkaD!9 zz9g;nHVHKRo~X1j4XC46&zkhqc8iffT>!YmLT*q^oT!#A2{r+bvbtAT!jRqMmH0mP6X-W09#kuL(bSqwjn&|J9} zK|nH9zT>H#y(ID}%=t2t3lv15jesb&WE*>yQb5qMx&K+AiC~A+LyC!+lI#FTmi?yh ze-`U0!;l$I7n81ChY*0Q2u>ZvStbFw!85}TVrGd<7E=Oo@)G8-oGSgPvnQETN-rpo zl~4H|-3@evo>=mUoz7gIIt>7Lh5$HuMkO2HOOe%je+Em={)V^+8K0Q2l^Fj3$ptb# zE%%bMy2q&-1$Ld%ZO{i~eqX3H|L0oL*`a_=H9LWI>!WXeNkkw(7YzRGV|~F>Xi7Mp zzD5QTBQd!7&r#3+&I42zbB!D355y}>2Dk9PL|)|VpXUys)DSYE2ZLH!Tx9W@_2&ni zv*1;SMsVcjCELz<(*HB3@#n0b3>zfSRHZ6UUqJY&4T-18z@KL|w2==%d8MOz82}5y z0;qWZ&szhaobpDB8$9AnBX)irJ4q=_DEX z5&yieJSHFxR5|EWp<+PlD=-;V4lW*|dU-hvZkbCx8&0Ju%|`t2VDKGisABCxAWSyNM= z8~9|@E6IP)bK^3erOeE4d~Pa$IAOCn;{T8`2TgD2(FHk+geEM%0EUW!?!Nr1-oUT; zY6Fz;sq$bJ4&eGT?Q8$O_nbig@EUgjVVjF-1i%K_AEUSbQ!0Re^Cab-kaWon$s%nK z=K^8A_dj0+u8k>y4B*`cA6kKYMdZQwzgqqQFe{C0w4Wwj=;+Gq9|3}4D(;EONlv^{ZgNFF?bK#vlH&^gLe-APlmbla$N(K(>~xeTH=ZII>3412QNo zd2T5UpdMF0_dnE6;X}Xs&pSFm!J)%!#O5DKl?ni|&}UB>c1Qv)2!^M`{%Zr81i}Q} zi^y9whG38?J80;izd_Rxk)4(vL^AHiZDP>Kq=)M)IR)IFL zm`H_$;I`4Ik=_NxU)iBlE?V&!so$TmvbE19XY@XUP%ZH-z5dwo{hcDZIOocW9heXS z=|~lOqV9FyOI>)qr=h6MMAvuysBwR~%76c4DS1MBUuUS`2sag{Hi8?{<@g^(=bIr7 zATVFDHGzUnQ=3mGkpHre=dP)n+nsafOp>I^pgFN5^MBSDaFXNcG{49zL_!+yCW)5t ztjBn&&gstyI0*Q#yrvSH4?z^|+C~2;`T5`afM4~_bTMZnAPo?ba8vyd(Dz_h)`njv zf2EF^?eDiqc6fnUEo&+UZk)6g>-}u32u?3&?vt6`fk5qO zIkzK;=}cB1k*b3zg0zJHFc{&7CnqA+MH&#;^QiA~6<{Um)wJ=F2#1*pCGO!==i$*H zbn}1WXeR=!QOS%1;E4is=$8kPC3`eTZ;fJb4cF2pDr~g282(?_V=4~d1)ZbFt&=1m z1<8|)kq)MTvSr6ojgtu}v(HtaLwnGl-scgIH}w7$3nZ48lb~2eSV>qF&@CIa@WjiA zg!a9jh{}_s)x&!%5!iK}Ih<@n1BR`f--<0hSI`2ba-;WNRdI>H;88cMk6?jhT){V@-*r&Wl?K zjK*^Mgf}k!F<+<|SPrZ)`YM9Yh%|uac3t;xNcc(|=(nyRI30F-;jgh`E^I)cX#r|* zfP#KC#R)BPK*Mm0(zDH3t&9YPOHEv|{~dSd3J{=WOC)V*0EJczSV@&bcmaoXtXm|1 z63S&#VW}Xo9L3)*0gn6YUt$D-C!Y4jb6G7?2P@S3n zHR6_)?(g4C#0K&le0%e5gsJHL)viv4NKpLBVZ!kD`yiF&Zf18S#8`&X9jpb2jk-Le z0E%sW!)Ux2RczT};}9|MU)U3o0T_cGi=8ZkKs(FQo~;CPcyiAEzQ;J;6+IG|Rll*I z}SFT-XW0Y%}P$c`l$4~c0seI|(mD{dar=#3>G7#J( z${+!P&P(5b!|B~hpv$~HQ?iOm3^G$|Wg5@~=^oGcr@Sq>c;$}+;A8}RQ^!*tUVbXl zfX+nf4CYAWm*Dk_8tT8?H2oQo+`0{y?LEgsx?0cw1sbMb!J=im{$XJUKZW8702Qm$ zG;}j1t^#};hIeMH2s2geH&F9(O~?N~!*ame;WU($T zqYsO`?erSNu4-M{jkCh~!#yGvWSG3X6>#>ql54NY+k zFzPHv-@WI=*DqzL7p3bzV)>@eXiQ_Wm4;%IJECr4XK!5oRv{bRP~*It=ycNBN5Uw3 zDBUug)gY4mY?^NVoKfrE3S*Oy&zv#NqV%PR)Y-w)Nr3PnV4kSN{t1HY=rnfH0w1k6 z*l5LF+md4Gs~7P>31fY$52NAa;zn3TG%zMix8U@nOB`u7osW4oX|F-j(ih9e@9s0Fne^X;lw#f^@eU-vOsrUlrz^c}b0;x1?et z;q^3|>gVa{m!I&<+2|e7S=Wm`rh(S8Qup2(nf0GTQ z1dvQQu`V6LG{KxWNugWKV+k3TWQmG5qpW(F1>6+$1hl9TBkAy0cIRgXJ2^UjUr zOW(|&^1w{O=fsoUOh$_rlZ(-VF3mZct-g6bHy5dz-Ys?+nn8tG=eV+6~&kzmn zzHeGdh;r|`RZt2hw4H`PMzAr^U#&`%>^s(to`F%rc0 zY?%D*;cvv084g>;aA6Y?G>*R4FxBH-S9$HD<58}~xe7I5@P9F{?W)LfoZjqQ-`+Sa zXiTjDc?}`!?pHEio(e@gnjRIt>9bCtmm4$t2e_J%dVoyzN}ulY6KL!mGtyu)s(dnE zOAtv)Ahv}tmBlxF2Lb~BqwcX#Gpl3YaxjT@acnZ4h!cF(z+e;gH(gs7g-^wlVl@dI#rdZ&=& zpb{K&_qezEzR#3VXW5Oh5|~q`X!Be8left$`ZvzpL}XDw5ka@RV>@$#|5UgpszQlp zW3N-OZkYVS&GO40@60mjXxru1nfmr8A-hB4Kzlq3`Hld+Q_okv zsm=VhIBE$m^0Af^;vhUbQ9DQqY5fO-1YH9lh{7+yN*B@q^Q^{6BuDLDabH!1g&iCJBzis}FJB<)aA759P zpPHjEz}IO-yLqrQyk3fR@}%I9&zAx(Fcv`XtY3co^IsmAashMI@C;cs0;iAW2up8_ z9q0@l$zv-^Y3?>XLG&1=Rm@qi{RJRQuL9gb6n7qR6aa)2TwZD=kvVSNf7Rmcp8R^m z0>mp|e-qL>wiQ$C)q}a0ME2JuWP{6gM`)>cA4mx+15iD^lfhQgbbjND(|Y?!=~(u? z^f2Uo-U13nBOk>i*~Gv0(?SE(`q9;~(|Hi+qC7!hI}W*Ua-DVZ*?#?tU;wk(my>u< zL&;zNsWymc;jQx;yd>oz=z{bv7=W@$)WP0`o}v`s5HkB|uc43a5`QZXA|wQ9IF45z z<;DScU#|IGCkEL9JAsb+;{+931xA07C;NZ@W%jFU=$rg^=D*B+N(NNLZ+u~Gd;*{_ zZcRxML&O1Fo_piI`|K>pq&#Ysm7247h_{G*!Ng+>UFo? zZe`PbV;C8=|DrFm;*}UPfDELF*6yEjR5^e*%im^GKL8wpMieH&3*o@wVvLdA;_`#xxr`3AYto(6basJ}A!|l?u`; zX@(^Q;*?3w{v!p2F_1bb@CxmLPq+>752YXpM;b*}Y8Rtd-E6qd4;P{?^vb~b|0r$% zQUf0hw5C5w$AS2~FhosI&Xd~xJ$Ia&L@DkaQJvU%Ww2qT9Qof0muWWGL{;|x{2rwS zz~SKL)pg9OTU|K~iD5l4QvFZ0Pvi+AAtB)s?Dqa=fb`(A#9U+ro-7z56F7quT{6^VIJl@mYLcvoQmG z)JeUgM&*c^Ghcu}1G%kfbtCt_5P`V7jKAgQmFn{&!^u`6~ z_W|Lvej9s@I1q(wce()v&E92GsOqdz`8} z@(C&M%#$7^wTyS54x3x8H^dOZg*emdS!@w}N0_vKhA-E7zQ(YnmNJWxzRdIwN#9Ak z2mLn1YV&FzlL8jW-CfE=eA#I|3nw&*EvcgTB%GpBgM3SG_HEco&GUTFpF*KZVL${( zWo=SrzvBuh)B7aU?jEq7QImghyA{^gzP=aZ(Nf)P#Emi35$;yzxJL)A?! zGf#@bH^W-qZ_`DBI^b%GVk(G(d&AOl8<>qAyA%6(-S7La$OfZjO&}5XNwlIsGO{`xTAOd+Dhm^6uX>Tb80np3)^j|AgmG zn)uzD0nwt&31N4^oMoi+y}u!k!861A$7;vU0T~%}+5D=Z$ou@df#gDs=H_h{oM*-g zl>-ByC9Nj8T=@!!$KhV6RW4-hXi`21KzkMFjxP;i&%7@JWID9AgGy5j5U0TlQ9{O= zBDuLcV8Qk}#0tn)Bd21>tOo%PinXsk>BAXI9CTna8q0wK8DN{;bTeD0ALG=;)8}g0 z&K?Irj%Fc2&gVzHQ9bAo|DCSl*?IMw&6`)CFS+U-U`UW%@AJw+9zxF!iSz&pxlZ*b zk}zX1=fW8MgfbD;`UHI=W_ToUVtW55Y#;o!D3m%!Z;MV@m_Wwro8}g|%H2QD>fxWw zKh}pCfjO5K=_fmge$E=W`(swon5JWD^i1K=#W;1z01HphSirgN3pz`vb57{tyi5_W z!k@s!qYwCiXc_4N*;}Lmi>dM%X&MM)cb`i}M?rBx4ji~V5$R=aAv!5lS?avh=1um1 zROXaFf#CW1_)V$+svC(%^pQZu-+u^^B4L&F5t%&sARf4k+Hyf7d%andhTxnm(ps5! z(oZ1B*mn5=E1695VT#i`gd{2vcqQyJQk_ud24y<5g}N_6+@>)#8;9bJ0+XJ*Ni8ZW zWO`e)dR6Ehr{NmIZL$Yq|B-H~0E}T+u)Phj;sK;I_KM8v22nV>6w}(lMpBCvYNK>x zhLXdP;>Q4pGCU{$fC;IkmUR2HB7t}V6u&lUe!NLZzRD2~K>~L?(duzf3?EV#waqus_Y(h&gl*dmoe6ci5u{nsnSaQDANo~)uMP#)_ziYnlKa^SWw4pIC|zlg%hXlqIlD6_Ixh~nl@Mf&bnsc~AL%0;874oA`*T4%4pC26?z*>3z?7w5m1Q6Gv zF~p0IBMO(P6rRKe`ls@<{L~~cEX1IlzR(L(vh>wdTl6jZN9AbY239;w5z;yW=(O`k zZt|?~omom;&teeH#cVx;nx1b+a&C#kY^Zko9r^x_b8oZBc-79fR<}s|kYBk0X{d=Q zEqsvonMy_)vo32Kvi$h?kOW!ncW0}q5CT1M5oo^3ILeqtR{aZgvTr2$tNvk&r#f!h z>0|&HkDqYXpXkU(MHTNVLNwZNJ3=}-$?&!)u-6oIBwFAB6R`Q#kB{Jg4zKbp`!dzZ6qppjtE3xU z{mcA5>NsdG=N8#cVIa`uX9c^@O@?#|7LIanN#!rMj}#@1@2`1ZsXy|ClTphZ7f@N* z^=i*-JxrrF!D8h()Jz&IZ@=D6ODHd^Fp>XoBB~89s;o;jWP9#2wK^KBz!;h{Q8TqC zI1JCiQp;_bdJNRzI9JBY%68B1Qb0_eACkB9)z1u>?RIryQf8g~Vu63yS+~DV3inv& z2$E*6c43Wk@9`lj4EAs#Bi4dw=;n?pO8VF>jzKhrhPO?8k2{ixG7)$m?i05@T}w7d+je+n z(bwzU5`Hk`BfVC~EyFr8vEFc1rgnDiKs=>sDJuGJk_k;$2GHf@EaU!GlH_`Hxzjxr zh<)u$XNkd1?3<++0G{-5@)#2>0I{LhTBr9vvQ7m^yG zw+LCcL`!W;;W6e4-y(K$IBQZ#pWF5uW=`9pd5hH}RF=Ssy*?(7tx0!zb!0+>G zKA&-~x%ZxX&U2pgeU|e)=X`O^H-1X(u$jLrOF9ZaPnL{tB5b(`x?8+k>Fj|omoA}?<8#y zurXall|0Kz{8)?s>?OIuj>~?Ax??X4CZfFaPL4M2p6HVGoYy#AbUmPJ{SAYs6@jq+ z@kO8D!bFA2c%Qp&)#v{G3ys_hCR>U<@Md^1V0Ogi@N1-TU>*R5^C`afEMq!K;(1YH zr}%W)#S44(8Woxd8P&(_fr=L@iRGDl&zdXYGm@6Q`kD-pL!~kN-Q3qmmjg|&Mf2}a z-z}7kOvTCb?iT9h6I3ixe*EW&wLf6BW?e6c{AJR41B>Tj zfPwcHj%&-%-F&KU9`NA;QuTlY6|boV&o@A0NxQBfPP<1EW`q-PL#LFVpxYb{SPuxQ z`rb>2W+N#uq+LW9EUn~epFvy0wCh0YQ$~`vj6|v*AWIz}um4b!25k*h-vg~zYL}sg_6JF<@SdJAs z6?QrrqXWt*_BcLvSEZVp)t%^wj^X$D0=~|k7kkFu38l(LOO@yko0^X0;GJ?i8+Ba* z0>@;c{PXo(jK*BiS?CA><9@6Df+ZIsVD~XL)`$3;p)1Y$tNDrkI>_n@%Sv}2mk0sL z?7~dJp2@NsE*6bO?4v(!bf}lOdTPKw+FY+3y5T}m9$PPYA=qPzx?^5cD;6^3Jz7F; z(Oi9ZgXl~&!nIcvmRJfH=T}Zl4c26M=KdXBSZN_H&<3nvh;CLQm|1;U5U6ZDr2gp! zQMNsY4cobzPhk}Q#9JZI<6@N`vDiZ9@Ar2`qHEe^`Cci=S~%fT+n3z-^EKKoC$t-{ zc6CmW&9hTI)xB|@GRKXkuA7s_1Mo{DlTC9ThhNyLGfG(SS!b zMdi3G%pqxv+$Gde(@9xbbcxQN%56n*q-@_~*kob`1g|h}kBX6q-qy@3? zRFJdxhnbLP-4(6@t{rbz$~#ONlXX5la`i-a_%wt7%0@N7EuO=IwU#B%rjTE1t*!DO zcjtBH50`e1HI_`8<<$)IVmIzviJ(;WuCf)hw|&qP=sI0N34n!kis+4nWiFu6XJ0myC6NreO`cKAIl>26-W+Y@jk$tLEN`Sc0 z)h_QRJkBLpc)pq_t?j8Pzi+k%Z=HFiP@1pXe7e#w;jaSM)fba|Mz#6G5kk$OHL)8M zW938O4^nn#hnHDY&)%0bpaIh(#sIGMmUC}SFm1x!UQxgm^1+UcCYlP`1lTG^d?qjc z5=sLgG9%ys+I#ZzIU4B3cmO!xgbTR0HH-NZq*c!X(8YMU^a>54rI`cp=P_(KNP~)3 zVgU&KQ{6w*-QbEp%>Qfa=E%G?FIQ3 z&baQ15@RAxG3(Wx?o$LLa=v4aAAwXkfs|WtZInVAo1@cUEKf`@lDB<(;wygA4 zLGPOH#kQJ0i+b$SLx8WWCin1M$kTSR%4aZhPNtOYSG<8=Z63)bBF2U@C&-bG<&9E= zsiiI^e^((K#ob9MxqRa6g5gvke6_PsW_)5K%;sX*+{?<4mdERnfHPvjS#5@8+j67o z+73I+59AU7X~lJM%NIipzO$16yjA2EJAN)lx2^ZHoCJi;BS9w``JpPT1&9?`wjtH+ zM714M(|{sA%wO4D^JX@7nM6mgk-Yx0uXj@V2< zJYw6A9-)!u!XJPl9Q>bdO(kx=6$1n4Q=DvcmhR^)posSKe@G00{vk1SfN}ic;y*y~ z2PlBGPXAyrRSNwPcUy??N2AzMHvVW7+xpxepx9C!{s6`QbD+>*4Sv#cn9fj96&As~ zlEB7;PRC!pa_*O`ouA_65ybQRsswl%{@jAj4&ivCVLe&X&jmWr^7P8~X#07h%7`IaE&wr}l< zpc@&xw(~f)tSnqzE6+#m@S|d&((M23>WWgWIH)+u3`}QQ`C%5b*Ob80DBI1olD6w( zw-MYqo@GFdVA&L1j*5GCCN#b^L&X&n5EFJVdRT)ww`FHT`t!h&ZMi$uKvRtQ2 ztig+yIvg(3T8%7r2aEE<)BRZoQl7p1B@6H8wALFn>$QY632-bHC1|$z%krz6S1$}W zM3PdDVvmBQQ#qgBfYUf}fhy}u#=5St8*>`41}8mZLT*U~>WrB%8>XT9<^xcfOvDH1 zuc?X~*9{Y)lUl+t5$sCwY5&pUK_7=kcd}w_XIvM@M z+-)vZt?v;?!)5)^TG2LpQcv{7r=@Uey~n}Rk9C-l+j&>iQVyFA^eaRaPy|37?u3S@ zc^qat1%ygaYX#`;Mw=9Y<|h*&J(H}#UcJlR0(tZ!{2?3@(|E6>dQn$oG9KhR{5k|- zz3q{qcDo|R=LIsaTLBFfo~V_?iW@MS(sLu%u~@-%6)7wZr`9zBylX|pTS4>Z%Gtj( zOZqBADEi5WFVO04N$>yy#C0lx={zkXDeS1qC8dxQD}a{?czD8e6>jG3+h&o?6CjG4 z`D<)zOeTp9)E--@1dd%;zr6J7w~owHU1A9$Cas^Gtxo}+mJ{^!f#tTp{Ebdup*7;s z-}ED*obcix!AOCsAiT~vJ-r(axgo1YvlBeX^?N`$F}0?b)T8NvRPFdQaVGq^R{5x{ z5Lg49A^K7PZ_XbtU*^y=vw8fh`mbo$mH)*J(KU?R3J(;sZlhy8%na*_YSsMR1kc4xWuUw&acq#O&TusSP+&SfUD8GB zXrAzv2gdyOF@#AQkqzb}{9leBl~=K%)3sl(HrL2mwW@=jU9D1dU4a|o57Pmu+TrOa z-^}dBxEeglL`#Y_IJ@CkFHf^asvx|xj-MJizs*fBjvq5!ZS9S70p(%3pF@0LJhzzW zFwpuTWF%o`YJ>u*2FOz2?Ff_LEIMikqhs&74~&+ah0|-6g>B6Ml}!otvxI8PPk!{b z6+@MUV%F-4TOH)fhyZ%X4Zrq4{%_r}^P+I|%(^^2@NsIN@q+tojql_=cuir9axz`4 z1dA89Z$R(r^)Kuufxtp(po~7Sb@P6U~B`Hk^IM2B_g;Opr!18fO+?< z2&lupU7t}XjLc~GH$4f8p4KVNgwA)a<01qJl97 z|7eZNB4!jZEDUsjkXn;zRcW8~Z!|bEz3l#8Twzk6F8XXOLz;3%k}Ww7Uhq_|o1Wo$ zA;gAmq^+hdc&E#OPGDq!3nTba!^lm)>k1FKyEq92;r2a&&9Sl}01ceVn7=l}G{ixQ z=_xA?Z6kbJHGuW#oZN*%cCiMZoOQvk*uf;E=>?UW_JAB|bo8pt&N%@Pg=aGILA?jeH+Qp1j(qFbY)-pUQ(Pb2n%H#`Skt#>3oi`oI8z za!=|Bux>(3Rm;2civrjLnEp`WQWB?S;Y4ObB1nUw;xINfl&tYv z+pj@t1xS7*(bp%N3c=%hr&`<_E$}ODFp{r?O}4uuoh(^pS#dwJNLU)NjvdxH2NACK zJP-TcI9m)C1s}RaD=e~12Xsl_g6!iCJ&cE{o>=sN5gOzA*rX?84!=G~-vhc3ROt29 zgp^kPubTIN^ehO4&(s{lo;n|CMx^ZkAl$St2De7A@#;mT-hT+vkf|2M21VOj&^N5^ zHd{vF(sBuW%}uXSK8H1Uka7#&$Jd-iKcF$J`!xEUzgNH;)(nHb1Rjf&p>U(=`jrBY}91kks)eJo)@q2y=3-^p1f6-^@J%~cMPMie3)eS6jzWNr;N z#>H*t_fZi@niV3~aQ2KiHm7V+*ZThasbI%5IP5ET^`&dU6d+O*>*(uoaCbYc;5@J+ zBcU@JRTSX+$Tq2gZ{+sM0=$af?a|G)NSc_7b}6@$A=4^|MI5}%Y(3j4u>qZ@A4%4CJY-Sq_xz|NXO(n8Fkv@FETNt?@G4A&Ps=}^UeSwFU6L*D4<|d~?Skfn5Ig08jsNNmt=gXO6B}oPY~}fz zJ#A<3!J*c_>T9YP$cUg!_2AT9#G*A!-B!Z(?Wzc9;;=i?IS>I;X>-k%rBNr|7!AzH z6kCOn**>dvi52w%q(44CzZh-Y5SIeg_$)|E$3e;I5}v+XTR%(K#lDs75y=_W;JrTR z#c23qHQW-8dO<6<^`+eOBL~=RHBmoO6PFy8cB(=Kpab6 ziC(1OR}irJ{vXD3;@~Tq$#5%9xu8=3JlRviu9?w{cj_7O1U zxa*1iTsnN648M6Ct8coHLldxAXUD=H{>s-Fh6*PiyDyXRmj4d4?(1B!tl;e5_$pZ} zx75ut5gJ^zhC&GS$f{FVKzXu;VJ`yFp8LU0pH~OrL6?C}Yc|2tf|a!wB&J@gS_MmZ zJ^K-UW=Mz=TLGl)8$R>veFR^vf!{oXHGb{k1f%6?o~pW!UE~scl@ivcVb%eL6$IYn zuZonnx5%qKiJiyANk!P7r+es|#emxx3JIS9>}lRmd~Cl~DlnCchLk4P9PLcyYHmho zPO+7p*x$hU^4F1!xd?3={!tiBX26?sHH+Zkz_Lq2UcnDtD*Vlzmoe}fMeJ0h82b5k zTJ5H^Jm-7lP~dT_Zhf5VO08goeJJp*^RHdnDMMWgRU~q``|1mLn>q`P3i`%GSg9>Y z3r4J;O@y~at>@$6YDa(=)pO&r38n{nQaG9k0#XtO-ArI3nwa|t8db{r5wwkMc`}SV z1a}Q3H;~AD?&u@?n|Xk_=7!LIa+`QPn)|hfJ1l`;YGefS93lTaGcVekhF3!*q`4IP zKW6pv^_13o5N9Y~+;KO1P>HI*v^#5Zy!~zoG^34woUj-~R!~JQUyLal0sqC(0^|&P zJ+VT!^kK@-(?1gX{;9P)$4tXb8xY-aWO^Np+S3`9XyPRW0zR4-buJW~v%ckskdXm_ zpoU>rbkuk4;N1aS+NG&+K@T_zZ+uypfWMyp{`0^A?5U@I4ph*}KLY%7!5*%8?eb;N zQQ({f1itGCf^OUbe0hN{2*i*E1~C9f@WyXxknO9&X$=3JZ`_y{Vmk-iPS}V+gtJZ< zUv}2Mx_9l`P|LcmS!RAeZ@Aj(ixO42(D}Jke&rt%CjaSTvj)Y0GgjF$citxc zeTOx}V2x`4_mm4cwA1b#?AAH67oQFUiX>p%}y|QwqD%BSQ2v&TiA? zjgL;HS#qC`;TZ)I7v=W(o|ql=8E<@;Wv93$ucOl+Tmd$n)_^swiOGn)9s3?btZDT9 zk)fu5W}^(8J)bW-&{VC(la_irGi$B1GxdS8=5s?*A*&a2cL$H&-K84Gi8|s-1mBLi z%9V603An6%JxJCIUIhsJ+%EpU=imR7NLy zYQ-JqSk{O98-1;+)_V^g!!n-2Z#Vevr2*<{8+6a$-2#r)|Q6!=xD!Cc}F8TGaioD8;`@3=f%y8}30V z%d%gKHXBr!KVCHW?oNl&)z;wa|A0SzE|TP&O2C}zNo$EOYdUa0?os@w)Tef}v$aE6 zN6#)CSi~6J6)&VDT%DCs-;Xht$(+^Y7*IK!6Q^v6Va{nP7_!u6O340Khz;>&w_fWR zA(yTbxb@a9D z{p{_|Qg8am!fN1wLU{#)v)OiX^Bmw6G!%99c6M&xwVR!TYrnCM{&A$epQkBsq!wf( zig32^^i1d66ATGvNZ-3J7#hqN%w*td<6>{cu^+f(?}f1OvT;UTm-Mi|X76F|im*3u zM4((Z%H-qUpOzNP)Fvc+@Q~?dNgEHsH&5+7&2{uII3m1&hS+%cr5_Z5>*(wLYyb-< zuc*WcIZf@W`err`ZUMLM+zpG2j*UwwDygcjsjL6+d1wPXfe)}y;pRt_dfYn9{tr(i BzR>^x literal 0 HcmV?d00001 diff --git a/assets/icon.ico b/assets/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3f81a13bf4ae6ea4c12044381f6d9d5fffe8bcdf GIT binary patch literal 109356 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 tnI9>*5lX`Tj \ No newline at end of file diff --git a/assets/icons/1024x1024.png b/assets/icons/1024x1024.png new file mode 100644 index 0000000000000000000000000000000000000000..d784cbc76b7cd1e09edb0b57d4a48f23ddb5a8c5 GIT binary patch literal 24937 zcmeFZcTiN>*EV_(0Y?#DN0bcX2$DfSvIJ!ik*MUXlC#p})F>nT1_Tr&M?rE@qQnLr z$r&WrB%$eULeu2bH2v)ZGw;2(zN%Yw|NE-$TNZZrIcM*^_OsS{*4k_D?!WYO)GwZA zI}bt7MUDG^Jc6LJ;O$xH94&Z3ateik7uu(q>VH5K_+NH&K|BQg25J0p$G|Urb=o(` z(yoneeO4Ro<#GPq!(Cza$=_6&sP6pn@L5jIfBsWAN4qB^7`fmbRk>sMhe2!GJr$M7 zz=TS5y1c-=E|U7kL}`t9>`Xc)leo7fP+z|{g$U7hcg&m(?nel|mtlWvOHQJcrrECc zAdSqi3wXO)Leht8U7cM0zd+DvtenPGR8U}h54QtfN~Y~{4|hTH(Z(cCEb7R?OgH?) zil7?ZZ{#@FceZIs6xWn7DhjPeI}`H-2+G#PeyBN@oQ`?Hv)6Qld%+VG8TAdx4+R+U zcG+wA=vJD?5r*aGxF6Z_Lr^H2SvsbT$Ct03w<}s~)?HA-fK>o;F0qcwh;Neb;&S5L zj}^If34&BMuo#qG>qU)n-OB92KX|jD!j|V6yBd|qIMw)4Q%5$?*NjJqSx=}?yhR-5 z`02tZAB~E)YbvHpW9FSLX}{qN1bKB_*EoKM@zprCe3sboB)ehx#s}|KQeWdZQZUIpjZEn@U~aBl4>n79a6JC+=Y)e}&SWEe zv^Lv#)OlI0o?QhJfVp8(d6acGBa)OIc$pxAi`M2Y4`2R{XE4z9wo)wL!E+#D%C~z< z(@c;M+gnVthK^39PMayXjZc?zQdFFK&7;edo@e|BIvW48n&EIZ$=31YwuzLsljY6z zG>tVuSDhJ*Hq-Nl?Pnf4#_96P3FIGAL(n@l{kW=Ov$I+PvYOWpuW)A58OCwE#l&jN zB##*$Q$Y}aM0mB;Jo&2=C*#b!I7_9E!jh0x0wz#nmtX!I7`ypPu7*<57!9@N`ej6Fv+8o*((5%a*}4;LfmaruQz5TIDLpgVTQVJ50G8J;1`D!BBL zmY+XvvNxOEK^hO;fzi-+*Il9CRET7FbYVxDdajTMsa>ggdJECc=kH)(beUhj_ZtIMBT|7WyZhw=?~p8GPE|Qp5p{YWV>_PNS->rNvdm($G9NY zk~h182}-EWBvQh7s3W6cVgE9WTTK~brAp#4wQx=EU%B7{(Q5$<^AI}$R(Qc$gF$=q z?$90i+&X5+W>|g^S#i>_3i}N{IoU31H9FIj84JiY9aABO1oRR*v;3`Elwm(MC(P?Z zofXaFD4y|eCveYrXvOu6^i&v)voljoT`MaQD1YenUog@ijx`u`Hy_85F7yxQ&lo|g z@5aV#T~DCSjymM^N5t{PPnkYTyt18t=5ZDeQdgpKjsrCOSj;vYU>Ayuo3eVAXp9%3 zX)V_{j4`@CU*BJu-&t&0Avt-d@5I*eR!{{gw$ar7FVYPww2 z1?NNE;*Z3;Lb>F*z@2UTMqdBlx`GwGTQfhOZ^iS}-I)AH7Xt=?g1@EnH0DP<2sNvq z0tWVyt;Cbfoj}a#pfT*m?7)?o{ytr;i(0G&({c-bjj7CV@vKT*16Lz)kuq8c=&hYjfw9@bl zj#Dgt0|VxlC!is%Em75|u)Ibe>U%@(Q{y#oIaKrr76+W2qPJ)Gbz&5S8|9k z%%EDYKSfLT@PTh;lb|F7h~!q+n>7v=@F2c2INqXBP}d@X6)O1qWG0d8HHN`YjU6DZ z`LK6a~PoiJn->mI-pGrA1M_rN$qgnXgM!xZ9 zw+CnxAbx$FcPCI1l8$au1`lmt0l{;0h?Z~#@+b*`gH(37JV#HR@A=j;4WH7}EBCNGrXmE3 zi`iwYkjst9_lbXj=R%9w6Kw}}xm-&i+24#PfHp!~@U6RCjwO(zuMOOhabR#DqcBAW ziQ*CCVKpC-1s7GyO0zJ3EfOt4Xj}Wm_fJ}_hSsiGv_KP$bT7dZP|eoz>F3;kK967% zAi2O9k{$HOib*nvDB8XZr+v~en{ zYt<^>MYm~?Y(d-p=3*obRde4H39Qm2p>zt&K0Aw7Y{(QQh@I)bV5=|8*s1LOPB}){ zkniSz&rr>9vh5L4$?3kt?_J4X=1(qFdbJ}}wN4-ls5wTu-}-y|#5s&BlBquGyf_uw zR37VbztZgg{z;;?^*7Lg3PG52D-CEAjNU^JzwlE@!Y|op+iw){l+m>Q=V=xESxVx! zt~VcQAQltXQ_Zr)kDbZ>H1`|0r$PX!9o&TWh7R0SXh2;xbQ6XGS{@(PhYp!JPUn*c z+bg7pV>)>`bK(&ER3{hTg~DJ!4^&QM;mw9Wg#M}rzo`83Pxt@R?0+EnA1i_M{{QMY zgD5O^5)vBdu!U~Vx}=cOYUO12Jvq0aRYz1p5(Pc< z{D*?o=Io1rzz$+>2>NJ$GddB=d(bn^*qOeh3;3!~OouAFe4AU^erYbNyyVt)&-(L~ zE1ZDx3IUzv4Gs4PiwI5H8`il|>P0x+(L*ifKm4+%-5Nj6GEgJ{rCI7hdgJnJ+Z8vH zJxrfB?z-3Qm^5~nVSnLtL(e>yS7;?Vl4@&%zmYjbLI4Gh()Df|WP}Al;Z*Ar28f^PItmkxJRTV|g zdRsVwCyH6D`-|FEJkJGYk-Bhe`jgEm>qVNSrXCzx;LHl z$iC01*<&o7)pWS&L!lT|>FC^xFv$Qs{xzGlpiOveSMn1e!bIU~E@{DBAVTt!+>yaS zu`pWt-s~i#5iAN7*$f%Yt>ot?m=JzTMyxBH1`)@DVD9aSegP~%;>_W75To9@%43hvWdEHc+tN^5m)yiR-5Moou$N~*Q) z5<-?XqII&Q6m>z5@z#E~V^QmVH^5(J^5!4#tNlRM^s8p7<`fV?@b4a8H|n{u;+CL2 zhL&fqsPmT2{Ak!7!?qXc)*yk$|8nsnxw3ttrV9Qe+c)0uw`-r=vbP`BXT-ecTkHF( zJCzoZ`B`Q_EBJR25s`0a^9PCz1c7{aYtuj4-6)q4H`hr{)*hd^RT68an9z;1_HHIP zV3gZqSkgXSZ?`91tTX@lX{jpTVR$QcaR&5g8Bgp2f87iEnf$-;4qAfL=rK*g1KyRg z8q->|XRK@e5W}Qxb6M37{6<;q&fgn>b1WJXL7knhsLApQemZP_Rz^ftlQN^SzsFjJ zm%2N0Js+s9D&p56V;C<5*Cy54^qbJ?rtlLbvFe$xTkdsd%(f{)MuP9xI-9|4;kL!MHR2k z{h?@j;bGPoOY=P+bWq)D!-4yxchq#{SaMCGQtg+Lim*%j#X1`mi`$fP=M_1imU?0r zX)BggKH$A)m4&`Bo%u~W%J>OUC3^J@hJgn1R-^j3dHX!{*mR||{-IU#2zzCZ56Pjq zMp`qka$c_?^FnAj7oP@JEImnqt3gg?Hqf%Xnc$Hk9vINrkxyikcXZrM|7`4o&hZ{Z z{Y+)AZFFuX#&iNLaX7b43{y7O6xW&8{BaRsKDLbFfzCW7+mf){ETsy83|xf-cpd zb6aVVX{Fzthy(e(~q7Zm(jCIc)kKbne4n$GdY7mqme6w{$Nz1GPZjU{XBD5$-~{L-*7xLsi#7& zU?FVBGmP$HpHd@7qA@YZQ5yY>bj#}_ziATfGADhx@kFf^<%Fd-g?X!%JxuL(lI-NAJk#L&xG6ycMa4VryUj|P4v%|32~#@Eqt)d-TkW- zk^_X^(7+`^cjdrRGmVPFv8ZL&%-CLGRmak^#)O~>tAm3`>I@z3lIRL;v(&9-UH7bS zV%BL*R!s*4O1!0y^3x@p0{hzpJZ)hIQ z`OhvGTPxEMw#rxQNIzL694CfJ3M8`0B<_4@t%q)w951sa!s^&>+CyR_k2WylL0;T+ z?S!KGTCls_Cu0Te`!?J#h>_c@mw%?Bp#fl!}T_e-c7dL`c-E+O6O95raWIEfy*7qrBb)%OR z27;45QHopPeu<+QB|lD6pQU5bPq z_8nIjo!tkpuW&4>V-eEyd6nE#QvIoKljP`v>`_8B4Scso%-lzKWT%!M_oGTwX9qQvdN9o z8mFP>j;gA8*8*Lutam5uQB!_<-w%e=X1g&sE)jVn%MzdvhqPeC)HUv|u@#Sz0P8^X zu7$ACQxyu8oNJOQVnQ?myVm84>lNzn=cTj=Yo;bKab8@03BsTJ`{yde+iFj@qOB8r zIeZ?~PV5`fiUqPcCI~bLnmRhq~oX{6*yC@;+ zuhacHHx7oZLsFwWj;nr$8Z^MNJ!23(c0c*!uD$=Pxo($H8o|tq$>hvg=mE2+;8*lhsvFuTi?X25gPXwdfwaepZ=WiVsI{)x?y&aMpv_~$$O;E>l z`5teRkH|4X!^2NG5hhnaSj7MNq8Y;!`XV|E@pl^^=3<4v$Kl@IfS>iy%p799_1Zz} zdp_)7b4;fbE=06$%2zcOTg(hICbz;7M$5wE>CnT%m%AZW($)@DNAvsKxJh zci%=qF`UizF-r5Js}1Cp^F1mAL%{@&hH>+%p1+$nqqmf@(m>Q0dK*x7Cpyft_eBS` znJ(zJu)sTV>f$~>{5mWGmcPkSe#~OFqflun%|{PJ2H9^haYE4H%bcrJQ+6ckO@h8y z4=6(BeQHnMIGFhh)m@~Hysk>eC?u~_QAJ^(!^Bk_D|T>t-lb(dO0q(QhxiYK5PQ9? zQNOFNdH=yC7%nq-N%zaY~!u8eqS)j0lE(MKzwU}tRVChBmC+q1Plf{8OvkB$&@|9C&Ir;_xyVpPms zvAStmG&W9Ov|GS~tVPSfVgkDJKJ8A5dQK{^MWi5jm(kR>Ogj+cw;d8j$Ix%Aygr>C zG|DWIO$p6e*e?93dJkjHEqlEHx!%aCWcw}U=FCok$i;+kj=)y&`qj}W$>(3Ls&%}u zQaiC|+3Z?L=um3AhZKAGKxsdw;!5od)QmRY3-k>M*sPFrA7ulRzog*N;v#xHY$xZJ zqzVM(u9^IihK(DbT;rC*t1gWXR^Vj^g+LW6`?9nD`PR8RUpI>ukZ;FZ4hvH`!wx_0 z+(YA52dvYh$0wWc{8A$*Yf5_1-wvKw4V-LXw{9yTS4W!?LXL`| zeg&#`Dtrckms;IwCnO6(=8s;piI*3X@@}({WUwyWM^-UGeM11g+VR!(28;E{3st+$ zD^2quQAZCi5YZIH140+huI7?WRLmJgxUiTpX!1=8s-5(#NDrFQ4cs1nIa(0@KvhS6 z^IiHnR`&|0U4nsNLJuTlAH-`kw><_tM83FV$ zQ(OPZ$yJF3`-dug^rc?}Ahh;m`E z6WVQ$(x<;WqUjjqt`U{@_j7Ejo%Y{cI+*0^@9OWd_%et=21NO;2HS=Nt?rHBDc?uM zVS@Tn4E7QGzK;)R^dA&NaQaSkY-Nsf16+(*q+GrFZ!a~uHV*BoslV{yJSrZ?O~q!U zJP8ZG%1PsV7go|o!6=AWIcrFhC`FnA;z3ZRkR`gN* zS68%!<)yY&E-2VA z7Q868h99W{*o?_u@hU~4jt|Bnj_W?Q?S&pwd$t485&4n zdxisV{q%$y0iA>#yv=HmhrI8=m{wQ5g4Clqk``tu)3<~XoJ)yj5ifOq1bz8Ch(JB7 zt(v!sI&P-4GA>$H1bg(wQY+dK{|dwg5|tIni3b#gZ8aFv4=*@-AxB3%=w)yEHOD72 z#v3nVM361y8Fb4HqQd@HDMc(5Sd+wZg*?)ZrBaji!i8-u=IV&Z(|SdnppeT7MQ{h* zt)1{n;?kln!A__un^g%>yEg6SA8ZD;ynXQP5puL3cQ4Rkre**g6+=~`1xr6Fn@u?L zcplq`i|!{C#5w}7kTG)CU0$)mX67f+$1wgLeQo3@%ByeD6oeQPk-15LD)dt4yn<-*e6Kt$6r5UIAv}2oMgb=}JHA32#fEOqPn8HXk6Gp&q0}*7DEq zPk*-0SJm|+Baj&}Rrr0Y=(=vvbI=yfpn`V$_?S7VjUK>yzV-3>eV>`1*{+pCF@PS5 zT~=q4#ZW}^rP&H(1RCTxK^uw%c7MNltN4!oFno`Q^xDn*>@Xyrt$H%-HPvvONJK~u zo<&d6Tq`-5k<0UL1iHy-pw51vY%`Vy)ZOrwyC&ehu}Y+K9_{X2sqAc9z>I3%Q4HK2Zs^@cJLWY`fr-^k;Tz zq{r*`N6|WPLGJv0n&6I~jV`rg}&Vo@M*243|XY^P$Ii zW{J11aK2!Z>?AZ`vAk;Pp;j(!Uk;{cBH9@2ZhHJ|%DJu=x<{mBg4d_yCz`N^oTFcJ)(04IHyVwZ z+Ju!hx6`u9c^TY6s^U#FD;YfoqO$E2uB_;+J&D=!?}Rv=Gm`7gcdO_sb~h3)Gu zt*??m%=BK#lqr0!N4v|N{8KgDK?Oy{3QA41j2!7w_sZUWSC8&71G!!UD6uYVu-i|6 zAJe8J9O;ZrHZj=@i1-ZHyLhBVWcq)`^S^s@iBm|5n2B;|%azG{vfk-ax3s1#QL=f| zJxn8sD1a;3qeZM7&xl3bKy11UPLHJR2g9ItE<1IxQO_pGy0s;q^1I(p?KJ<((tOfAXd z{_vsZX260>|85#F(Xwt*4DH^~^I-PiPctV_oyv$`>#W(cNMk29iti~t_eeEQ4ZN*B z5|@8_eU#dNu83|EjXV<7kZ{L*2F1woNhF$FNt7npgG!WQW>mTVNO=UdI!b3Cs>Fn? zt$4G7A9^?V^3|4SPlhq30cjoAxQ4o>8St~=DkxR@A5E%n?pMWP=1T_p01;KKNRzNN zpd7|oH=%g3yg)m_>z3W|uDVB$9i`z`((Lh`mcP>j-S*|`BFO@5oVjQhZ=FS4`*HLn zVm{NqXDtFJg(f6{&uSgH7ePT|ku#7xh0?srr>6ei7Wk{)@3G3{$D)ncsi|ixd4{H? z6?}ae$_mEQn>Y*ao-9e9(Pg>Ebuze*!80kJa*f2~*}UzsQ%Rcc9?I@kZ0pJY(O2cdFMUy@=|ZsgUO<`jMZT&iW5}jp*xV zbx#@}2{KRblX{6ZG^U`A=`VoVC#A@(bXOrd`#n0<84o}e)rOp7vr+lW!dPDnyIYny zcXKoFf&T#3TQ&f-zhm$5D+kkd%H5cPH8FV|?OP&F-G-pXYD`%fUL_TWA-1n^_sP4s z>UjwtCOZ@;$8#Sa&>f6uBUcj&zIqu0y;}s0a3i`^D`nNro*>9+$xTOtQo-Pj6r8>Q0BEETbX66+$h1U(K37?J^8lAd#YsHa-0 zD`2e2RE|(biKkXVA&;LesCmonTN}Y+JtKg1x&R%f$widk_L8dA(whv1%FhCdaG>?J zZSO5QSWDp^!08~(x%`jTz{>V>KCd=F&jG7w?PuxUw9=ikFsNBmU5%M%7wdkJg>>t$ zpDz`*devjGYX_4Jb3f&2j4Z*;|7mx;T8BW5_}6<5S!Gt1faCvw$H>mh<29c4d!lo+ zxq|pwmXsLsuxLrL05i&s;;ciP3mN>{6zKc~3!SW*xx&YhvaGjOm zc=Or;Ihy$jXWl5o>`t_rdiEc1@a<^cAHHy~%ox)jJ3z9)vaPm!xgtXm?>HWK;*aS% zRKEB!p>h3ic5zUQGu@o4sUFYY+&)EvKx|ehW#|K$Q(@jOcxP2N?IPhiIGAIj_bZ$| ze06WcrKWG!sCw>EQ-tLoRP3yd@@>8K;CkER(E!Mh$#&+8zuWsX2zlQHYBYcFsqa4Ng~&ZO^3b5zV74S1=}=Ny z(|>HxUyq@ykX6i?;(PG!>j&J8#s5^a2qckL;&O7g17wuFG-Ga)IpK}6p@$DTKxAYB z*}=9r0@v3&j`Y(y4*Hgor#y}lGBY#t+~rm7^zB#vwv6L_z7;03SU3{XX)~ZJDE}bq zIVGME^B)h61mNXYIr9v5rw_ju83=-)3vY!EM%f=nA3 zAgBMD-7jqY$}(s{?V#0nHf=J$+IJGed;@3cz>$%JZ87kAH*6A&S)TNq?gP_>&(~zf z`mJ`6JeTWYdlC9vVqoySadu=DG2J(kmC1W~N~pgZH*ow~jnMG3t$@3mgj{bEb~dZt zR#FzJsTnXDqsrceMWUP9TNgPP_MJ^h;YGQcN?H1RCBif0m!~z{jn_oJ8wnvPcV`HG zCJdpsCJ{=MNK%lYi-Yn7s$pulea|#$P+N`=(P4Z1QV!G^6mS-YsDqwp=Bu1xhSf)p zx0#V-r;zmy;?=l3E6eSHsI3yA0a5vT0;`{gc3Ht*=8$+H0=9>5Ye; ztL3*{zSwGR&iGeRSZ2<=auIj4cVb7Y*He}}BZJ2l>&PP3jdMNu z*0X{4EN5HxU+372HWOqfYX5C6A?cty;G`UcwD0r(gy+xm{F-5mjaxy24jSeTn6r8! zD0>saH#PIs(}Ne~>Vt5I{AQo7}Vme|nw({A=%N(1JuaPrIRnhtbUA2zix=Q`4 zJlnhQh5H7~>50?2_rXZ(+o)3vTetm5^VsZ83;~t$&>#1s45bKOD z^n8izZ^Vw5pVPa}US5A^=+bGk&MAM%t)AH+Q1tPd8%L7-ugZvk32XE>Zmw#DgghD& zH))p~$?7unwbb`|-BA5Ab%mMp#i_jM6w-)_|D!d3Rlxgn0M%`jV8buH2<7bWw{jIc<3m{X7B}S>Tvv4-7RL$ z-11UIpE7#9ayFi2^cp;3_Nxmx+!xIjYtR&5Y%bOVd^#%TAxO{%`aLSP);vA-zG&)u z;%w}@4D`WyfN;3Fei5SNvFD0)RE(Z4*w2Nx zQ=AJcdkH8jZy#)LhN;Qb23&q%xi^~%W5dSG%2sc60bp1@MJdA4?e*<2U}Hiy8D~^3 z!jwxVY;j9D$=Wvr$Pj)2HjHQYW=((}d|q#uW#W7x+Atp@1jaEoV*g|YjN@dLOf^p4 z+DlP%xCh$gqq&Z7!)VcY69te(cPg*d*8-Cn>SH9A;Lmw~6Zl8G(!4x5Wc_j}2$eLx zNAeQAvQ&T2pry zk-uk|2B^gyIWhjZqG4wUoj6nO^^sFZ#<4XUa6<&(20hgghucXCYt2A>gCR~G>cXNG zV!d>qNS|8A<0~TO(4b;8nLR2-g%e)zUz~o{!#%Q^KGBc^6_&XW8yfKEyuP}{&a`aT z>O&0$&qL3IF6+Y&l1J)$y&Z-}80~(})4<*xm3npYMv~d;NM`Uxy;hbKpeyeu*}yd3Cs_aOC(+?T(?$!t4+X1nP%Jo2%?>~Xfi+`}9_MNif-3r*< zN5o#`e7~j@ushUiEsFxkwShe33MZ9g1U#9!{=f<$`7=`6tJMXTzhrl>1S2%MAT-=>R<6?a>Pumq-_K;l9b;LjO!#bJ5< z*S_JRVuo;1b=9Ro*YUptzciTq&_V3ZQOlPYZ)A1=b;7%r{`*T2K>Js;vlN^0=Yp*e zRjj8TRlIr}0m{E;6z9H~jzj{Z=Bg^cYndXgNi}FGB2Im(u>?ieL!^L~40X1%eQ$_3 zFlsn&xTSq(%uQqr%BF>FMGamqt^R_ONP58veczhcGK#K{8F4_Fc>SqV@r~_Nm&JI1 zsBQmL60l!JzvqeI$<5Jse87YfOsTU;!e{QE=qB<;<2zF)ld~TKGBb{~fJ!Tu#vr^j z;6?aMlfh8@z-<$+vjLs-#Aim)XR?oFX|hSFWmKo$8=3hj&fiJcq&gdDNR>(tc~y9K zYY3d&afYimhTFY}Sm4B5m5v)KxV(B%Die>ZQUXvz38;S->%yH$c>fqFM_c?(EBk#2oSc%xefGT9yslsA6&a2d={9}d>@^u1>@#nU)^Le8z^GnWSMU&0F z&N{c!hpy?res}?dtHQV{wDPAvo94m11g z2*O;pvBbZv_@V5T^m|lpk`XWe=_W&_3V&`8Ck)Py{}^3mf}G(Rl;KCmjhDiv!=NaP zM+l!e=T;SSrUoV|L6bQ%?8gVGOb&zjSEF7(qJ}5(5}cf4;-os{A$s0LgYz^%Z21o- z4}W$H8M*`&UN06uRnpuM5-RTcJ@mv4i?jXzDoTY6Vn=LF^?zq1?wguAlpS-cE}2SY z2d204M>(`AQuXJdlhK{mqu3xra8}_e&;UqPUaLVTU_mNk3!@SzLx7a_^XbzdDYZ*Y zyK?FdP<9e9dU(npyh;3P+;A5qkRGfJkbJiPL*U@qPv?Gv2ZTZ?9>o4IOar6*3#552 z>7%Qr60dsV66uz=EHA#G0A{)u8!D~U4sB-^) zTbx3|gN(Jp6EPY4Z$va}h0SY4&Fk!MjgZteHyv-O?`fg@r^%$CVob`~-eEJ5 zV|YIpw?|UMi{FFvU{e6qKGv#pzg;;MJ~c4Hz{de0Citaxb^PMiK z2xh~L@Z$OZEgS&L@E_Sefeo!`kjcXj{C|+%zO)F+CY{d2zLyF5-^UO?^RKiqmmn`V zWdPF$#{T~{g?y*;(7&L4$`|e z7U-{DhwKYBFpc-%YXc`%0lEOo1cX$zqvp(n7;r{`e6Z$4`Ws~dT#L}}J&=aH zkPO)FI@5YCbW)C#)3Xu-WU0PTbnB!0`g_4DUo2m2x z5P^@-0t-XZDqBF_8kyDS4B+PcHAg9 z%AS4y)TO8${3y9jG0|h3Hov(Bw5^;>gNNosJqaGB|4cuU_TrJ&Nj-i6| zK%E3u`XZtL{uTI+Jp!+`0Lk`D8BVPQ9Oc32$>g)ZM(n+0AMb>+3KyZ0HRZnJj+V zE|4BLxlir1-FeKR{JCI_g&MaSB|5OzvM~VGe3cELa!G$H3VH+xkb0#v*L*qV<{Qy~ z!>FxD>ktpvGS~PKwE+bE&Ge)u@e0!79>yDWl$q|m*3fXB3YaWSsIzdX0%Wkb9z(>G zY7bN>w5vGYaC#lsO4zo5CZ|H`%=(+Ff6G%By>QQj}1ylX^l&rF3( z&)Q<}FB-0AJOM_OjyjGkZ9Hm3bd6XgM~MZxUllP+#cbbQ_@F6@Y&)Vo3nkx`JP$SK z0vnTWTIg@MPXA#emx}E|_-1L+@m=ZQJzZ?SSc^g$>JTYuVRPx(Sn7^x<626+;{w9- zXPz@!c26}j8B=`aCUxjiwavC;)yHi;s=;FxMwq}wBOZv4zG zdw6Ccq)^1CS=a^RWXt7lMA} zv!C-Ho*#~THB@*=_UY$BH=5VE9j5bLz!&Ag_wG)qu$mg}E@uecL;-XwcjJVrb_I-; zYJjLewa3$hq4=CVs)qPR8jc6ljg0?{{Zm?E#I$bjI%s? zEo@bpqp3~}C3BuS(I5jj3{?Fd+gtG$^J0d@2i-c4t-q1Q{A^$-&y98$L0Jh%g_Mdt zwR|_&@@LLC#54(M&+0Xn?YFO@60t8e%S%u0 zpNhHOelG?K9???`}pAL|7A%>e80J5(x{xKJxS-s;%{rH$}Gg3*o>;#0Yl`FUlQ zEc8HKbY?&O7TfV(XQAbv(xC=zl<7x*+K_xObGzu3m^-oT6dRwV&F`j&A$^ygGtfJ? zQaLlZ#n!LRW$g*`|6pqkaNz-3?s#l z{_f|P@aZY)xJPyKGW^ZWWr_R~evYgprDXw7f^8R_cDr!@uis9=*WqVBTap&9_wEavcmSk8-{U8FI9p zZg*J*yR}UAy@V2wpoRWUXkKXGm?qB^b>vgsHGu#N`IoW(BzZ7o`6QY?9o}`ls_UIr+GVa-;(o zn0f`I9<8^_ft++>)6`zuY>5J`qH{AWT4Z!IE0u~A6Lj-0#n~1m1&_nQqK>O)F+8x16+6&F-}RtY zCU~~k*08#)fYP(SX&7Z79vWpemIIVqA;~kL0I|pCZ8{ygP6*Vw&7+-DB^|V=vLf2>XCw{7K z`)j~ZAAs-=M6Uk%$y_->B+IYI2{h}j!M@Zst({MYl|k(c=gHs)ZyZNrDvoSwkv}bg z4KUwgGevd5r4K>S11KjKpo$Pk20cy3o~gLlQM2o1iOyXkMCFpnT+WZR*G-O#)poNUk< zkGMfaV58683GGen#l{|o0IK&^e@}ZM{3>={vjS$Lo1s&*Z{WTdxLST%dy-~R0v)kj zw+a5aRNarkugU1WdRRyG0Y)mfISrL)4w459ej#?0^OZk1i~|Wi0lE7_NQIdrXn!qe zLDxD-(HD78jf+0Z;>v6t;2j=*70zu~ZUWy1hK7%Ot4i7|^F_(+g&f7|nlon)Ig+2O zgVnzU;lCnI#X1^A=Ib$&Yf!tJ3Aip{I6?Rk6Qx#{Q zA=OT$v(FwDyOQQ-^Om^RUr4rmf&FRF&E_7YcZmivu=TD;|N~YpAshR(8OQ91X6Mk%-FOm)fv*)7}Ru zK=FGh)c>Y@&@FQ%QhyMktfD`+4!K+H7UDZafeEXjNY4Je0BoVR@6k#B&ijD74M?bjEDATXqtI7Cb_fX7^XJdRj=7SypsblMUp} zuH1~Qtmv{)SnIEAId1dsp@!&{E<=UgUmB=Yx^~^`2J6gxV?J4jh6=7;dB2yDp|@eLB)3npEV3wo?O{T6t){i)4O z^;ZCnT-jC&aujH;v$GB-awxjbe~u7(qLOKSns*e z1sz9j@3#e;)*qEN*lgDX(;ZE-{_*wtS2?e3JtI-ehraJxs>cVI1m~H<2MZE2f}ivU z{)qCN0eR<^DDp{SxtYR}8fAa4AV}fcw{5SE6}(0CZq#2Xl{!AXDVxz83h5oSNQGF} zW+{cbnbZuld(T_dkdHdmp5K2oVLOmQB}Q3Uw#x%Vg8}bK%JwVmh1Yxef?oNDGj4q9 z1$jeG2YgeU^KrxXp~X+v#U?CIRj(lJ7QU?-Gs!u zo)7hT5bm^>mIKLt^i|(o{j3nk)xy{4GnFx|u-1J!u$E7oG78p1!ZZ+lNde^MU^q-*j-J zQ>PhcGk#vD1JMK&+Mqnp=%&yBI@u8C))|QyuRAU^%}Q_?b2yk}wi_Bwr~yAal-q&8 zw61Z41UWEpPsD%KUF`+AJHm1H`XmbX{`Myqa|Yt<_n+#3c+^0hy@1`U`j)0qW}2Nt zMixkg`{ELCASM59T5anOmZq6%n#T4U!-lM8Aa_m@)*Wte6Y zan(4s%eyJd&uxl>*&JH(3FAKdpL54`-nvw35pFB(SlG-fMYAd&#|(&nt*zzCdRx_O zQ@b_gWgTCXnYMZ$x$DxqHi00s{=Qp>t?yye{5mV7Ez<%O#w7z&u8@#m61zM7ccdgiYD?@SW9(ksROh5!$lY)wVxY zB48#Av84+&-gX?LHUmat_NiLAZ>O4V5Hpkn#_yc3l-@(xBAQ~zhejcLD}2o#9dU#Y z==^%ew2hh(4wuRc@!+S=5=utuBpqC}8i)oRx7|oQl&?RcV^PyK1KU#u6&b4&Rf=Oy z=pRQ`&dqLG^<`y%4y+UqF~6Ym4_JN#1gGJ&?J3@P*^WQ?>`CI)Tv^B7X?^~U@wv@g z{ktop1P;T@I%7|-&1T7zqGP3A?1rngLhzSKJF}@iWZ-YVX?rq0IjH!zOKNZQGs1em%@?YY}QNZf(Mo30tW!WLHa) zOBYFKY%N}GMV-l=8H*QD_~urFP?DZ+nHDi$m!b0Hn%fAg@8J7+=#SVR_Q&)2e9k$a z^SPbpInSK;umsO18q^)UkpEh^N_EQXaWomr9P#s>cp!;zFz-pCgnLCjN#_JtUY1P? zhu+H$YzaiyN4Aut_jk-~GQAiOUDVDIqz3%2RPfw^@7L=!KqZy5a|{2+zxQ$-t8sMF zVzMW3I<9qoUd`W+UE=>mzpqc&{n*x4arvydWNPx`kf3`S}u*Bl&6NSD< zSuvLzwQS=XQsR0=x%0D|RD=sn1;H^HaYo2!_zU`|{9qpxGx|yhygvTD%=%BP|KpT@ z>fqlkD>vYq3s^L;mQ(W0Y-enhcnM`o6x6&8i*5bXxc6iQ9lM*(=GtJ3&qAI-o9SYM zDHuCr?~6=muG94<+!h^@`*&`)4m7RyOlxnpcU7nzy--3+t~Uv845a75Ruvu)%jl0b zSnX?rrN^wGjunx%CsxsogZ-~|EL_4nhn_E1v*W{L$cAe)7#X(emOrD%1TN70+L1}O zolX3gSs^p017AWTLnVvYYC8M+m>m5c4#EjB=vrEMP%-x44u44>hsrif7p&{Y-HY<3 z_v5%3v}EL?vmIsge|?M9O$z8O`u4MIO)Q$%Ww=1&t46N8h6}@FYn7fp0Hp-?OC+rDUqbi=|4)!uIPy~TQDe&|(rzr_x|k>WGgxj)NR zL^k2fmwq%3W=7}M=f7QDpgzcJY+ns+?4u-GJiS&avPkqvL7qn^Q`^iV<(MOS7vDfz zBR^;lVlgaCPA#i#!WS&m;gAzPhj;P`-Fcp&QY1cm|HP85XT^Ct*@v+3ipLrtVijy* z*cyGs4@)aGDF|Ccteg7@C*ij#Nhf=cX<~@#jjvxEf4rW3YC^zv$HFsGmWug5M!oq$$`SPSUZlgDmzAc@4s%Ys#3OW4%SHFQ_r7gu!70EYC7LC`TIFaJ40w=+ohw zvj&UPp0z&wmL5S;ZbBaJXg`$$GtUPEEIB|HfxKBPk&%LiZ~QVh#4(Mr0#U1w)eIp{ zdX2pA60L~5hjYynt!c72Lc`xf#u&Md*`X3-2B51azoHlK9;E$OODeLnyf9XNT^EERM+9qPKL_HjEOzGYzp&){Cr&*ggj5&iiv zUX@QdgN|TR=@c$VdoJfqYbSCnHX(g>@`OodSGz# zAJwD`@9HyvE*o;oRy=CyQ=$79*FC}=9i`(OWh1fM>}tkrqcEE8pgq+v__&^HFtY|@ zM3|CyD$dfekx@3-Cgu!}y5mBn|}+o(G0gu{Tn;lgRYExV7BI%&;d(=Fw}VSEjKD_Uk<|fP&lW-_W&*X5w`KSft0qPF zsEi>=l@Dqj#j^;H?svVg606U<1(fm~;~-`(M7svrkE%*9dBH5T85h1Oa9)@>bZUGX zcn4hRMu-Xq{sP_f?VdKP>{}RfPR~g7!>-LZA*S=$lfc+y#7$eNH_sa_lGE>YCw6KJ zD;}Q#x>Zf(c2c!PMZqaKKL@7KArJF72PQ&+m7zXDoc2fl&Vt+d-(n0kLb}#B!U`C* zJR6?uWZ#>&mU-2fovZq@m)TRl(qZ>~4UejrHFb%HsYAG~ztq|H4Tb~#&*v6=O58X3 z+oUsOUm^qxY1luJMsxfE?4?;mY-2xh$75Mg<}ZYWfQp(72Xr!QKtY)ix(kg=M!cQX z#n3T-q>4Bmbwb*jx{4_LsH-N{CkfY)H*Olmi_9iy6vn;!Db(t`LC`E0QsR4G$<}eZ zef<#pk+aQgX$~&9YiRARVAbrpZoDkHe-9m{p8UCUh8hZ=$E9ddwI~d5Jr0n)v*6%=5N4qin6qqRtCoy=WPTB2+c`N!b4397}(sH9#3{b z^7Yf@6IrkLp-U?1vt zT;Ndr$EXId^sij@m2}Uy1S=*JMH?Z{enO7g!ty1asE+X9QEe5MOS9AubwXxp`Nl&Z z>`$dpJL#nlBvc5u`*LX_JJ*oqNBC6KVBAgmG+|XvTz0TxrF*dAptYrk9q2z(|27gB zFN&IQ?k#Gj#dWHt=!2Ks4cyUQ+ElvXbI7^K{1FFf2~k+YdUkTEP6gw&r%_?eD(7f( zI9F^ZcMSGkUC8Fbs@nw=gC}b!4X6YbCNWB&^iVh#jqLDAF1ZMpyG>8=gTwv}_~J7kCmT9HU{n92)aEmtyG**0nHMIvl}g1qWv_dzRGvUjcRuA#cX|Iiov%XSIA;|8Kc#%xq+H2i7;vudtL?Hbb-8YpmNjLRkpo|)drjVBY} z5Ex&!&}C_FE8Fj8jk>)w4{sR0Zpd98v9k8qPOVTkq+Yb>&dH%+;-Wd(7_69Am*FUv z^dbQ-viHMlb5DrqVlY*mPE8RWw|;;mHn7FmAIyn)ee(IxBINgBNj&A)?D~d#w@;_+ z0A@C*h-5Dxc+ra0RBDnCUG|*61aP$0(n?&^Bpn$p2hY&y(lJw3sw=aMZ~K{hEelKP zh{kK^!gM#^g!VX3)d8^G107GhHM+pfd{1wCp3Dw0wLMCGEYoutduQ;^tnBnzO& zrPVl8Q|pJPJ|@b0jwWb@I=jx?3J*r>7i9**G>Ph@Hid--^!^T0W!yOul3HUM%aHsGv;IB8TfuIearNu;W9 zKW&-IK}Tz-T^e4*G+XLpi~Nal{`pGtf}ZJ?%j=+W+%2{FN@s7e^vRj;vgjSrl$pQ? nED6EMrnO^kQR+a+P?vE7ziPYE(ApFOO^n#%U|slw=cWGxZdjB| literal 0 HcmV?d00001 diff --git a/assets/icons/128x128.png b/assets/icons/128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..c9693abf96ed6d431766398a464fc3b9d1d977bd GIT binary patch literal 2927 zcmbW(S2!CA8wc=&h*7cksA`a^TGcl8-jv!qQhPUwa>Q0esgY2MS~X$?rL_r~Qv0(< zt)R51IMgm*&&7B1U7qKC-uHL^f8L9K;v*v+2pta{004mK>1vw(G3uYC0spzZ%8v*C z0CqCa(F9!mGld=HSODOfke;TRc}U*wTQtgiioZ|gcxh26_ZSP(03T1NlC7i=dY)Uo{9u~NqejKvqaj3*DFmWrQb+1J zAJ2yPWF1qafTykxY+mt!TMIYzSNVY619WMopp4P-j`w$e7v{Dc*$U3mH`)|w% z31mb`9X(7?AXpN3y@^zW1674W1B2TNU`3h|&|8aGMfyhiXcbLcAIob)FbdP?E(Ty< z=^J;y6@U6PaF{%Z?=^=2Iy%DRw{k57$ML8T_k$r&P85F;i-5>JT_#6l0Ev|Xpg;P6 z5w|_3|3by$M6>X`U@Z%3+^K6%_Z852odCW^$(?wp`*ix0E&CmbcNGhBRCJ?^yWP3! zkQm}YxXGTK?_n%N>zqTEtk=kidG3#=a}l1urq|PN2{b6~NE4z@3M-J5H3h^#sc!r$ zSew2hMXBEP^Qur=?AIup(02HGR~NP5ZzKG4dzj!rHlwce@xP9psqPVH(zJjOVWdDx zq=P6`nkq{q?U+*Hk*WuaBtTC+oq~x^6wv)Y274&#tgB~DC+a;cTlx3{64Y!Lt!=8eW$(1MiCN_#LR}`za7}S2bT3L66ZNb*A##>z_eA&oKa~>?w8C4_gNY0nN7Wo)% zMhw`y$UiI7cyW0pO>U9PilXUaPbd9q1{+R5wyZ2hpKG)`eP;2yywu3xNTsF2$a?VO z@>I@l4j2fypPkrTgl<3sp9O<98cOF+b{&jmg2(OO``C2AW^WN&i1v|lP7-Y^rb`zj zU(0Ir_1fzJLz_TmlE|1-J%!X>r9$(;YZ$lO&9iJSj-)s-G5ojG)asisXp^z6iJ!EX zfWvUH0VmcoNqk3L4 zkI_S^BT0Pf^R+>Qlm4l2*(76O#qEP~`(DTEA>2tE1?NG6pfsn4YtyBv=~y!luMU~d zqon$UEK2g^q8N?~PMkdZZ7=uu!RXSdx&03gk~AuCPK)hZW;UX>m=MFAL=I6J%9rgs zJR5C%SBLsRaoN^}fjC;`*fz;2sphr9R4UzGRfI+OonZH#wxQanJLmWkc9QL1BZ9;} zPLgLlYk!uC4b;a~AKv+y8);?a*MnN_ zFuuZuVS0Eh?#XOl^jYm}L!^vOE<@3_JTysLCcMW-Bqets&RGI1d=V@(g^@?j`=g-> z4CeLkp24PmIsRv9%E*6&Mxp>EH!)a#cP-|7iOmH4seDAcksr8$QkepMLKS@ENF#Qj`(4PF)brQWRXtRx&wva9s^NQvspTL@V{ix(XcrL%K?DI6C!f#(mU z&=rxFw>{lF<2+qin*k4R?uUkK)VQn7w1jsXkI^53qQlzVp^P1k^r^vQT1jt}Q)-Uk zfxqqYZxDGdH^Vt&(fvQELNbu>MAtlH+8ViqI6szlyY~>AQTp z_-HA>Fsy`K8?gLg;Z!OHuaag~1M^T`^tkn;H?ddNKBa%*WW>nK09(}lJHF6ajSHA3 zJEv;bR{zBMmVE01WJAFZE|M|k%hl$yCDO^qq7Cr%EqA)ThYI2ynAuH^U`c$p4E?Se z(ryZ1UQ1s61lU42Pl)8<`*m2+3uCW72%@8ICAeh=Q^Ri|?tK zcpMV{;&GQW1?VO8LD7IB=>QClO_c@12ag5|SY*&RHs}*_=_%EI8aemkryGYtTBLmR zUS20mg^rIECrl1eTwO>enqZ2kQH^}ufm*2rJIv0aT{~qVEz)k;*~-iB7{mxH=jlj6|ssu*Fzq*gFaaR^6?LL z&|=ZEezy9b&9m3Wq`J4hf}o$m*}jdPu{TcorBV0- zs3VsySdP3`A&qYmFlzoK)Iv>O^AD^G{xyoL4SRF+nNpJ{Q`_SH%aIl->T#z~Q zW+GD7CG%@$NU8q9m9*az=Tu3DxmVT&2_k~y>b42Ubb9g|rt^sDu=dxm={xX{7hr7! z1xSZZ6;%TGKl(C)fiLevgm2_+N5u-I^O=E1IEVMG$8UaNeYoU-YJF=$y!j(uZjU0+ z3f|hybQ@C?*AAjdVT)SP1^zp5QS}9t7tl#7$km z`q1$an{HsR@Gze@_#2C$O!R1c)WLW$T(XXXODp3R!E}Xn9pZG?hMFuQC4Q1|B#cqz zh$E;Y!6=C|Di_U12o@DvbTxQ+EJAq9wPfWANQ`tgZr426{nMZUdRj)Bcy(mVe*s`@ BVc`G( literal 0 HcmV?d00001 diff --git a/assets/icons/16x16.png b/assets/icons/16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..7f9d3bf4a3f3333f1108174e514f748b1869a688 GIT binary patch literal 454 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 literal 0 HcmV?d00001 diff --git a/assets/icons/32x32.png b/assets/icons/32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..7a681f284bf101cbfba1bd46b0b1e188e55a61da GIT binary patch literal 956 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 literal 0 HcmV?d00001 diff --git a/assets/icons/64x64.png b/assets/icons/64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..a96d9b9d119f8861084e665a9bc535c8ed5e247f GIT binary patch literal 1603 zcmV-J2E6%+P)1Ls2r$B_HWoaTLNQ8jKSTK@c zVhW-U=nKImA)*+J@xg=`HB=43vdRMzqauqf_)r8|YzY-8Q_28c2HH+bX{XDK57W7w zwKJnkZ|%%KIXS1_IrsGc{qOm{d*;ksaE1oh1e^j|01IIKpO-=4KJX*39+2>Y0^s^M zARO#c1>|^g-ZT!#ja9h|WZIqA5E^&hwVbsJuxT8SQK~$v0zL)u2u<`$zS7D7nACzYkNF5da}1isr2#H#3j8=mgBYk7zfw zQE~YfdioxD zYs}8hnZ@pnyC`^S4)2$L;5XfXo&rw-@$o5?tbH4e#Z_L*#>SK@38mew|?>QDL}tbkE!Yij|C*IRRU}(`({_EEsuc>LMW@q^hC+7k7p8SRyeU01rJlzz(xF{k(_0_W& z?l*YsJAdUAk3B5iioZ@Xx%+qKE)ZcdmKu>ofQAu%pe*e%EO5 zdQF?j=w?$pgO5=NC1oZv70SHH!YAU#ti-@!GJysm>)K|+42{c z5Eqk#)!ai;N*4OdKT}urLm<-z1^#|A4rm2*)}3a^Ws{;(X_@@=YGy88N6z#m=yJ!$ zx9t{!kOO*+jkH}nKI)kC?Ad`#88ifKAJBMWH-^f640zehB&OsL6`LIBv`-#>3gGiZ z$Qz=Qvq+y&Ol(pHTD6v;-Y$B(S}=rp-+ckL*g zQ%s~rD<7i))ZVJ0y}RAx`0SJ{W@XQm9Rg_XXr->{sxLPT|5|_v0^dhs5!rJ|EL?|L z*nUsvsa9cYtHj8;o*J87<qk8ljbP+ZREr>DxUB)Fwnm8IdPF?+FbR!aC?QZ`Zx0LRAdp=!yEt|c z>}^K@e!FtUrvMXnE9@^qUI3pVFwojSM@5+&^D2Ao66^L{;A!cOw1ph+@>0e*2M9dJ zy<6-H-#OrRoBPhy6(Ro=2>B2Q3!pRsr4bfDX#z?kEP&Dkltx$pY%ffNDuyJ$`^m(_ zM~ehpRGNi?_)`K7D9u7a90Xe)s6zR7_{O>%aa1A)FpL9IV^wN_1YD4b?R8S6$&JOG zmz^K^Wzh&$VtdVeJ}?dr_@4;cuqFEgzy-&Se*lR`UWg#w`?~-D002ovPDHLkV1o5^ B{RjX6 literal 0 HcmV?d00001 diff --git a/assets/logo.svg b/assets/logo.svg new file mode 100644 index 0000000..7be8647 --- /dev/null +++ b/assets/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/thumbnail.png b/assets/thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..11ce432e9f182ee39e756ea68065ee0d28e4c0c6 GIT binary patch literal 7175 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 literal 0 HcmV?d00001 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1e901dd --- /dev/null +++ b/package-lock.json @@ -0,0 +1,18864 @@ +{ + "name": "nextm", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@ant-design/icons": "^5.3.7", + "@antv/x6": "^2.18.1", + "@antv/x6-plugin-clipboard": "^2.1.6", + "@antv/x6-plugin-export": "^2.1.6", + "@antv/x6-plugin-history": "^2.2.4", + "@antv/x6-plugin-keyboard": "^2.2.3", + "@antv/x6-plugin-minimap": "^2.0.7", + "@antv/x6-plugin-selection": "^2.2.2", + "@antv/x6-plugin-snapline": "^2.1.7", + "@antv/x6-plugin-stencil": "^2.1.5", + "@antv/x6-plugin-transform": "^2.1.8", + "@antv/x6-react-components": "^2.0.8", + "@reduxjs/toolkit": "^2.2.5", + "antd": "^5.18.1", + "axios": "^1.7.2", + "copy-webpack-plugin": "^12.0.2", + "crypto-js": "^4.2.0", + "electron-debug": "^3.2.0", + "electron-log": "^4.4.8", + "electron-unhandled": "^5.0.0", + "electron-updater": "^6.1.4", + "js-cookie": "^3.0.5", + "path-browserify": "^1.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-hot-toast": "^2.4.1", + "react-redux": "^9.1.2", + "react-router-dom": "^6.16.0", + "semantic-ui-css": "^2.5.0", + "semantic-ui-react": "^3.0.0-beta.2", + "uuid": "^10.0.0" + }, + "devDependencies": { + "@electron/notarize": "^2.1.0", + "@electron/rebuild": "^3.6.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.11", + "@svgr/webpack": "^8.1.0", + "@teamsupercell/typings-for-css-modules-loader": "^2.5.2", + "@testing-library/jest-dom": "^6.1.3", + "@testing-library/react": "^14.0.0", + "@types/crypto-js": "^4.2.2", + "@types/electron": "^1.6.10", + "@types/jest": "^29.5.5", + "@types/js-cookie": "^3.0.6", + "@types/node": "20.6.2", + "@types/react": "^18.2.21", + "@types/react-beforeunload": "^2.1.5", + "@types/react-dom": "^18.2.7", + "@types/react-test-renderer": "^18.0.1", + "@types/terser-webpack-plugin": "^5.2.0", + "@types/uuid": "^9.0.8", + "@types/webpack-bundle-analyzer": "^4.6.0", + "@typescript-eslint/eslint-plugin": "^6.7.0", + "@typescript-eslint/parser": "^6.7.0", + "browserslist-config-erb": "^0.0.3", + "chalk": "^4.1.2", + "concurrently": "^8.2.1", + "core-js": "^3.32.2", + "cross-env": "^7.0.3", + "css-loader": "^6.11.0", + "css-minimizer-webpack-plugin": "^5.0.1", + "detect-port": "^1.5.1", + "electron": "^26.2.1", + "electron-builder": "^24.6.4", + "electron-devtools-installer": "^3.2.0", + "electronmon": "^2.0.2", + "eslint": "^8.49.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-erb": "^4.1.0-0", + "eslint-import-resolver-typescript": "^3.6.0", + "eslint-import-resolver-webpack": "^0.13.7", + "eslint-plugin-compat": "^4.2.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jest": "^27.4.0", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.3", + "identity-obj-proxy": "^3.0.0", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "mini-css-extract-plugin": "^2.7.6", + "prettier": "^3.0.3", + "react-refresh": "^0.14.0", + "react-test-renderer": "^18.2.0", + "rimraf": "^5.0.1", + "sass": "^1.67.0", + "sass-loader": "^13.3.3", + "style-loader": "^3.3.4", + "terser-webpack-plugin": "^5.3.10", + "ts-jest": "^29.1.1", + "ts-loader": "^9.5.1", + "ts-node": "^10.9.1", + "tsconfig-paths-webpack-plugin": "^4.1.0", + "types": "file:@electron/rebuild", + "typescript": "^5.2.2", + "url-loader": "^4.1.1", + "webpack": "^5.88.2", + "webpack-bundle-analyzer": "^4.9.1", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^4.15.1", + "webpack-merge": "^5.10.0" + } + }, + "@electron/rebuild": { + "dev": true + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@ant-design/colors": { + "version": "7.0.2", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^3.6.1" + } + }, + "node_modules/@ant-design/cssinjs": { + "version": "1.20.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "@emotion/hash": "^0.8.0", + "@emotion/unitless": "^0.7.5", + "classnames": "^2.3.1", + "csstype": "^3.1.3", + "rc-util": "^5.35.0", + "stylis": "^4.0.13" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@ant-design/icons": { + "version": "5.3.7", + "license": "MIT", + "dependencies": { + "@ant-design/colors": "^7.0.0", + "@ant-design/icons-svg": "^4.4.0", + "@babel/runtime": "^7.11.2", + "classnames": "^2.2.6", + "rc-util": "^5.31.1" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@ant-design/icons-svg": { + "version": "4.4.2", + "license": "MIT" + }, + "node_modules/@ant-design/react-slick": { + "version": "1.1.2", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.4", + "classnames": "^2.2.5", + "json2mq": "^0.2.0", + "resize-observer-polyfill": "^1.5.1", + "throttle-debounce": "^5.0.0" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, + "node_modules/@antv/x6": { + "version": "2.18.1", + "license": "MIT", + "dependencies": { + "@antv/x6-common": "^2.0.16", + "@antv/x6-geometry": "^2.0.5", + "utility-types": "^3.10.0" + } + }, + "node_modules/@antv/x6-common": { + "version": "2.0.17", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.15", + "utility-types": "^3.10.0" + } + }, + "node_modules/@antv/x6-geometry": { + "version": "2.0.5", + "license": "MIT" + }, + "node_modules/@antv/x6-plugin-clipboard": { + "version": "2.1.6", + "license": "MIT", + "peerDependencies": { + "@antv/x6": "^2.x" + } + }, + "node_modules/@antv/x6-plugin-dnd": { + "version": "2.1.1", + "license": "MIT", + "peerDependencies": { + "@antv/x6": "^2.x" + } + }, + "node_modules/@antv/x6-plugin-export": { + "version": "2.1.6", + "license": "MIT", + "peerDependencies": { + "@antv/x6": "^2.x" + } + }, + "node_modules/@antv/x6-plugin-history": { + "version": "2.2.4", + "license": "MIT", + "peerDependencies": { + "@antv/x6": "^2.x" + } + }, + "node_modules/@antv/x6-plugin-keyboard": { + "version": "2.2.3", + "license": "MIT", + "dependencies": { + "mousetrap": "^1.6.5" + }, + "peerDependencies": { + "@antv/x6": "^2.x" + } + }, + "node_modules/@antv/x6-plugin-minimap": { + "version": "2.0.7", + "license": "MIT", + "peerDependencies": { + "@antv/x6": "^2.x" + } + }, + "node_modules/@antv/x6-plugin-selection": { + "version": "2.2.2", + "license": "MIT", + "peerDependencies": { + "@antv/x6": "^2.x" + } + }, + "node_modules/@antv/x6-plugin-snapline": { + "version": "2.1.7", + "license": "MIT", + "peerDependencies": { + "@antv/x6": "^2.x" + } + }, + "node_modules/@antv/x6-plugin-stencil": { + "version": "2.1.5", + "license": "MIT", + "dependencies": { + "@antv/x6-plugin-dnd": "^2.x" + }, + "peerDependencies": { + "@antv/x6": "^2.x" + } + }, + "node_modules/@antv/x6-plugin-transform": { + "version": "2.1.8", + "license": "MIT", + "peerDependencies": { + "@antv/x6": "^2.x" + } + }, + "node_modules/@antv/x6-react-components": { + "version": "2.0.8", + "license": "MIT", + "dependencies": { + "clamp": "^1.0.1", + "classnames": "^2.2.6", + "rc-dropdown": "^3.0.0-alpha.0", + "rc-util": "^4.15.7", + "react-color": "2.19.3", + "react-resize-detector": "^7.0.0", + "ua-parser-js": "^0.7.20" + }, + "peerDependencies": { + "antd": ">=4.4.2 || >=5.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@antv/x6-react-components/node_modules/rc-util": { + "version": "4.21.1", + "license": "MIT", + "dependencies": { + "add-dom-event-listener": "^1.1.0", + "prop-types": "^15.5.10", + "react-is": "^16.12.0", + "react-lifecycles-compat": "^3.0.4", + "shallowequal": "^1.1.0" + } + }, + "node_modules/@antv/x6-react-components/node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helpers": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7", + "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/core/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "dev": true, + "license": "MIT", + "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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-wrap-function": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-function-name": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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-typescript": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "dev": true, + "license": "MIT", + "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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7", + "@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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "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.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.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.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@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.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.24.7", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.24.7", + "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.24.7", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.7", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.24.7", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-modules-systemjs": "^7.24.7", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.7", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "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-env/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "dev": true, + "license": "MIT", + "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/preset-react": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.24.7", + "@babel/plugin-transform-react-jsx-development": "^7.24.7", + "@babel/plugin-transform-react-pure-annotations": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/runtime": { + "version": "7.24.7", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@develar/schema-utils": { + "version": "2.6.5", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@electron/asar": { + "version": "3.2.10", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "bin": { + "asar": "bin/asar.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@electron/asar/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@electron/asar/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@electron/get": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/@electron/get/node_modules/fs-extra": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@electron/get/node_modules/jsonfile": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/get/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@electron/get/node_modules/universalify": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/@electron/notarize": { + "version": "2.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/osx-sign": { + "version": "1.0.5", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "compare-version": "^0.1.2", + "debug": "^4.3.4", + "fs-extra": "^10.0.0", + "isbinaryfile": "^4.0.8", + "minimist": "^1.2.6", + "plist": "^3.0.5" + }, + "bin": { + "electron-osx-flat": "bin/electron-osx-flat.js", + "electron-osx-sign": "bin/electron-osx-sign.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@electron/osx-sign/node_modules/fs-extra": { + "version": "10.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { + "version": "4.0.10", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/@electron/rebuild": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@malept/cross-spawn-promise": "^2.0.0", + "chalk": "^4.0.0", + "debug": "^4.1.1", + "detect-libc": "^2.0.1", + "fs-extra": "^10.0.0", + "got": "^11.7.0", + "node-abi": "^3.45.0", + "node-api-version": "^0.2.0", + "node-gyp": "^9.0.0", + "ora": "^5.1.0", + "read-binary-file-arch": "^1.0.6", + "semver": "^7.3.5", + "tar": "^6.0.5", + "yargs": "^17.0.1" + }, + "bin": { + "electron-rebuild": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/@electron/rebuild/node_modules/fs-extra": { + "version": "10.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/universal": { + "version": "1.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/asar": "^3.2.1", + "@malept/cross-spawn-promise": "^1.1.0", + "debug": "^4.3.1", + "dir-compare": "^3.0.0", + "fs-extra": "^9.0.1", + "minimatch": "^3.0.4", + "plist": "^3.0.4" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/@electron/universal/node_modules/@malept/cross-spawn-promise": { + "version": "1.1.1", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@electron/universal/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@electron/universal/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@emotion/hash": { + "version": "0.8.0", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.7.5", + "license": "MIT" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "dev": true, + "license": "MIT", + "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.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@fluentui/react-component-event-listener": { + "version": "0.63.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-component-event-listener/-/react-component-event-listener-0.63.1.tgz", + "integrity": "sha512-gSMdOh6tI3IJKZFqxfQwbTpskpME0CvxdxGM2tdglmf6ZPVDi0L4+KKIm+2dN8nzb8Ya1A8ZT+Ddq0KmZtwVQg==", + "dependencies": { + "@babel/runtime": "^7.10.4" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "dev": true, + "license": "Apache-2.0", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@icons/material": { + "version": "0.2.4", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/sprintf-js": { + "version": "1.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@malept/cross-spawn-promise": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/@malept/flatpak-bundler": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.0", + "lodash": "^4.17.15", + "tmp-promise": "^3.0.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@mdn/browser-compat-data": { + "version": "5.5.33", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "2.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/move-file/node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.15", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-html": "^0.0.9", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^4.2.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "@types/webpack": "4.x || 5.x", + "react-refresh": ">=0.10.0 <1.0.0", + "sockjs-client": "^1.4.0", + "type-fest": ">=0.17.0 <5.0.0", + "webpack": ">=4.43.0 <6.0.0", + "webpack-dev-server": "3.x || 4.x || 5.x", + "webpack-hot-middleware": "2.x", + "webpack-plugin-serve": "0.x || 1.x" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "sockjs-client": { + "optional": true + }, + "type-fest": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + }, + "webpack-hot-middleware": { + "optional": true + }, + "webpack-plugin-serve": { + "optional": true + } + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.25", + "dev": true, + "license": "MIT" + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rc-component/async-validator": { + "version": "5.0.4", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.4" + }, + "engines": { + "node": ">=14.x" + } + }, + "node_modules/@rc-component/color-picker": { + "version": "1.5.3", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.6", + "@ctrl/tinycolor": "^3.6.1", + "classnames": "^2.2.6", + "rc-util": "^5.38.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/context": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/mini-decimal": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0" + }, + "engines": { + "node": ">=8.x" + } + }, + "node_modules/@rc-component/mutate-observer": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/portal": { + "version": "1.1.2", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/tour": { + "version": "1.15.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0", + "@rc-component/portal": "^1.0.0-9", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/trigger": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2", + "@rc-component/portal": "^1.1.0", + "classnames": "^2.3.2", + "rc-motion": "^2.0.0", + "rc-resize-observer": "^1.3.1", + "rc-util": "^5.38.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.2.5", + "license": "MIT", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@remix-run/router": { + "version": "1.16.1", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@semantic-ui-react/event-stack": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@semantic-ui-react/event-stack/-/event-stack-3.1.3.tgz", + "integrity": "sha512-FdTmJyWvJaYinHrKRsMLDrz4tTMGdFfds299Qory53hBugiDvGC0tEJf+cHsi5igDwWb/CLOgOiChInHwq8URQ==", + "dependencies": { + "exenv": "^1.2.2", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@teamsupercell/typings-for-css-modules-loader": { + "version": "2.5.2", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^5.3.1", + "loader-utils": "^1.4.2", + "schema-utils": "^2.0.1" + }, + "optionalDependencies": { + "prettier": "*" + } + }, + "node_modules/@teamsupercell/typings-for-css-modules-loader/node_modules/camelcase": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@teamsupercell/typings-for-css-modules-loader/node_modules/json5": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/@teamsupercell/typings-for-css-modules-loader/node_modules/loader-utils": { + "version": "1.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@teamsupercell/typings-for-css-modules-loader/node_modules/schema-utils": { + "version": "2.7.1", + "dev": true, + "license": "MIT", + "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/@testing-library/dom": { + "version": "9.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.1.3", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/@testing-library/dom/node_modules/dom-accessibility-api": { + "version": "0.5.16", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.4.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "@babel/runtime": "^7.9.2", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + }, + "peerDependencies": { + "@jest/globals": ">= 28", + "@types/bun": "latest", + "@types/jest": ">= 28", + "jest": ">= 28", + "vitest": ">= 0.32" + }, + "peerDependenciesMeta": { + "@jest/globals": { + "optional": true + }, + "@types/bun": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "jest": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/react": { + "version": "14.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^9.0.0", + "@types/react-dom": "^18.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/crypto-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz", + "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==", + "dev": true + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/electron": { + "version": "1.6.10", + "resolved": "https://registry.npmjs.org/@types/electron/-/electron-1.6.10.tgz", + "integrity": "sha512-MOCVyzIwkBEloreoCVrTV108vSf8fFIJPsGruLCoAoBZdxtnJUqKA4lNonf/2u1twSjAspPEfmEheC+TLm/cMw==", + "deprecated": "This is a stub types definition for electron (https://github.com/electron/electron). electron provides its own type definitions, so you don't need @types/electron installed!", + "dev": true, + "dependencies": { + "electron": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "4.17.21", + "dev": true, + "license": "MIT", + "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.19.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.12", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/js-cookie": { + "version": "3.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsdom": { + "version": "20.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/plist": { + "version": "3.0.5", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*", + "xmlbuilder": ">=11.0.1" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-beforeunload": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/react-beforeunload/-/react-beforeunload-2.1.5.tgz", + "integrity": "sha512-xrczkBsJ26lidA/Y/Oln0lYgux79KUkpomaOdnQFPRV9Sx1Mgx53RkYsgZ234HG1ZMKGCmzpk7jO5T4h3bmjvg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-test-renderer": { + "version": "18.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/terser-webpack-plugin": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "terser-webpack-plugin": "*" + } + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/verror": { + "version": "1.10.10", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@types/webpack-bundle-analyzer": { + "version": "4.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "tapable": "^2.2.0", + "webpack": "^5" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.32", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.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/parser": { + "version": "6.21.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.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.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.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.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.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.21.0", + "dev": true, + "license": "MIT", + "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.21.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.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/utils": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.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/visitor-keys": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.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", + "dev": true, + "license": "ISC" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.10", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/7zip-bin": { + "version": "5.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/abab": { + "version": "2.0.6", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/accepts": { + "version": "1.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.0", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/add-dom-event-listener": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "object-assign": "4.x" + } + }, + "node_modules/address": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "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", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.16.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html": { + "version": "0.0.9", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/antd": { + "version": "5.18.1", + "license": "MIT", + "dependencies": { + "@ant-design/colors": "^7.0.2", + "@ant-design/cssinjs": "^1.19.1", + "@ant-design/icons": "^5.3.7", + "@ant-design/react-slick": "~1.1.2", + "@babel/runtime": "^7.24.5", + "@ctrl/tinycolor": "^3.6.1", + "@rc-component/color-picker": "~1.5.3", + "@rc-component/mutate-observer": "^1.1.0", + "@rc-component/tour": "~1.15.0", + "@rc-component/trigger": "^2.2.0", + "classnames": "^2.5.1", + "copy-to-clipboard": "^3.3.3", + "dayjs": "^1.11.10", + "qrcode.react": "^3.1.0", + "rc-cascader": "~3.26.0", + "rc-checkbox": "~3.3.0", + "rc-collapse": "~3.7.3", + "rc-dialog": "~9.5.2", + "rc-drawer": "~7.2.0", + "rc-dropdown": "~4.2.0", + "rc-field-form": "~2.2.1", + "rc-image": "~7.9.0", + "rc-input": "~1.5.1", + "rc-input-number": "~9.1.0", + "rc-mentions": "~2.14.0", + "rc-menu": "~9.14.0", + "rc-motion": "^2.9.1", + "rc-notification": "~5.6.0", + "rc-pagination": "~4.0.4", + "rc-picker": "~4.5.0", + "rc-progress": "~4.0.0", + "rc-rate": "~2.13.0", + "rc-resize-observer": "^1.4.0", + "rc-segmented": "~2.3.0", + "rc-select": "~14.14.0", + "rc-slider": "~10.6.2", + "rc-steps": "~6.0.1", + "rc-switch": "~4.1.0", + "rc-table": "~7.45.7", + "rc-tabs": "~15.1.0", + "rc-textarea": "~1.7.0", + "rc-tooltip": "~6.2.0", + "rc-tree": "~5.8.7", + "rc-tree-select": "~5.21.0", + "rc-upload": "~4.5.2", + "rc-util": "^5.41.0", + "scroll-into-view-if-needed": "^3.1.0", + "throttle-debounce": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ant-design" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/antd/node_modules/rc-dropdown": { + "version": "4.2.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.6", + "rc-util": "^5.17.0" + }, + "peerDependencies": { + "react": ">=16.11.0", + "react-dom": ">=16.11.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/app-builder-bin": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/app-builder-lib": { + "version": "24.13.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@develar/schema-utils": "~2.6.5", + "@electron/notarize": "2.2.1", + "@electron/osx-sign": "1.0.5", + "@electron/universal": "1.5.1", + "@malept/flatpak-bundler": "^0.4.0", + "@types/fs-extra": "9.0.13", + "async-exit-hook": "^2.0.1", + "bluebird-lst": "^1.0.9", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", + "chromium-pickle-js": "^0.2.0", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "electron-publish": "24.13.1", + "form-data": "^4.0.0", + "fs-extra": "^10.1.0", + "hosted-git-info": "^4.1.0", + "is-ci": "^3.0.0", + "isbinaryfile": "^5.0.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "minimatch": "^5.1.1", + "read-config-file": "6.3.2", + "sanitize-filename": "^1.6.3", + "semver": "^7.3.8", + "tar": "^6.1.12", + "temp-file": "^3.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "dmg-builder": "24.13.3", + "electron-builder-squirrel-windows": "24.13.3" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/notarize": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/notarize/node_modules/fs-extra": { + "version": "9.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/app-builder-lib/node_modules/fs-extra": { + "version": "10.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/app-builder-lib/node_modules/minimatch": { + "version": "5.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/array-includes": { + "version": "3.1.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-tree-filter": { + "version": "2.1.0", + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.find": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ast-metadata-inferer": { + "version": "0.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@mdn/browser-compat-data": "^5.2.34" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.5", + "dev": true, + "license": "MIT" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.7.0", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axios": { + "version": "1.7.2", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axobject-query": { + "version": "3.2.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@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-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "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" + } + ], + "license": "MIT" + }, + "node_modules/batch": { + "version": "0.6.1", + "dev": true, + "license": "MIT" + }, + "node_modules/big.js": { + "version": "5.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "dev": true, + "license": "MIT" + }, + "node_modules/bluebird-lst": { + "version": "1.0.9", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "^3.5.5" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "dev": true, + "license": "MIT", + "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/bytes": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/boolean": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.1", + "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" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001629", + "electron-to-chromium": "^1.4.796", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.16" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/browserslist-config-erb": { + "version": "0.0.3", + "dev": true, + "license": "MIT", + "peerDependencies": { + "electron": ">=12.0.0" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "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" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/builder-util": { + "version": "24.13.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.6", + "7zip-bin": "~5.2.0", + "app-builder-bin": "4.0.0", + "bluebird-lst": "^1.0.9", + "builder-util-runtime": "9.2.4", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "debug": "^4.3.4", + "fs-extra": "^10.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-ci": "^3.0.0", + "js-yaml": "^4.1.0", + "source-map-support": "^0.5.19", + "stat-mode": "^1.0.0", + "temp-file": "^3.4.0" + } + }, + "node_modules/builder-util-runtime": { + "version": "9.2.4", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/builder-util/node_modules/fs-extra": { + "version": "10.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "16.1.3", + "dev": true, + "license": "ISC", + "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", + "dev": true, + "license": "ISC", + "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", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "5.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/cacache/node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001634", + "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" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/char-regex": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/chromium-pickle-js": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/ci-info": { + "version": "3.9.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/clamp": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/classnames": { + "version": "2.5.1", + "license": "MIT" + }, + "node_modules/clean-css": { + "version": "5.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/co": { + "version": "4.6.0", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/color-support": { + "version": "1.1.3", + "dev": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colord": { + "version": "2.9.3", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/compare-version": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "dev": true, + "license": "MIT", + "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/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.0", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/concurrently": { + "version": "8.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "date-fns": "^2.30.0", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "spawn-command": "0.0.2", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": "^14.13.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/config-file-ts": { + "version": "0.2.6", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^10.3.10", + "typescript": "^5.3.3" + } + }, + "node_modules/config-file-ts/node_modules/glob": { + "version": "10.4.1", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/config-file-ts/node_modules/minimatch": { + "version": "9.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/config-file-ts/node_modules/minipass": { + "version": "7.1.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "dev": true, + "license": "ISC" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "license": "MIT", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "12.0.2", + "license": "MIT", + "dependencies": { + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.1", + "globby": "^14.0.0", + "normalize-path": "^3.0.0", + "schema-utils": "^4.2.0", + "serialize-javascript": "^6.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "14.0.1", + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/path-type": { + "version": "5.0.0", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "5.1.0", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js": { + "version": "3.37.1", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.37.1", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.37.1", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "dev": true, + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/crc": { + "version": "3.8.0", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-env": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, + "node_modules/css-declaration-sorter": { + "version": "7.2.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "dev": true, + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "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": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "cssnano": "^6.0.1", + "jest-worker": "^29.4.3", + "postcss": "^8.4.24", + "schema-utils": "^4.0.1", + "serialize-javascript": "^6.0.1" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "lightningcss": { + "optional": true + } + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "6.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "cssnano-preset-default": "^6.1.2", + "lilconfig": "^3.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-default": { + "version": "6.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "css-declaration-sorter": "^7.2.0", + "cssnano-utils": "^4.0.2", + "postcss-calc": "^9.0.1", + "postcss-colormin": "^6.1.0", + "postcss-convert-values": "^6.1.0", + "postcss-discard-comments": "^6.0.2", + "postcss-discard-duplicates": "^6.0.3", + "postcss-discard-empty": "^6.0.3", + "postcss-discard-overridden": "^6.0.2", + "postcss-merge-longhand": "^6.0.5", + "postcss-merge-rules": "^6.1.1", + "postcss-minify-font-values": "^6.1.0", + "postcss-minify-gradients": "^6.0.3", + "postcss-minify-params": "^6.1.0", + "postcss-minify-selectors": "^6.0.4", + "postcss-normalize-charset": "^6.0.2", + "postcss-normalize-display-values": "^6.0.2", + "postcss-normalize-positions": "^6.0.2", + "postcss-normalize-repeat-style": "^6.0.2", + "postcss-normalize-string": "^6.0.2", + "postcss-normalize-timing-functions": "^6.0.2", + "postcss-normalize-unicode": "^6.1.0", + "postcss-normalize-url": "^6.0.2", + "postcss-normalize-whitespace": "^6.0.2", + "postcss-ordered-values": "^6.0.2", + "postcss-reduce-initial": "^6.1.0", + "postcss-reduce-transforms": "^6.0.2", + "postcss-svgo": "^6.0.3", + "postcss-unique-selectors": "^6.0.4" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-utils": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/cssom": { + "version": "0.5.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-urls": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/date-fns": { + "version": "2.30.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/dayjs": { + "version": "1.11.11", + "license": "MIT" + }, + "node_modules/debounce": { + "version": "1.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.3.5", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "dev": true, + "license": "MIT" + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-equal": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "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", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-port": { + "version": "1.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-compare": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal": "^1.0.0", + "minimatch": "^3.0.4" + } + }, + "node_modules/dir-compare/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/dir-compare/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dmg-builder": { + "version": "24.13.3", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "24.13.3", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", + "fs-extra": "^10.1.0", + "iconv-lite": "^0.6.2", + "js-yaml": "^4.1.0" + }, + "optionalDependencies": { + "dmg-license": "^1.0.11" + } + }, + "node_modules/dmg-builder/node_modules/fs-extra": { + "version": "10.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dmg-license": { + "version": "1.0.11", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "@types/plist": "^3.0.1", + "@types/verror": "^1.10.3", + "ajv": "^6.10.0", + "crc": "^3.8.0", + "iconv-corefoundation": "^1.1.7", + "plist": "^3.0.4", + "smart-buffer": "^4.0.2", + "verror": "^1.10.0" + }, + "bin": { + "dmg-license": "bin/dmg-license.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.6.3", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-align": { + "version": "1.12.4", + "license": "MIT" + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domexception": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/domhandler": { + "version": "4.3.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "9.0.2", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/duplexer": { + "version": "0.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron": { + "version": "26.6.10", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@electron/get": "^2.0.0", + "@types/node": "^18.11.18", + "extract-zip": "^2.0.1" + }, + "bin": { + "electron": "cli.js" + }, + "engines": { + "node": ">= 12.20.55" + } + }, + "node_modules/electron-builder": { + "version": "24.13.3", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "24.13.3", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", + "chalk": "^4.1.2", + "dmg-builder": "24.13.3", + "fs-extra": "^10.1.0", + "is-ci": "^3.0.0", + "lazy-val": "^1.0.5", + "read-config-file": "6.3.2", + "simple-update-notifier": "2.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "electron-builder": "cli.js", + "install-app-deps": "install-app-deps.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/electron-builder/node_modules/fs-extra": { + "version": "10.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-debug": { + "version": "3.2.0", + "license": "MIT", + "dependencies": { + "electron-is-dev": "^1.1.0", + "electron-localshortcut": "^3.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/electron-devtools-installer": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "rimraf": "^3.0.2", + "semver": "^7.2.1", + "tslib": "^2.1.0", + "unzip-crx-3": "^0.2.0" + } + }, + "node_modules/electron-devtools-installer/node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/electron-is-accelerator": { + "version": "0.1.2", + "license": "MIT" + }, + "node_modules/electron-is-dev": { + "version": "1.2.0", + "license": "MIT" + }, + "node_modules/electron-localshortcut": { + "version": "3.2.1", + "license": "MIT", + "dependencies": { + "debug": "^4.0.1", + "electron-is-accelerator": "^0.1.0", + "keyboardevent-from-electron-accelerator": "^2.0.0", + "keyboardevents-areequal": "^0.2.1" + } + }, + "node_modules/electron-log": { + "version": "4.4.8", + "license": "MIT" + }, + "node_modules/electron-publish": { + "version": "24.13.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/fs-extra": "^9.0.11", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", + "chalk": "^4.1.2", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "mime": "^2.5.2" + } + }, + "node_modules/electron-publish/node_modules/fs-extra": { + "version": "10.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.803", + "dev": true, + "license": "ISC" + }, + "node_modules/electron-unhandled": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/electron-unhandled/-/electron-unhandled-5.0.0.tgz", + "integrity": "sha512-spH7quQUrNWgTp1rJNa0sCPTPHwKywctnHLVbrQxpjxojQLhGxXHMdETBkag0No8x9Jwo/c6r2T/nfeoG+4Cxw==", + "dependencies": { + "clean-stack": "^5.2.0", + "electron-is-dev": "^3.0.1", + "ensure-error": "^4.0.0", + "lodash.debounce": "^4.0.8", + "serialize-error": "^11.0.3" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/electron-unhandled/node_modules/clean-stack": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz", + "integrity": "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==", + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/electron-unhandled/node_modules/electron-is-dev": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-3.0.1.tgz", + "integrity": "sha512-8TjjAh8Ec51hUi3o4TaU0mD3GMTOESi866oRNavj9A3IQJ7pmv+MJVmdZBFGw4GFT36X7bkqnuDNYvkQgvyI8Q==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/electron-unhandled/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/electron-unhandled/node_modules/serialize-error": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", + "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", + "dependencies": { + "type-fest": "^2.12.2" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/electron-unhandled/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/electron-updater": { + "version": "6.2.1", + "license": "MIT", + "dependencies": { + "builder-util-runtime": "9.2.4", + "fs-extra": "^10.1.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "lodash.escaperegexp": "^4.1.2", + "lodash.isequal": "^4.5.0", + "semver": "^7.3.8", + "tiny-typed-emitter": "^2.1.0" + } + }, + "node_modules/electron-updater/node_modules/fs-extra": { + "version": "10.1.0", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron/node_modules/@types/node": { + "version": "18.19.34", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/electronmon": { + "version": "2.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "chalk": "^3.0.0", + "import-from": "^3.0.0", + "runtime-required": "^1.1.0", + "watchboy": "^0.4.3" + }, + "bin": { + "electronmon": "bin/cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/electronmon/node_modules/chalk": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/emittery": { + "version": "0.13.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ensure-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ensure-error/-/ensure-error-4.0.0.tgz", + "integrity": "sha512-7Xenn3+R6tp2UqAbH9Jqs6QCSABQok+1VAhaPaF0jjm3iuhVHCblfBh18nYtpm3K9/V4Jpxz1JIqFZyrjstBtw==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/envinfo": { + "version": "7.13.0", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.3", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "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/es6-error": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/escalade": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.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-config-airbnb": { + "version": "19.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5" + }, + "engines": { + "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "15.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-config-airbnb-base/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-config-airbnb-typescript": { + "version": "17.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", + "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3" + } + }, + "node_modules/eslint-config-erb": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "^6.7.0", + "@typescript-eslint/parser": "^6.7.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-compat": "^4.2.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jest": "^27.4.0", + "eslint-plugin-jsx-a11y": "6.7.1", + "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0" + }, + "engines": { + "node": ">=16.x.x" + }, + "peerDependencies": { + "eslint": ">=7 || >=8", + "jest": ">=27.0.0", + "react": ">=17.0.0 || >=18.0.0" + } + }, + "node_modules/eslint-config-erb/node_modules/ast-types-flow": { + "version": "0.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/eslint-config-erb/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-config-erb/node_modules/eslint-plugin-jsx-a11y": { + "version": "6.7.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.7", + "aria-query": "^5.1.3", + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.6.2", + "axobject-query": "^3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.3", + "language-tags": "=1.0.5", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-config-erb/node_modules/language-tags": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "~0.3.2" + } + }, + "node_modules/eslint-config-erb/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-config-erb/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.1", + "dev": true, + "license": "ISC", + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-import-resolver-webpack": { + "version": "0.13.8", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.find": "^2.2.2", + "debug": "^3.2.7", + "enhanced-resolve": "^0.9.1", + "find-root": "^1.1.0", + "hasown": "^2.0.0", + "interpret": "^1.4.0", + "is-core-module": "^2.13.1", + "is-regex": "^1.1.4", + "lodash": "^4.17.21", + "resolve": "^2.0.0-next.5", + "semver": "^5.7.2" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "eslint-plugin-import": ">=1.4.0", + "webpack": ">=1.11.0" + } + }, + "node_modules/eslint-import-resolver-webpack/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-webpack/node_modules/enhanced-resolve": { + "version": "0.9.1", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.2.0", + "tapable": "^0.1.8" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/eslint-import-resolver-webpack/node_modules/resolve": { + "version": "2.0.0-next.5", + "dev": true, + "license": "MIT", + "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/eslint-import-resolver-webpack/node_modules/semver": { + "version": "5.7.2", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint-import-resolver-webpack/node_modules/tapable": { + "version": "0.1.10", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-compat": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@mdn/browser-compat-data": "^5.3.13", + "ast-metadata-inferer": "^0.8.0", + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001524", + "find-up": "^5.0.0", + "lodash.memoize": "^4.1.2", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=14.x" + }, + "peerDependencies": { + "eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "27.9.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^5.10.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0 || ^7.0.0", + "eslint": "^7.0.0 || ^8.0.0", + "jest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/eslint-scope": { + "version": "5.1.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-plugin-jest/node_modules/estraverse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2", + "aria-query": "^5.3.0", + "array-includes": "^3.1.7", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "=4.7.0", + "axobject-query": "^3.2.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.15", + "hasown": "^2.0.0", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-promise": { + "version": "6.2.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.2", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.19", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.hasown": "^1.1.4", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "dev": true, + "license": "MIT", + "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/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "dev": true, + "license": "BSD-2-Clause", + "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", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "dev": true, + "license": "BSD-2-Clause", + "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/esprima": { + "version": "4.0.1", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/get-stream": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==" + }, + "node_modules/exit": { + "version": "0.1.2", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/express": { + "version": "4.19.2", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.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/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.4.1", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "optional": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "license": "MIT", + "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", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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/filelist": { + "version": "1.0.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/find-root": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.2.1", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "dev": true, + "license": "Unlicense" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "dev": true, + "license": "ISC", + "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/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.5", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "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/goober": { + "version": "2.1.14", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "11.8.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/harmony-reflect": { + "version": "1.6.2", + "dev": true, + "license": "(Apache-2.0 OR MPL-1.1)" + }, + "node_modules/has": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/hasown": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "2.2.0", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "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-parser-js": { + "version": "0.5.8", + "dev": true, + "license": "MIT" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-corefoundation": { + "version": "1.1.7", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "cli-truncate": "^2.1.0", + "node-addon-api": "^1.6.3" + }, + "engines": { + "node": "^8.11.2 || >=10" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/identity-obj-proxy": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "harmony-reflect": "^1.4.6" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "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" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.1", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/immer": { + "version": "10.1.1", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/immutable": { + "version": "4.3.6", + "dev": true, + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-from": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-from/node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ip-address": { + "version": "9.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "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-array-buffer": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-map": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "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-set": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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.13", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/isbinaryfile": { + "version": "5.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.2", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jackspeak": { + "version": "3.4.0", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jake/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-environment-jsdom": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0", + "jsdom": "^20.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-leak-detector/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-util": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jquery": { + "version": "3.7.1", + "license": "MIT" + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "engines": { + "node": ">=14" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "20.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/json2mq": { + "version": "0.2.0", + "license": "MIT", + "dependencies": { + "string-convert": "^0.2.0" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "dev": true, + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/keyboard-key": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keyboard-key/-/keyboard-key-1.1.0.tgz", + "integrity": "sha512-qkBzPTi3rlAKvX7k0/ub44sqOfXeLc/jcnGGmj5c7BJpU8eDrEVPyhCvNYAaoubbsLm9uGWwQJO1ytQK1a9/dQ==" + }, + "node_modules/keyboardevent-from-electron-accelerator": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/keyboardevents-areequal": { + "version": "0.2.2", + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/launch-editor": { + "version": "2.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/lazy-val": { + "version": "1.0.5", + "license": "MIT" + }, + "node_modules/leven": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lilconfig": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "dev": true, + "license": "MIT" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "license": "MIT" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "dev": true, + "license": "ISC" + }, + "node_modules/make-fetch-happen": { + "version": "10.2.1", + "dev": true, + "license": "ISC", + "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", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/matcher": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/material-colors": { + "version": "1.2.6", + "license": "ISC" + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "dev": true, + "license": "Unlicense", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/memory-fs": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.9.0", + "dev": true, + "license": "MIT", + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "license": "ISC", + "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", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "2.1.2", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/minizlib": { + "version": "2.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mousetrap": { + "version": "1.6.5", + "license": "Apache-2.0 WITH LLVM-exception" + }, + "node_modules/mrmime": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/no-case": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-abi": { + "version": "3.65.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "1.7.2", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-api-version": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "9.4.1", + "dev": true, + "license": "MIT", + "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/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.14", + "dev": true, + "license": "MIT" + }, + "node_modules/nopt": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "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/nth-check": { + "version": "2.1.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.10", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "dev": true, + "license": "MIT", + "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.entries": { + "version": "1.1.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.hasown": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "dev": true, + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/param-case": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.2", + "dev": true, + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/plist": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "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" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "9.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "colord": "^2.9.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-convert-values": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-comments": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-empty": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "6.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^6.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-rules": { + "version": "6.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^4.0.2", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "colord": "^2.9.3", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-params": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "6.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "dev": true, + "license": "MIT", + "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.2.0", + "dev": true, + "license": "ISC", + "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", + "dev": true, + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-string": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-url": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-ordered-values": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^3.2.0" + }, + "engines": { + "node": "^14 || ^16 || >= 18" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "6.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/progress": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/psl": { + "version": "1.9.0", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qrcode.react": { + "version": "3.1.0", + "license": "ISC", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "dev": true, + "license": "MIT", + "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/raw-body/node_modules/bytes": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rc-align": { + "version": "4.0.15", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "dom-align": "^1.7.0", + "rc-util": "^5.26.0", + "resize-observer-polyfill": "^1.5.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-cascader": { + "version": "3.26.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "array-tree-filter": "^2.1.0", + "classnames": "^2.3.1", + "rc-select": "~14.14.0", + "rc-tree": "~5.8.1", + "rc-util": "^5.37.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-checkbox": { + "version": "3.3.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.25.2" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-collapse": { + "version": "3.7.3", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.3.4", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-dialog": { + "version": "9.5.2", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/portal": "^1.0.0-8", + "classnames": "^2.2.6", + "rc-motion": "^2.3.0", + "rc-util": "^5.21.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-drawer": { + "version": "7.2.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@rc-component/portal": "^1.1.1", + "classnames": "^2.2.6", + "rc-motion": "^2.6.1", + "rc-util": "^5.38.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-dropdown": { + "version": "3.6.2", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-trigger": "^5.0.4", + "rc-util": "^5.17.0" + }, + "peerDependencies": { + "react": ">=16.11.0", + "react-dom": ">=16.11.0" + } + }, + "node_modules/rc-field-form": { + "version": "2.2.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0", + "@rc-component/async-validator": "^5.0.3", + "rc-util": "^5.32.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-image": { + "version": "7.9.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.2", + "@rc-component/portal": "^1.0.2", + "classnames": "^2.2.6", + "rc-dialog": "~9.5.2", + "rc-motion": "^2.6.2", + "rc-util": "^5.34.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-input": { + "version": "1.5.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.18.1" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/rc-input-number": { + "version": "9.1.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/mini-decimal": "^1.0.1", + "classnames": "^2.2.5", + "rc-input": "~1.5.0", + "rc-util": "^5.40.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-mentions": { + "version": "2.14.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.22.5", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.6", + "rc-input": "~1.5.0", + "rc-menu": "~9.14.0", + "rc-textarea": "~1.7.0", + "rc-util": "^5.34.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-menu": { + "version": "9.14.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^2.0.0", + "classnames": "2.x", + "rc-motion": "^2.4.3", + "rc-overflow": "^1.3.1", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-motion": { + "version": "2.9.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.39.3" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-notification": { + "version": "5.6.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.9.0", + "rc-util": "^5.20.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-overflow": { + "version": "1.3.2", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.37.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-pagination": { + "version": "4.0.4", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.38.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-picker": { + "version": "4.5.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.1", + "rc-overflow": "^1.3.2", + "rc-resize-observer": "^1.4.0", + "rc-util": "^5.38.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "date-fns": ">= 2.x", + "dayjs": ">= 1.x", + "luxon": ">= 3.x", + "moment": ">= 2.x", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + }, + "peerDependenciesMeta": { + "date-fns": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + } + } + }, + "node_modules/rc-progress": { + "version": "4.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-util": "^5.16.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-rate": { + "version": "2.13.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.0.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-resize-observer": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.7", + "classnames": "^2.2.1", + "rc-util": "^5.38.0", + "resize-observer-polyfill": "^1.5.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-segmented": { + "version": "2.3.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-motion": "^2.4.4", + "rc-util": "^5.17.0" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/rc-select": { + "version": "14.14.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^2.1.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-overflow": "^1.3.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-slider": { + "version": "10.6.2", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.36.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-steps": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.16.7", + "classnames": "^2.2.3", + "rc-util": "^5.16.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-switch": { + "version": "4.1.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0", + "classnames": "^2.2.1", + "rc-util": "^5.30.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-table": { + "version": "7.45.7", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/context": "^1.4.0", + "classnames": "^2.2.5", + "rc-resize-observer": "^1.1.0", + "rc-util": "^5.37.0", + "rc-virtual-list": "^3.14.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tabs": { + "version": "15.1.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.2", + "classnames": "2.x", + "rc-dropdown": "~4.2.0", + "rc-menu": "~9.14.0", + "rc-motion": "^2.6.2", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.34.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tabs/node_modules/rc-dropdown": { + "version": "4.2.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.6", + "rc-util": "^5.17.0" + }, + "peerDependencies": { + "react": ">=16.11.0", + "react-dom": ">=16.11.0" + } + }, + "node_modules/rc-textarea": { + "version": "1.7.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-input": "~1.5.0", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tooltip": { + "version": "6.2.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.2", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.3.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tree": { + "version": "5.8.8", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.1" + }, + "engines": { + "node": ">=10.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-tree-select": { + "version": "5.21.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-select": "~14.14.0", + "rc-tree": "~5.8.1", + "rc-util": "^5.16.1" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-trigger": { + "version": "5.3.4", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "classnames": "^2.2.6", + "rc-align": "^4.0.0", + "rc-motion": "^2.0.0", + "rc-util": "^5.19.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-upload": { + "version": "4.5.2", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "classnames": "^2.2.5", + "rc-util": "^5.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-util": { + "version": "5.42.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "react-is": "^18.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-util/node_modules/react-is": { + "version": "18.3.1", + "license": "MIT" + }, + "node_modules/rc-virtual-list": { + "version": "3.14.3", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.0", + "classnames": "^2.2.6", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.36.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-color": { + "version": "2.19.3", + "license": "MIT", + "dependencies": { + "@icons/material": "^0.2.4", + "lodash": "^4.17.15", + "lodash-es": "^4.17.15", + "material-colors": "^1.2.1", + "prop-types": "^15.5.10", + "reactcss": "^1.2.0", + "tinycolor2": "^1.4.1" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, + "node_modules/react-hot-toast": { + "version": "2.4.1", + "license": "MIT", + "dependencies": { + "goober": "^2.1.10" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "license": "MIT" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "license": "MIT" + }, + "node_modules/react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "dependencies": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + }, + "peerDependencies": { + "@popperjs/core": "^2.0.0", + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, + "node_modules/react-redux": { + "version": "9.1.2", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.3", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25", + "react": "^18.0", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-resize-detector": { + "version": "7.1.2", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-router": { + "version": "6.23.1", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.16.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.23.1", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.16.1", + "react-router": "6.23.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-shallow-renderer": { + "version": "16.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-test-renderer": { + "version": "18.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "react-is": "^18.3.1", + "react-shallow-renderer": "^16.15.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-test-renderer/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/reactcss": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "lodash": "^4.0.1" + } + }, + "node_modules/read-binary-file-arch": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "bin": { + "read-binary-file-arch": "cli.js" + } + }, + "node_modules/read-config-file": { + "version": "6.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "config-file-ts": "^0.2.4", + "dotenv": "^9.0.2", + "dotenv-expand": "^5.1.0", + "js-yaml": "^4.1.0", + "json5": "^2.2.0", + "lazy-val": "^1.0.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "dev": true, + "license": "ISC" + }, + "node_modules/renderkid": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/reselect": { + "version": "5.1.1", + "license": "MIT" + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.8", + "dev": true, + "license": "MIT", + "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-alpn": { + "version": "1.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.7", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "10.4.1", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "9.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minipass": { + "version": "7.1.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/runtime-required": { + "version": "1.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/sanitize-filename": { + "version": "1.6.3", + "dev": true, + "license": "WTFPL OR ISC", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/sass": { + "version": "1.77.5", + "dev": true, + "license": "MIT", + "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": "13.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 14.15.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 || ^8.0.0 || ^9.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/sax": { + "version": "1.4.1", + "license": "ISC" + }, + "node_modules/saxes": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "license": "MIT", + "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/schema-utils/node_modules/ajv": { + "version": "8.16.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/scroll-into-view-if-needed": { + "version": "3.1.0", + "license": "MIT", + "dependencies": { + "compute-scroll-into-view": "^3.0.2" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semantic-ui-css": { + "version": "2.5.0", + "license": "MIT", + "dependencies": { + "jquery": "x.*" + } + }, + "node_modules/semantic-ui-react": { + "version": "3.0.0-beta.2", + "resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-3.0.0-beta.2.tgz", + "integrity": "sha512-BFqd7dGPgXPbIkWkIzkPrPRBElf/iB4NKOSFl5tZwMEaIyGQXbvtVWHyOW0sMD2A/qZPgY2Wl/19GDc9JOg3ng==", + "dependencies": { + "@babel/runtime": "^7.23.7", + "@fluentui/react-component-event-listener": "~0.63.0", + "@popperjs/core": "^2.11.8", + "@semantic-ui-react/event-stack": "^3.1.3", + "clsx": "^1.1.1", + "keyboard-key": "^1.1.0", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "prop-types": "^15.7.2", + "react-is": "^16.8.6 || ^17.0.0 || ^18.0.0", + "react-popper": "^2.3.0", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/send": { + "version": "0.18.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "0.13.1", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "dev": true, + "license": "ISC" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "dev": true, + "license": "ISC" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "dev": true, + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sirv": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "dev": true, + "license": "MIT", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawn-command": { + "version": "0.0.2", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/ssri": { + "version": "9.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "dev": true, + "license": "MIT" + }, + "node_modules/stat-mode": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-convert": { + "version": "0.2.1", + "license": "MIT" + }, + "node_modules/string-length": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "3.3.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/stylehacks": { + "version": "6.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/stylis": { + "version": "4.3.2", + "license": "MIT" + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/svgo": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "5.1.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domhandler": { + "version": "5.0.3", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "3.1.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "dev": true, + "license": "MIT" + }, + "node_modules/synckit": { + "version": "0.8.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "dev": true, + "license": "ISC", + "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/node_modules/minipass": { + "version": "5.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/temp-file": { + "version": "3.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "async-exit-hook": "^2.0.1", + "fs-extra": "^10.0.0" + } + }, + "node_modules/temp-file/node_modules/fs-extra": { + "version": "10.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/terser": { + "version": "5.31.1", + "dev": true, + "license": "BSD-2-Clause", + "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", + "dev": true, + "license": "MIT", + "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/jest-worker": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "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/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "dev": true, + "license": "MIT" + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/throttle-debounce": { + "version": "5.0.0", + "license": "MIT", + "engines": { + "node": ">=12.22" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/tiny-typed-emitter": { + "version": "2.1.0", + "license": "MIT" + }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "license": "MIT" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "dev": true, + "license": "WTFPL", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-jest": { + "version": "29.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths-webpack-plugin": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.7.0", + "tsconfig-paths": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/tsconfig-paths": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "dev": true, + "license": "0BSD" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/types": { + "resolved": "@electron/rebuild", + "link": true + }, + "node_modules/typescript": { + "version": "5.4.5", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.38", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "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/undici-types": { + "version": "5.26.5", + "dev": true, + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-filename": { + "version": "2.0.1", + "dev": true, + "license": "ISC", + "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", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unixify": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "normalize-path": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unixify/node_modules/normalize-path": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unzip-crx-3": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "jszip": "^3.1.0", + "mkdirp": "^0.5.1", + "yaku": "^0.16.6" + } + }, + "node_modules/unzip-crx-3/node_modules/mkdirp": { + "version": "0.5.6", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.16", + "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" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "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/url-parse": { + "version": "1.5.10", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/utf8-byte-length": { + "version": "1.0.5", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/utila": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "10.0.0", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.2.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.1", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/watchboy": { + "version": "0.4.3", + "dev": true, + "license": "ISC", + "dependencies": { + "lodash.difference": "^4.5.0", + "micromatch": "^4.0.2", + "pify": "^4.0.1", + "unixify": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "dev": true, + "license": "MIT", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/webpack": { + "version": "5.92.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.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.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "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-bundle-analyzer": { + "version": "4.10.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/ws": { + "version": "7.5.9", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-cli/node_modules/interpret": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "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/websocket-driver": { + "version": "0.7.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "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-builtin-type": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "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-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "dev": true, + "license": "MIT", + "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/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "8.17.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaku": { + "version": "0.16.7", + "dev": true, + "license": "MIT" + }, + "node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..e6369be --- /dev/null +++ b/package.json @@ -0,0 +1,286 @@ +{ + "description": "A foundation for scalable desktop apps", + "keywords": [ + "electron", + "boilerplate", + "react", + "typescript", + "ts", + "sass", + "webpack", + "hot", + "reload" + ], + "homepage": "https://github.com/electron-react-boilerplate/electron-react-boilerplate#readme", + "bugs": { + "url": "https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/electron-react-boilerplate/electron-react-boilerplate.git" + }, + "license": "MIT", + "author": { + "name": "Electron React Boilerplate Maintainers", + "email": "electronreactboilerplate@gmail.com", + "url": "https://electron-react-boilerplate.js.org" + }, + "contributors": [ + { + "name": "Amila Welihinda", + "email": "amilajack@gmail.com", + "url": "https://github.com/amilajack" + } + ], + "main": "./src/main/main.ts", + "scripts": { + "build": "concurrently \"npm run build:main\" \"npm run build:renderer\"", + "build:dll": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts", + "build:main": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts", + "build:renderer": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.prod.ts", + "postinstall": "ts-node .erb/scripts/check-native-dep.js && electron-builder install-app-deps && npm run build:dll", + "lint": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx", + "package": "ts-node ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never && npm run build:dll", + "rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir release/app", + "start": "ts-node ./.erb/scripts/check-port-in-use.js && npm run start:renderer", + "start:main": "cross-env NODE_ENV=development electronmon -r ts-node/register/transpile-only .", + "start:preload": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.preload.dev.ts", + "start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts", + "test": "jest" + }, + "browserslist": [], + "prettier": { + "singleQuote": true, + "overrides": [ + { + "files": [ + ".prettierrc", + ".eslintrc" + ], + "options": { + "parser": "json" + } + } + ] + }, + "jest": { + "moduleDirectories": [ + "node_modules", + "release/app/node_modules", + "src" + ], + "moduleFileExtensions": [ + "js", + "jsx", + "ts", + "tsx", + "json" + ], + "moduleNameMapper": { + "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/.erb/mocks/fileMock.js", + "\\.(css|less|sass|scss)$": "identity-obj-proxy" + }, + "setupFiles": [ + "./.erb/scripts/check-build-exists.ts" + ], + "testEnvironment": "jsdom", + "testEnvironmentOptions": { + "url": "http://localhost/" + }, + "testPathIgnorePatterns": [ + "release/app/dist", + ".erb/dll" + ], + "transform": { + "\\.(ts|tsx|js|jsx)$": "ts-jest" + } + }, + "dependencies": { + "@ant-design/icons": "^5.3.7", + "@antv/x6": "^2.18.1", + "@antv/x6-plugin-clipboard": "^2.1.6", + "@antv/x6-plugin-export": "^2.1.6", + "@antv/x6-plugin-history": "^2.2.4", + "@antv/x6-plugin-keyboard": "^2.2.3", + "@antv/x6-plugin-minimap": "^2.0.7", + "@antv/x6-plugin-selection": "^2.2.2", + "@antv/x6-plugin-snapline": "^2.1.7", + "@antv/x6-plugin-stencil": "^2.1.5", + "@antv/x6-plugin-transform": "^2.1.8", + "@antv/x6-react-components": "^2.0.8", + "@reduxjs/toolkit": "^2.2.5", + "antd": "^5.18.1", + "axios": "^1.7.2", + "copy-webpack-plugin": "^12.0.2", + "crypto-js": "^4.2.0", + "electron-debug": "^3.2.0", + "electron-log": "^4.4.8", + "electron-unhandled": "^5.0.0", + "electron-updater": "^6.1.4", + "js-cookie": "^3.0.5", + "path-browserify": "^1.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-hot-toast": "^2.4.1", + "react-redux": "^9.1.2", + "react-router-dom": "^6.16.0", + "semantic-ui-css": "^2.5.0", + "semantic-ui-react": "^3.0.0-beta.2", + "uuid": "^10.0.0" + }, + "devDependencies": { + "@electron/notarize": "^2.1.0", + "@electron/rebuild": "^3.6.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.11", + "@svgr/webpack": "^8.1.0", + "@teamsupercell/typings-for-css-modules-loader": "^2.5.2", + "@testing-library/jest-dom": "^6.1.3", + "@testing-library/react": "^14.0.0", + "@types/crypto-js": "^4.2.2", + "@types/electron": "^1.6.10", + "@types/jest": "^29.5.5", + "@types/js-cookie": "^3.0.6", + "@types/node": "20.6.2", + "@types/react": "^18.2.21", + "@types/react-beforeunload": "^2.1.5", + "@types/react-dom": "^18.2.7", + "@types/react-test-renderer": "^18.0.1", + "@types/terser-webpack-plugin": "^5.2.0", + "@types/uuid": "^9.0.8", + "@types/webpack-bundle-analyzer": "^4.6.0", + "@typescript-eslint/eslint-plugin": "^6.7.0", + "@typescript-eslint/parser": "^6.7.0", + "browserslist-config-erb": "^0.0.3", + "chalk": "^4.1.2", + "concurrently": "^8.2.1", + "core-js": "^3.32.2", + "cross-env": "^7.0.3", + "css-loader": "^6.11.0", + "css-minimizer-webpack-plugin": "^5.0.1", + "detect-port": "^1.5.1", + "electron": "^26.2.1", + "electron-builder": "^24.6.4", + "electron-devtools-installer": "^3.2.0", + "electronmon": "^2.0.2", + "eslint": "^8.49.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-erb": "^4.1.0-0", + "eslint-import-resolver-typescript": "^3.6.0", + "eslint-import-resolver-webpack": "^0.13.7", + "eslint-plugin-compat": "^4.2.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jest": "^27.4.0", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.3", + "identity-obj-proxy": "^3.0.0", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "mini-css-extract-plugin": "^2.7.6", + "prettier": "^3.0.3", + "react-refresh": "^0.14.0", + "react-test-renderer": "^18.2.0", + "rimraf": "^5.0.1", + "sass": "^1.67.0", + "sass-loader": "^13.3.3", + "style-loader": "^3.3.4", + "terser-webpack-plugin": "^5.3.10", + "ts-jest": "^29.1.1", + "ts-loader": "^9.5.1", + "ts-node": "^10.9.1", + "tsconfig-paths-webpack-plugin": "^4.1.0", + "types": "file:@electron/rebuild", + "typescript": "^5.2.2", + "url-loader": "^4.1.1", + "webpack": "^5.88.2", + "webpack-bundle-analyzer": "^4.9.1", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^4.15.1", + "webpack-merge": "^5.10.0" + }, + "build": { + "productName": "nexTM", + "appId": "org.erb.nexTM", + "asar": true, + "asarUnpack": "**\\*.{node,dll}", + "files": [ + "assets", + "dist", + "node_modules", + "package.json" + ], + "afterSign": ".erb/scripts/notarize.js", + "mac": { + "target": { + "target": "default", + "arch": [ + "arm64", + "x64" + ] + }, + "type": "distribution", + "hardenedRuntime": true, + "entitlements": "assets/entitlements.mac.plist", + "entitlementsInherit": "assets/entitlements.mac.plist", + "gatekeeperAssess": false + }, + "dmg": { + "contents": [ + { + "x": 130, + "y": 220 + }, + { + "x": 410, + "y": 220, + "type": "link", + "path": "/Applications" + } + ] + }, + "win": { + "target": [ + "nsis" + ] + }, + "linux": { + "target": [ + "AppImage" + ], + "category": "Development" + }, + "directories": { + "app": "release/app", + "buildResources": "assets", + "output": "release/build" + }, + "extraResources": [ + { + "from": "./assets", + "to": "assets" + } + ], + "publish": { + "provider": "github", + "owner": "electron-react-boilerplate", + "repo": "electron-react-boilerplate" + } + }, + "collective": { + "url": "https://opencollective.com/electron-react-boilerplate-594" + }, + "devEngines": { + "node": ">=14.x", + "npm": ">=7.x" + }, + "electronmon": { + "patterns": [ + "!**/**", + "src/main/**" + ], + "logLevel": "quiet" + } +} diff --git a/release/app/package-lock.json b/release/app/package-lock.json new file mode 100644 index 0000000..ddf8f0c --- /dev/null +++ b/release/app/package-lock.json @@ -0,0 +1,2841 @@ +{ + "name": "nextm", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "nextm", + "version": "0.1.0", + "hasInstallScript": true, + "license": "AGPL-3.0-only", + "dependencies": { + "fs": "^0.0.1-security", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.20" + }, + "devDependencies": { + "@electron/rebuild": "^3.6.0" + } + }, + "node_modules/@electron/rebuild": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.6.0.tgz", + "integrity": "sha512-zF4x3QupRU3uNGaP5X1wjpmcjfw1H87kyqZ00Tc3HvriV+4gmOGuvQjGNkrJuXdsApssdNyVwLsy+TaeTGGcVw==", + "dev": true, + "dependencies": { + "@malept/cross-spawn-promise": "^2.0.0", + "chalk": "^4.0.0", + "debug": "^4.1.1", + "detect-libc": "^2.0.1", + "fs-extra": "^10.0.0", + "got": "^11.7.0", + "node-abi": "^3.45.0", + "node-api-version": "^0.2.0", + "node-gyp": "^9.0.0", + "ora": "^5.1.0", + "read-binary-file-arch": "^1.0.6", + "semver": "^7.3.5", + "tar": "^6.0.5", + "yargs": "^17.0.1" + }, + "bin": { + "electron-rebuild": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/@electron/rebuild/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==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@electron/rebuild/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", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@electron/rebuild/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==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@electron/rebuild/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@electron/rebuild/node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": 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/@electron/rebuild/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==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": 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/@electron/rebuild/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==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@electron/rebuild/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==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/rebuild/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==", + "dev": 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/@electron/rebuild/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/rebuild/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==", + "dev": 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/@electron/rebuild/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==", + "dev": 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/@electron/rebuild/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==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@electron/rebuild/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==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@electron/rebuild/node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@electron/rebuild/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==", + "dev": true, + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@electron/rebuild/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==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.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==", + "devOptional": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@malept/cross-spawn-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", + "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 12.13.0" + } + }, + "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==", + "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/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==", + "deprecated": "This package is no longer supported.", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "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/@mapbox/node-pre-gyp/node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "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/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "optional": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "optional": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sqltools/formatter": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", + "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==" + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "optional": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.14.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", + "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "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==" + }, + "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==", + "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==", + "devOptional": 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/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/app-root-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", + "engines": { + "node": ">= 6.0.0" + } + }, + "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==" + }, + "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==", + "deprecated": "This package is no longer supported.", + "devOptional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/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" + } + ] + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "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==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "optional": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "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/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-highlight/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "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==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "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==" + }, + "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==", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "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==" + }, + "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==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/dayjs": { + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" + }, + "node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "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==" + }, + "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/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.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==", + "devOptional": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "devOptional": true + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "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==", + "dev": true + }, + "node_modules/foreground-child": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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==", + "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==" + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", + "devOptional": 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/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==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "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/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "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/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "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==" + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "engines": { + "node": "*" + } + }, + "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==", + "devOptional": true + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "optional": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "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==", + "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==", + "devOptional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "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/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" + } + ] + }, + "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==", + "devOptional": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "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/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "devOptional": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "devOptional": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/jackspeak": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "devOptional": true + }, + "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/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/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/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==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "optional": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "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==", + "devOptional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "optional": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "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==", + "devOptional": 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==", + "devOptional": 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==", + "devOptional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "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/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "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==", + "devOptional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-abi": { + "version": "3.65.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", + "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + }, + "node_modules/node-api-version": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.0.tgz", + "integrity": "sha512-fthTTsi8CxaBXMaBAD7ST2uylwvsnYxh2PfaScwpMhos6KlSFajXQPcM4ogNE1q2s3Lbz9GCGqeIHC+C6OZnKg==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + } + }, + "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": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "optional": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.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": ">= 10.12.0" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "deprecated": "This package is no longer supported.", + "devOptional": 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/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/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "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==", + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "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==", + "devOptional": 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==", + "devOptional": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-binary-file-arch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", + "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "bin": { + "read-binary-file-arch": "cli.js" + } + }, + "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/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==" + }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "devOptional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "optional": true + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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==" + }, + "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/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==", + "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==", + "engines": { + "node": ">=8" + } + }, + "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==" + }, + "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==", + "devOptional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "devOptional": true, + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "optional": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "devOptional": true + }, + "node_modules/sqlite3": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.6.tgz", + "integrity": "sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^4.2.0", + "tar": "^6.1.11" + }, + "optionalDependencies": { + "node-gyp": "8.x" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "peerDependenciesMeta": { + "node-gyp": { + "optional": true + } + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "optional": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "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==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "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==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "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/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/typeorm": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.20.tgz", + "integrity": "sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q==", + "dependencies": { + "@sqltools/formatter": "^1.2.5", + "app-root-path": "^3.1.0", + "buffer": "^6.0.3", + "chalk": "^4.1.2", + "cli-highlight": "^2.1.11", + "dayjs": "^1.11.9", + "debug": "^4.3.4", + "dotenv": "^16.0.3", + "glob": "^10.3.10", + "mkdirp": "^2.1.3", + "reflect-metadata": "^0.2.1", + "sha.js": "^2.4.11", + "tslib": "^2.5.0", + "uuid": "^9.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "typeorm": "cli.js", + "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js", + "typeorm-ts-node-esm": "cli-ts-node-esm.js" + }, + "engines": { + "node": ">=16.13.0" + }, + "funding": { + "url": "https://opencollective.com/typeorm" + }, + "peerDependencies": { + "@google-cloud/spanner": "^5.18.0", + "@sap/hana-client": "^2.12.25", + "better-sqlite3": "^7.1.2 || ^8.0.0 || ^9.0.0", + "hdb-pool": "^0.1.6", + "ioredis": "^5.0.4", + "mongodb": "^5.8.0", + "mssql": "^9.1.1 || ^10.0.1", + "mysql2": "^2.2.5 || ^3.0.1", + "oracledb": "^6.3.0", + "pg": "^8.5.1", + "pg-native": "^3.0.0", + "pg-query-stream": "^4.0.0", + "redis": "^3.1.1 || ^4.0.0", + "sql.js": "^1.4.0", + "sqlite3": "^5.0.3", + "ts-node": "^10.7.0", + "typeorm-aurora-data-api-driver": "^2.0.0" + }, + "peerDependenciesMeta": { + "@google-cloud/spanner": { + "optional": true + }, + "@sap/hana-client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "hdb-pool": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "mssql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "pg-query-stream": { + "optional": true + }, + "redis": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "ts-node": { + "optional": true + }, + "typeorm-aurora-data-api-driver": { + "optional": true + } + } + }, + "node_modules/typeorm/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==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typeorm/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/typeorm/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typeorm/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typeorm/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/typeorm/node_modules/mkdirp": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", + "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "optional": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "optional": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "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/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/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "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/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==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "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==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "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==", + "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-cjs": { + "name": "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==", + "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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "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==", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/release/app/package.json b/release/app/package.json new file mode 100644 index 0000000..2bd9149 --- /dev/null +++ b/release/app/package.json @@ -0,0 +1,25 @@ +{ + "name": "nextm", + "version": "0.1.0", + "description": "A portable threat modeling tool for agile development.", + "license": "AGPL-3.0-only", + "author": { + "name": "dkrohmer", + "email": "dkrohmer@proton.me", + "url": "https://github.com/dkrohmer" + }, + "main": "./dist/main/main.js", + "scripts": { + "rebuild": "node -r ts-node/register ../../.erb/scripts/electron-rebuild.js", + "postinstall": "npm run rebuild && npm run link-modules", + "link-modules": "node -r ts-node/register ../../.erb/scripts/link-modules.ts" + }, + "dependencies": { + "fs": "^0.0.1-security", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.20" + }, + "devDependencies": { + "@electron/rebuild": "^3.6.0" + } +} diff --git a/src/__tests__/App.test.tsx b/src/__tests__/App.test.tsx new file mode 100644 index 0000000..6a1de2a --- /dev/null +++ b/src/__tests__/App.test.tsx @@ -0,0 +1,9 @@ +import '@testing-library/jest-dom'; +import { render } from '@testing-library/react'; +import App from '../renderer/App'; + +describe('App', () => { + it('should render', () => { + expect(render()).toBeTruthy(); + }); +}); diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..2fefa2a --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,23 @@ +import { ElectronHandler } from './main/preload'; + +declare global { + // eslint-disable-next-line no-unused-vars + interface Window { + electron: ElectronHandler, + } + + interface DialogOptions { + defaultPath?: string; + filters?: FileFilter[]; + // Add other properties as needed + } + + interface FileFilter { + name: string; + extensions: string[]; + } + + type DialogType = 'file' | 'directory'; +} + +export {}; diff --git a/src/main/controllers/IncrementController.ts b/src/main/controllers/IncrementController.ts new file mode 100644 index 0000000..7434e22 --- /dev/null +++ b/src/main/controllers/IncrementController.ts @@ -0,0 +1,154 @@ +// src/controllers/ProductController.ts + +import { ipcMain } from 'electron'; +import { IncrementService } from '../services/IncrementService'; +import { Increment } from '../models/Increment'; + +function validateSortBy(sortBy: string): boolean { + const validSortByFields = ['name', 'createdAt', 'start', 'end', 'incrementIndex']; + return validSortByFields.includes(sortBy); +} + +function validateSortDirection(sort: string): boolean { + return ['asc', 'desc'].includes(sort); +} + +// src/controllers/IncrementController.ts +export class IncrementController { + private incrementService: IncrementService; + + constructor() { + this.incrementService = new IncrementService(); + this.initializeIncrementHandlers(); + console.log("Increment controllers initialized.") + + } + + destroy() { + ipcMain.removeHandler('create-increment'); + ipcMain.removeHandler('get-all-increments'); + ipcMain.removeHandler('get-increment-by-id'); + ipcMain.removeHandler('get-latest-increment'); + ipcMain.removeHandler('update-increment'); + ipcMain.removeHandler('delete-increment'); + } + + private initializeIncrementHandlers() { + /** + * create-increment + */ + ipcMain.handle('create-increment', async (_event, data: Increment) => { + try { + const increment = await this.incrementService.createIncrement(data); + if (increment) { + + return increment + } else { + throw new Error('Failed to create increment'); + } + } catch (error) { + console.error(error); + } + }); + + /** + * get-all-increments + */ + ipcMain.handle('get-all-increments', async (_event, data) => { + try { + let { sort }: { sort: 'asc' | 'desc' } = data + let { sortby }: { sortby: string } = data || 'createdAt' + const { productId }: { productId: string | undefined } = data + // let sort = data.sort as 'asc' | 'desc'; + // let sortby = data.sortby as string || 'createdAt'; + // const productId = data.productId as string | undefined; + + if (!validateSortBy(sortby)) { + sortby = 'createdAt'; // default sort field if invalid + } + + if (!validateSortDirection(sort)) { + sort = 'desc'; // Default to ascending if invalid + } + + const { increments, incrementsCount } = await this.incrementService.getAllIncrements(sortby, sort, productId); + if (increments) { + return { increments, incrementsCount }; + } else { + throw new Error ('Failed to get increments') + } + } catch (error) { + console.error(error); + } + }); + + /** + * get-increment-by-id + */ + ipcMain.handle('get-increment-by-id', async (_event, data) => { + try { + const { incrementId }: { incrementId: string } = data; + const { isEagerLoading }: { isEagerLoading: boolean } = data; + + const increment = await this.incrementService.getIncrementById(incrementId, isEagerLoading); + + if (increment) { + return increment; + } else { + throw new Error('Failed to get increment'); + } + } catch (error) { + console.error(error); + } + }); + + /** + * get-latest-increment + */ + ipcMain.handle('get-latest-increment', async (_event, data) => { + try { + const { productId }: { productId: string | undefined } = data + const latestIncrement = await this.incrementService.getLatestIncrement(productId); + + if (latestIncrement) { + return latestIncrement + } else { + throw new Error('Failed to get latest increment.') + } + } catch (error) { + console.error(error); + } + }); + + /** + * update-increment + */ + ipcMain.handle('update-increment', async (_event, data) => { + try { + const { incrementId }: {incrementId: string} = data; + const { name }: { name: string} = data; + + const updatedIncrement = await this.incrementService.updateIncrement(incrementId, { name }); + if (updatedIncrement) { + return updatedIncrement + } else { + throw new Error('Failed to update increment'); + } + } catch (error) { + console.error(error); + } + }); + + /** + * delete-increment + */ + ipcMain.handle('delete-increment', async (_event, data) => { + try { + const { incrementId }: { incrementId: string } = data; + await this.incrementService.deleteIncrement(incrementId); + } catch (error) { + console.error(error); + } + }); + } +} diff --git a/src/main/controllers/ModelController.ts b/src/main/controllers/ModelController.ts new file mode 100644 index 0000000..f9eac5f --- /dev/null +++ b/src/main/controllers/ModelController.ts @@ -0,0 +1,126 @@ +// src/controllers/ProductController.ts + +import { ipcMain } from 'electron'; +import { ModelService } from '../services/ModelService'; + +function validateSortBy(sortBy: string): boolean { + const validSortByFields = ['name', 'createdAt']; + return validSortByFields.includes(sortBy); +} + +function validateSortDirection(sort: string): boolean { + return ['asc', 'desc'].includes(sort); +} + +// src/controllers/ModelController.ts +export class ModelController { + private modelService: ModelService; + + constructor() { + this.modelService = new ModelService(); + this.initializeModelHandlers(); + console.log("Model controllers initialized.") + + } + + destroy() { + ipcMain.removeHandler('create-model'); + ipcMain.removeHandler('get-all-models'); + ipcMain.removeHandler('get-model-by-id'); + ipcMain.removeHandler('update-model'); + ipcMain.removeHandler('delete-model'); + } + + private initializeModelHandlers() { + /** + * create-model + */ + ipcMain.handle('create-model', async (_event, data) => { + try { + const model = await this.modelService.createModel(data); + return model + } catch (error) { + console.error(error); + } + }); + + /** + * get-all-models + */ + ipcMain.handle('get-all-models', async (_event, data) => { + try { + let sort = data.sort as 'asc' | 'desc'; + let sortby = data.sortby as string || 'createdAt'; + const incrementId = data.incrementId as string | undefined; + + if (!validateSortBy(sortby)) { + sortby = 'createdAt'; // default sort field if invalid + } + + if (!validateSortDirection(sort)) { + sort = 'desc'; // Default to ascending if invalid + } + + const { models, modelsCount } = await this.modelService.getAllModels(sortby, sort, incrementId); + + if (models) { + return { models, modelsCount } + } else { + throw new Error('Failed to get models') + } + } catch (error) { + console.error(error); + } + }); + + /** + * get-model-by-id + */ + ipcMain.handle('get-model-by-id', async (_event, data) => { + try { + const { modelId } = data; + const { isEagerLoading }: { isEagerLoading: boolean } = data; + + const model = await this.modelService.getModelById(modelId, isEagerLoading); + if (model) { + return model + } else { + throw new Error('Failed to get model') + } + } catch (error) { + console.error(error); + } + }); + + /** + * update-model + */ + ipcMain.handle('update-model', async (_event, data) => { + try { + const { id }: { id: string } = data; + const { name }: { name: string } = data; + + const updatedModel = await this.modelService.updateModel(id, { name }); + if (updatedModel) { + return updatedModel + } else { + throw new Error('Failed to update model') + } + } catch (error) { + console.error(error) + } + }); + + /** + * delete-model + */ + ipcMain.handle('delete-model', async (_event, data) => { + try { + const { modelId } = data + await this.modelService.deleteModel(modelId); + } catch (error) { + console.error(error) + } + }); + } +} diff --git a/src/main/controllers/ProductController.ts b/src/main/controllers/ProductController.ts new file mode 100644 index 0000000..05280b4 --- /dev/null +++ b/src/main/controllers/ProductController.ts @@ -0,0 +1,131 @@ +// src/controllers/ProductController.ts + +import { ipcMain } from 'electron'; +import { ProductService } from '../services/ProductService'; +import { Product } from '../models/Product'; +import { Responsible } from '../models/Responsible'; + +function validateSortBy(sortby: string): boolean { + const validSortByFields = ['name', 'createdAt', 'description', 'startsAt', 'endsAt']; + return validSortByFields.includes(sortby); +} + +function validateSortDirection(sort: string): boolean { + return ['asc', 'desc'].includes(sort); +} + +// src/controllers/ProductController.ts +export class ProductController { + private productService: ProductService; + + constructor() { + this.productService = new ProductService(); + this.initializeProductHandlers(); + } + + destroy() { + ipcMain.removeHandler('create-product'); + ipcMain.removeHandler('get-all-products'); + ipcMain.removeHandler('get-product-by-id'); + ipcMain.removeHandler('update-product'); + ipcMain.removeHandler('delete-product'); + } + + private initializeProductHandlers() { + /** + * get-all-products + */ + ipcMain.handle('get-all-products', async (_event, data) => { + try { + const limit = parseInt(data.limit as string) || 10; + const offset = parseInt(data.offset as string) || 0; + let sort = data.sort as 'asc' | 'desc'; + let sortby = data.sortby as string || 'createdAt'; + + if (!validateSortBy(sortby)) { + sortby = 'createdAt'; // default sort field + } + + if (!validateSortDirection(sort)) { + sort = 'desc'; // Default to descending + } + + const { products, productsCount } = await this.productService.getAllProducts(limit, offset, sort, sortby); + + if (products) { + return { products, productsCount }; + } else { + throw new Error ('Failed to get products') + } + } catch (error) { + console.error(error); + } + }); + + /** + * get-product-by-id + */ + ipcMain.handle('get-product-by-id', async (_event, data) => { + try { + const { productId } = data; + const { isEagerLoading }: { isEagerLoading: boolean } = data; + + const product = await this.productService.getProductById(productId, isEagerLoading); + + if (product) { + return product + } else { + throw new Error ('Failed to get product') + } + } catch (error) { + console.error(error); + } + }); + + /** + * create-product + */ + ipcMain.handle('create-product', async (_event, data: Product) => { + try { + const result = await this.productService.createProduct(data); + return result + } catch (error) { + console.error(error); + } + }); + + /** + * update-product + */ + ipcMain.handle('update-product', async (_event, data) => { + try { + const { productId }: { productId: string } = data; + const { product }: { product: any } = data; + + const { increments, ...filteredProduct } = product; // we don't want increments to be included + + const updatedProduct = await this.productService.updateProduct(productId, filteredProduct); + + if (updatedProduct) { + return updatedProduct + } else { + throw new Error('Failed to update product') + } + } catch (error) { + console.error(error) + } + }); + + /** + * delete-product + */ + ipcMain.handle('delete-product', async (_event, data) => { + try { + const { productId }: { productId: string } = data; + await this.productService.deleteProduct(productId); + } catch (error) { + console.error(error) + } + }); + } +} diff --git a/src/main/controllers/VersionController.ts b/src/main/controllers/VersionController.ts new file mode 100644 index 0000000..909326c --- /dev/null +++ b/src/main/controllers/VersionController.ts @@ -0,0 +1,141 @@ +// src/controllers/ProductController.ts + +import { ipcMain } from 'electron'; +import { VersionService } from '../services/VersionService'; + +function validateSortDirection(sort: string): boolean { + return ['asc', 'desc'].includes(sort); +} + + +// src/controllers/ModelController.ts +export class VersionController { + private versionService: VersionService; + + constructor() { + this.versionService = new VersionService(); + this.initializeModelHandlers(); + } + + destroy() { + ipcMain.removeHandler('create-version'); + ipcMain.removeHandler('get-all-versions'); + ipcMain.removeHandler('get-version-by-id'); + ipcMain.removeHandler('get-latest-version'); + ipcMain.removeHandler('delete-version'); + } + + private initializeModelHandlers() { + /** + * create-version + */ + ipcMain.handle('create-version', async (_event, data) => { + try { + const { modelId }: { modelId: string } = data + const { payload }: { payload: any } = data + const { thumbnail }: { thumbnail: string } = data + const { x }: { x: number } = data + const { y }: { y: number } = data + const { width }: { width: number } = data + const { height }: { height: number } = data + + const graphJson = JSON.stringify(payload.graph) + + const newVersion = await this.versionService.createVersion({ modelId, thumbnail, payload: graphJson, x, y, width, height }); + + // Return the created version with the graph still as an object for immediate use + return { ...newVersion, payload: graphJson }; + } catch (error) { + console.error(error); + } + }); + + /** + * get-all-versions + */ + ipcMain.handle('get-all-versions', async (_event, data) => { + try { + let sort = data.sort as 'asc' | 'desc'; + let sortby = data.sortby as string || 'createdAt'; + const modelId = data.modelId as string | undefined; + + sortby = 'createdAt'; // default sort field if invalid + + if (!validateSortDirection(sort)) { + sort = 'desc'; // Default to ascending if invalid + } + + const { versions, versionsCount } = await this.versionService.getAllVersions(sortby, sort, modelId); + + if (versions) { + return { versions, versionsCount } + } else { + throw new Error('Failed to get versions') + } + } catch (error) { + console.error(error); + } + }); + + /** + * get-version-by-id + */ + ipcMain.handle('get-version-by-id', async (_event, data) => { + try { + const { versionId }: { versionId: string } = data + const version = await this.versionService.getVersionById(versionId); + if (version) { + const payloadWithParsedGraph = { + ...version, + payload: JSON.parse(version.payload) // Parse the payload back to JSON object + }; + return payloadWithParsedGraph + } else { + throw new Error('Failed to get version') + } + } catch (error) { + console.error(error); + } + }); + + /** + * get-latest-version + */ + ipcMain.handle('get-latest-version', async (_event, data) => { + try { + const modelId = data.modelId as string; + + if (!modelId) { + throw new Error('No modelId provided') + } + + const latestVersion = await this.versionService.getLatestVersionByModelId(modelId); + if (latestVersion) { + const payloadWithParsedGraph = { + ...latestVersion, + payload: JSON.parse(latestVersion.payload), + }; + // console.log(payloadWithParsedGraph) + + return payloadWithParsedGraph + } else { + throw new Error('Failed to get latest version') + } + } catch (error) { + console.error(error); + } + }); + + /** + * delete-version + */ + ipcMain.handle('delete-version', async (_event, data) => { + try { + const { modelId }: { modelId: string } = data + await this.versionService.deleteVersion(modelId); + } catch (error) { + console.error(error) + } + }); + } +} diff --git a/src/main/database.ts b/src/main/database.ts new file mode 100644 index 0000000..d236330 --- /dev/null +++ b/src/main/database.ts @@ -0,0 +1,61 @@ +import { DataSource } from 'typeorm'; + +import { Product } from './models/Product'; +import { Increment } from './models/Increment'; +import { Model } from './models/Model'; +import { Version } from './models/Version'; +import { Responsible } from './models/Responsible'; +import { IncrementController } from './controllers/IncrementController'; +import { ModelController } from './controllers/ModelController'; +import { ProductController } from './controllers/ProductController'; +import { VersionController } from './controllers/VersionController'; + +export let AppDataSource: DataSource; +// export const AppDataSource = new DataSource({ +// type: 'sqlite', +// database: 'database.sqlite', +// synchronize: true, +// logging: false, +// entities: [Product, Responsible, Increment], +// }); + +export const initializeDataSource = async (databasePath: string) => { + console.log(`Initializing data source with database path: ${databasePath}`); + + if (AppDataSource && AppDataSource.isInitialized) { + console.log("Destroying existing data source..."); + await AppDataSource.destroy(); + } + + AppDataSource = new DataSource({ + type: 'sqlite', + database: databasePath, + synchronize: true, + logging: false, + entities: [ + Product, + Increment, + Model, + Version, + Responsible + ], + migrations: [], + subscribers: [], + }); + + const response = await AppDataSource.initialize(); + + if (response) { + console.log("Data source initialized successfully at: ", databasePath); + return true + } else { + return false; + } +}; + +export function getDataSource() { + if (!AppDataSource || !AppDataSource.isInitialized) { + throw new Error('Database connection is not established'); + } + return AppDataSource; +} diff --git a/src/main/helpers/entityBuilder.ts b/src/main/helpers/entityBuilder.ts new file mode 100644 index 0000000..e634093 --- /dev/null +++ b/src/main/helpers/entityBuilder.ts @@ -0,0 +1,104 @@ +// helpers.ts +import { Product } from '../models/Product'; +import { Responsible } from '../models/Responsible'; +import { Increment } from '../models/Increment'; +import { Model } from '../models/Model'; +import { Version } from '../models/Version'; + +export function buildProductEntity(productData: Product): Product { + const { name, description, startsAt, endsAt, increments, responsibles } = productData; + + const product = new Product(); + product.name = name; + product.description = description ?? null; + product.startsAt = startsAt ? new Date(startsAt) : null; + product.endsAt = endsAt ? new Date(endsAt) : null; + + if (endsAt && startsAt && new Date(endsAt) < new Date(startsAt)) { + throw new Error('The end date cannot be earlier than the start date.'); + } + + if (increments && increments.length > 0) { + product.increments = increments.map((incrementData: Increment, index: number) => buildIncrementEntity(incrementData, index)); + } else { + const incrementData = { + name: `${product.name} - Baseline` + } + product.increments = [] + product.increments.push(buildIncrementEntity(incrementData, 0)) + } + + if (responsibles && responsibles.length > 0) { + product.responsibles = responsibles.map((responsibleData: Responsible) => buildResponsibleEntity(responsibleData)); + } + return product; +} + +export function buildResponsibleEntity(responsibleData: Responsible): Responsible { + const { firstName, lastName, role } = responsibleData; + + const responsible = new Responsible(); + responsible.firstName = firstName; + responsible.lastName = lastName; + responsible.role = role ?? null; + + return responsible; +} + +export function buildIncrementEntity(incrementData: any, index: number): Increment { + const { name, incrementIndex, models } = incrementData; + + const increment = new Increment(); + increment.name = name; + + if (incrementIndex !== undefined && incrementIndex !== null) { + increment.incrementIndex = incrementIndex; + } else { + increment.incrementIndex = index + } + + if (models && models.length > 0) { + increment.models = models.map((modelData: Model) => buildModelEntity(modelData)); + } + return increment; +} + +export function buildModelEntity(modelData: Model): Model { + const { name, versions } = modelData; + + const model = new Model(); + model.name = name; + if (versions && versions.length > 0) { + model.versions = versions.map((versionData: any, index: number) => buildVersionEntity(versionData, index)); + } + else { + const versionData = { + payload: "{}", + thumbnail: "" + } + model.versions = [] + model.versions.push(buildVersionEntity(versionData, 0)) + } + return model; +} + +export function buildVersionEntity(versionData: any, index: number): Version { + const { payload, thumbnail, versionIndex, x, y, height, width } = versionData; + + const version = new Version(); + + if (versionIndex !== undefined && versionIndex !== null) { + version.versionIndex = versionIndex; + } else { + version.versionIndex = index + } + + version.payload = payload; + version.thumbnail = thumbnail; + version.x = x; + version.y = y; + version.height = height; + version.width = width; + + return version; +} diff --git a/src/main/main.ts b/src/main/main.ts new file mode 100644 index 0000000..d343cc9 --- /dev/null +++ b/src/main/main.ts @@ -0,0 +1,475 @@ +/* eslint global-require: off, no-console: off, promise/always-return: off */ + +/** + * This module executes inside of electron's main process. You can start + * electron renderer process from here and communicate with the other processes + * through IPC. + * + * When running `npm run build` or `npm run build:main`, this file is compiled to + * `./src/main.js` using webpack. This gives us some performance wins. + */ +import fs from 'fs'; +import path from 'path'; +import { app, BrowserWindow, shell, ipcMain, screen, dialog, Product } from 'electron'; +import { autoUpdater } from 'electron-updater'; +import log from 'electron-log'; +import MenuBuilder from './menu'; +import { resolveHtmlPath } from './util'; + +import { initializeDataSource } from './database'; // Import the database initialization function +import { IncrementController } from './controllers/IncrementController'; +import { ModelController } from './controllers/ModelController'; +import { ProductController } from './controllers/ProductController'; +import { VersionController } from './controllers/VersionController'; +import { ConsoleSqlOutlined } from '@ant-design/icons'; +import { Increment } from './models/Increment'; +import { version } from 'os'; +import { Version } from './models/Version'; +import { fixedDot } from '@antv/x6/lib/registry/grid/fixed-dot'; + +let isQuitting: boolean = false + +let productController: ProductController; +let incrementController: IncrementController; +let modelController: ModelController; +let versionController: VersionController; + +const configPath: string = (process.env.NODE_ENV === 'development') +? 'nextm.conf' +: path.resolve(app.getPath('userData'), 'nextm.conf'); + +const getDefaultDbPath = () => { + const dbPath = (process.env.NODE_ENV === 'development') + ? 'nextm.db' + : path.resolve(app.getPath('userData'), 'nextm.db'); + return dbPath; +} + +// const setCurrentDbPath = (dbPath: string) => { +// const config = { databasePath: dbPath } +// fs.writeFileSync(configPath, JSON.stringify(config), 'utf-8') +// } + +// const getCurrentDbPath = () => { +// if (fs.existsSync(configPath)) { +// const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')) +// return config.databasePath +// } else { +// return null; +// } +// } + +interface Config { + [key: string]: string; +} + +const setConfig = (configKey: string, configValue: string) => { + let config: Config = {}; + if (fs.existsSync(configPath)) { + config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); + } + config[configKey] = configValue; + fs.writeFileSync(configPath, JSON.stringify(config), 'utf-8'); +} + +const getConfig = (configKey: string) => { + if (fs.existsSync(configPath)) { + const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); + return config[configKey]; + } else { + return null; + } +} + +const initializeControllers = () => { + if (productController) { + productController.destroy(); + } + if (incrementController) { + incrementController.destroy(); + } + if (modelController) { + modelController.destroy(); + } + if (versionController) { + versionController.destroy(); + } + + productController = new ProductController(); + incrementController = new IncrementController(); + modelController = new ModelController(); + versionController = new VersionController(); +} + +import( 'electron-unhandled') + .then((m) => { + console.log("Loeded electron-unhandled") + }) + .catch(err => { + console.error('Error during loading module: ' + err) + }) + +class AppUpdater { + constructor() { + log.transports.file.level = 'info'; + autoUpdater.logger = log; + autoUpdater.checkForUpdatesAndNotify(); + } +} + +let mainWindow: BrowserWindow | null = null; + +if (process.env.NODE_ENV === 'production') { + const sourceMapSupport = require('source-map-support'); + sourceMapSupport.install(); +} + +const isDebug = + process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true'; + +if (isDebug) { + require('electron-debug')(); +} + +const installExtensions = async () => { + const installer = require('electron-devtools-installer'); + const forceDownload = !!process.env.UPGRADE_EXTENSIONS; + const extensions = ['REACT_DEVELOPER_TOOLS']; + + return installer + .default( + extensions.map((name) => installer[name]), + forceDownload, + ) + .catch(console.log); +}; + +const createWindow = async () => { + if (isDebug) { + await installExtensions(); + } + + const RESOURCES_PATH = app.isPackaged + ? path.join(process.resourcesPath, 'assets') + : path.join(__dirname, '../../assets'); + + const getAssetPath = (...paths: string[]): string => { + return path.join(RESOURCES_PATH, ...paths); + }; + + const { width, height } = screen.getPrimaryDisplay().workAreaSize; + + mainWindow = new BrowserWindow({ + show: false, + width: width, + height: height, + icon: getAssetPath('icon.png'), + webPreferences: { + preload: process.env.NODE_ENV === 'development' + ? path.join(__dirname, '../../.erb/dll/preload.js') + : path.join(__dirname, 'preload.js') + // preload: app.isPackaged + // ? path.join(__dirname, 'preload.js') + // : path.join(__dirname, '../../.erb/dll/preload.js'), + // preload: path.join(__dirname, 'preload.js') + }, + }); + + mainWindow.loadURL(resolveHtmlPath('index.html')); + + if (process.env.NODE_ENV === 'development') { + mainWindow.webContents.openDevTools(); + } + + /** + * mainWindow listeners + */ + mainWindow.on('ready-to-show', async () => { + if (!mainWindow) { + throw new Error('"mainWindow" is not defined'); + } + if (process.env.START_MINIMIZED) { + mainWindow.minimize(); + } else { + mainWindow.show(); + } + }); + + mainWindow.on('close', (event) => { + if (!isQuitting) { + event.preventDefault(); + dialog.showMessageBox(mainWindow!, { + type: 'warning', // Set to 'warning' to enable the icon + buttons: ['Cancel', 'Quit'], + defaultId: 1, + cancelId: 0, + title: 'Confirm', + message: 'Do you really want to quit?', + detail: 'All unsaved changes will be lost.', + icon: getAssetPath('icon.png'), // Path to your custom icon + }).then(result => { + if (result.response === 1) { // 'Quit' button + isQuitting = true; + app.quit(); + } + }); + } + }); + + mainWindow.on('closed', () => { + mainWindow = null; + }); + + + /** + * IPC handlers + */ + ipcMain.handle('open-file-dialog', async (event) => { + try { + if (!mainWindow) { + throw new Error('Main window is not ready'); + } + + const result = await dialog.showOpenDialog(mainWindow!, { + properties: ['openFile'], + filters: [ + { name: 'Database Files', extensions: ['db', 'sqlite'] } + ], + // multiSelections: false + }); + if (!result.canceled && result.filePaths.length > 0) { + return result.filePaths[0]; + } else { + throw new Error('No file selected'); + } + } catch (error) { + console.error('Error opening file dialog:', error); + throw error; + } + }); + + ipcMain.handle('open-directory-dialog', async (event) => { + try { + if (!mainWindow) { + throw new Error('Main window is not ready'); + } + + const result = await dialog.showOpenDialog(mainWindow, { + properties: ['openDirectory'] // Ensure 'openDirectory' is in an array of allowed properties + }); + + if (!result.canceled && result.filePaths.length > 0) { + return result.filePaths[0]; + } else { + throw new Error('No directory selected'); + } + } catch (error) { + console.error('Error opening directory dialog:', error); + throw error; + } + }); + + ipcMain.handle('create-database', async (event, input) => { + try { + // Check if the directory exists + fs.accessSync(input, fs.constants.F_OK); + + // Generate a unique file name if file already exists + let count = 1; + let dbPath = input; + + console.log(input) + + while (true) { + try { + const filename = `nextm${count >= 2 ? count : ''}.db`; + dbPath = path.join(input, filename); + + if (fs.existsSync(dbPath)) { + count++ + continue + } else { + break + } + } catch (error) { + break; // Break the loop if the file does not exist + } + } + + // Perform any other checks or validations as needed + // For now, assuming directory exists and filename is unique + + // Call initialization function + const result = await initializeDataSource(dbPath); // Adjust function call as per your logic + + if (result) { + // persist current dbPath in config file + setConfig('databasePath', dbPath); + initializeControllers() + return { success: true, message: 'Database created successfully' };; + } else { + return { success: false, message: 'Failed to create database' }; + } + } catch (error) { + console.error('Error creating database:', error); + return { success: false, message: error }; + } + }); + + ipcMain.handle('open-database', async (event, input) => { + try { + console.log(input); + let dbPath = input; + + // Check if the file exists + if (input === 'default') { + dbPath = (process.env.NODE_ENV === 'development') + ? 'nextm.db' + : path.resolve(app.getPath('userData'), 'nextm.db'); + } else if (fs.existsSync(input)) { + dbPath = input; + } else { + return { success: false, message: 'Invalid input specified' }; + } + + const result = await initializeDataSource(dbPath); + + if (result) { + // persist current dbPath in config file + setConfig('databasePath', dbPath); + initializeControllers(); + return { success: true, message: 'Database opened successfully' }; + } else { + return { success: false, message: 'Unable to open database' }; + } + } catch (error) { + console.error(error); + return { success: false, error: error }; + } + }); + + ipcMain.handle('get-default-db-path', async (event) => { + return getDefaultDbPath(); + }); + + ipcMain.handle('get-current-db-path', async (event) => { + return getConfig('databasePath'); + }); + + ipcMain.handle('set-grid-type', async (event, input) => { + try { + if (input === 'none' || 'dot' || 'mesh') { + setConfig('gridType', input) + return { success: false, message: 'Grid type set successfully' }; + } + } catch (error) { + console.error(error); + return { success: false, error: error } + } + }) + + ipcMain.handle('get-grid-type', async (event) => { + return getConfig('gridType'); + }) + + ipcMain.handle('set-explicit-object-selection', async (event, input) => { + try { + if (input === true || false) { + setConfig('explicitObjectSelection', input) + return { success: false, message: 'Grid type set successfully' }; + } + } catch (error) { + console.error(error); + return { success: false, error: error } + } + }) + + ipcMain.handle('get-explicit-object-selection', async (event) => { + return getConfig('explicitObjectSelection'); + }) + + const menuBuilder = new MenuBuilder(mainWindow); + menuBuilder.buildMenu(); + + // Open urls in the user's browser + mainWindow.webContents.setWindowOpenHandler((edata) => { + shell.openExternal(edata.url); + return { action: 'deny' }; + }); + + // Remove this if your app does not use auto updates + // eslint-disable-next-line + + // new AppUpdater(); +}; + +/** + * Add event listeners... + */ + // Listen for before-quit event + // app.on('before-quit', (event) => { + // console.log("ipcMain: Quit triggered") + // // Send the 'before-quit' event to the renderer process + // if (mainWindow) { + // mainWindow.webContents.send('pong'); + // // Delay the quit to ensure the renderer process has time to handle the event + // event.preventDefault(); + // setTimeout(() => { + // app.quit(); + // }, 3000); + // } + // }); + +let isModelSaved = false; + +// app.on('before-quit', (event) => { +// if (!isModelSaved) { +// // Prevent the default action (quit) +// event.preventDefault(); +// // Send a message to the renderer process to save the model +// if (mainWindow) { +// console.log("[ipcMain] Sending..."); +// mainWindow.webContents.send('save-model'); +// console.log("[ipcMain] Sending done"); +// } +// // Listen for the response from the renderer process +// ipcMain.once('model-saved', () => { +// isModelSaved = true; +// // Quit the app after the model is saved +// app.quit(); +// }); +// } +// }); + +app.on('window-all-closed', () => { + // Respect the OSX convention of having the application in memory even + // after all windows have been closed + if (process.platform !== 'darwin') { + app.quit(); + } +}); + +app + .whenReady() + .then(async() => { + + let dbPath = getConfig('databasePath') + + if (!dbPath) { + dbPath = getDefaultDbPath() + setConfig('databasePath', dbPath) + } + + // const databasePath = path.join(__dirname, '..', 'nextm.db'); + await initializeDataSource(dbPath); // Initialize the data source + initializeControllers(); + + createWindow(); + + app.on('activate', () => { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (mainWindow === null) createWindow(); + }); + }) + .catch(console.log); diff --git a/src/main/menu.ts b/src/main/menu.ts new file mode 100644 index 0000000..ba0fb77 --- /dev/null +++ b/src/main/menu.ts @@ -0,0 +1,290 @@ +import { + app, + Menu, + shell, + BrowserWindow, + MenuItemConstructorOptions, +} from 'electron'; + +interface DarwinMenuItemConstructorOptions extends MenuItemConstructorOptions { + selector?: string; + submenu?: DarwinMenuItemConstructorOptions[] | Menu; +} + +export default class MenuBuilder { + mainWindow: BrowserWindow; + + constructor(mainWindow: BrowserWindow) { + this.mainWindow = mainWindow; + } + + buildMenu(): Menu { + if ( + process.env.NODE_ENV === 'development' || + process.env.DEBUG_PROD === 'true' + ) { + this.setupDevelopmentEnvironment(); + } + + const template = + process.platform === 'darwin' + ? this.buildDarwinTemplate() + : this.buildDefaultTemplate(); + + const menu = Menu.buildFromTemplate(template); + Menu.setApplicationMenu(menu); + + return menu; + } + + setupDevelopmentEnvironment(): void { + this.mainWindow.webContents.on('context-menu', (_, props) => { + const { x, y } = props; + + Menu.buildFromTemplate([ + { + label: 'Inspect element', + click: () => { + this.mainWindow.webContents.inspectElement(x, y); + }, + }, + ]).popup({ window: this.mainWindow }); + }); + } + + buildDarwinTemplate(): MenuItemConstructorOptions[] { + const subMenuAbout: DarwinMenuItemConstructorOptions = { + label: 'Electron', + submenu: [ + { + label: 'About ElectronReact', + selector: 'orderFrontStandardAboutPanel:', + }, + { type: 'separator' }, + { label: 'Services', submenu: [] }, + { type: 'separator' }, + { + label: 'Hide ElectronReact', + accelerator: 'Command+H', + selector: 'hide:', + }, + { + label: 'Hide Others', + accelerator: 'Command+Shift+H', + selector: 'hideOtherApplications:', + }, + { label: 'Show All', selector: 'unhideAllApplications:' }, + { type: 'separator' }, + { + label: 'Quit', + accelerator: 'Command+Q', + click: () => { + app.quit(); + }, + }, + ], + }; + const subMenuEdit: DarwinMenuItemConstructorOptions = { + label: 'Edit', + submenu: [ + { label: 'Undo', accelerator: 'Command+Z', selector: 'undo:' }, + { label: 'Redo', accelerator: 'Shift+Command+Z', selector: 'redo:' }, + { type: 'separator' }, + { label: 'Cut', accelerator: 'Command+X', selector: 'cut:' }, + { label: 'Copy', accelerator: 'Command+C', selector: 'copy:' }, + { label: 'Paste', accelerator: 'Command+V', selector: 'paste:' }, + { + label: 'Select All', + accelerator: 'Command+A', + selector: 'selectAll:', + }, + ], + }; + const subMenuViewDev: MenuItemConstructorOptions = { + label: 'View', + submenu: [ + { + label: 'Reload', + accelerator: 'Command+R', + click: () => { + this.mainWindow.webContents.reload(); + }, + }, + { + label: 'Toggle Full Screen', + accelerator: 'Ctrl+Command+F', + click: () => { + this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen()); + }, + }, + { + label: 'Toggle Developer Tools', + accelerator: 'Alt+Command+I', + click: () => { + this.mainWindow.webContents.toggleDevTools(); + }, + }, + ], + }; + const subMenuViewProd: MenuItemConstructorOptions = { + label: 'View', + submenu: [ + { + label: 'Toggle Full Screen', + accelerator: 'Ctrl+Command+F', + click: () => { + this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen()); + }, + }, + ], + }; + const subMenuWindow: DarwinMenuItemConstructorOptions = { + label: 'Window', + submenu: [ + { + label: 'Minimize', + accelerator: 'Command+M', + selector: 'performMiniaturize:', + }, + { label: 'Close', accelerator: 'Command+W', selector: 'performClose:' }, + { type: 'separator' }, + { label: 'Bring All to Front', selector: 'arrangeInFront:' }, + ], + }; + const subMenuHelp: MenuItemConstructorOptions = { + label: 'Help', + submenu: [ + { + label: 'Learn More', + click() { + shell.openExternal('https://electronjs.org'); + }, + }, + { + label: 'Documentation', + click() { + shell.openExternal( + 'https://github.com/electron/electron/tree/main/docs#readme', + ); + }, + }, + { + label: 'Community Discussions', + click() { + shell.openExternal('https://www.electronjs.org/community'); + }, + }, + { + label: 'Search Issues', + click() { + shell.openExternal('https://github.com/electron/electron/issues'); + }, + }, + ], + }; + + const subMenuView = + process.env.NODE_ENV === 'development' || + process.env.DEBUG_PROD === 'true' + ? subMenuViewDev + : subMenuViewProd; + + return [subMenuAbout, subMenuEdit, subMenuView, subMenuWindow, subMenuHelp]; + } + + buildDefaultTemplate() { + const templateDefault = [ + { + label: '&File', + submenu: [ + { + label: '&Open', + accelerator: 'Ctrl+O', + }, + { + label: '&Close', + accelerator: 'Ctrl+W', + click: () => { + this.mainWindow.close(); + }, + }, + ], + }, + { + label: '&View', + submenu: + process.env.NODE_ENV === 'development' || + process.env.DEBUG_PROD === 'true' + ? [ + { + label: '&Reload', + accelerator: 'Ctrl+R', + click: () => { + this.mainWindow.webContents.reload(); + }, + }, + { + label: 'Toggle &Full Screen', + accelerator: 'F11', + click: () => { + this.mainWindow.setFullScreen( + !this.mainWindow.isFullScreen(), + ); + }, + }, + { + label: 'Toggle &Developer Tools', + accelerator: 'Alt+Ctrl+I', + click: () => { + this.mainWindow.webContents.toggleDevTools(); + }, + }, + ] + : [ + { + label: 'Toggle &Full Screen', + accelerator: 'F11', + click: () => { + this.mainWindow.setFullScreen( + !this.mainWindow.isFullScreen(), + ); + }, + }, + ], + }, + { + label: 'Help', + submenu: [ + { + label: 'Learn More', + click() { + shell.openExternal('https://electronjs.org'); + }, + }, + { + label: 'Documentation', + click() { + shell.openExternal( + 'https://github.com/electron/electron/tree/main/docs#readme', + ); + }, + }, + { + label: 'Community Discussions', + click() { + shell.openExternal('https://www.electronjs.org/community'); + }, + }, + { + label: 'Search Issues', + click() { + shell.openExternal('https://github.com/electron/electron/issues'); + }, + }, + ], + }, + ]; + + return templateDefault; + } +} diff --git a/src/main/models/Increment.ts b/src/main/models/Increment.ts new file mode 100644 index 0000000..9be6340 --- /dev/null +++ b/src/main/models/Increment.ts @@ -0,0 +1,47 @@ +import { + Column, + CreateDateColumn, + Entity, + JoinColumn, + ManyToOne, + OneToMany, + PrimaryGeneratedColumn, + Relation +} from 'typeorm'; +import { v4 as uuidv4 } from 'uuid'; + +import { Product } from './Product'; +import { Model } from './Model'; + +@Entity('Increment') +export class Increment { + @PrimaryGeneratedColumn('uuid') + id: string = uuidv4(); + + @CreateDateColumn() + createdAt!: Date; + + @Column() + name!: string; + + @OneToMany(() => Model, model => model.increment, { cascade: true}) + models!: Relation; + + @ManyToOne(() => Product, product => product.increments, { onDelete: 'CASCADE' }) + @JoinColumn({name: 'productId'}) + product!: Relation; + + @Column() + productId!: string; + + @Column() + incrementIndex!: number; + + toJSON() { + return { + ...this, + createdAt: this.createdAt.toISOString(), + models: this.models ? this.models.map(model => model.toJSON()) : [], + }; + } +} \ No newline at end of file diff --git a/src/main/models/Model.ts b/src/main/models/Model.ts new file mode 100644 index 0000000..faf9436 --- /dev/null +++ b/src/main/models/Model.ts @@ -0,0 +1,45 @@ +import { + CreateDateColumn, + Entity, + PrimaryGeneratedColumn, + Column, + ManyToOne, + OneToMany, + JoinColumn, + Relation +} from 'typeorm'; +import { v4 as uuidv4 } from 'uuid'; + +import { Increment } from './Increment'; +import { Version } from './Version'; + +@Entity('Model') +export class Model { + @PrimaryGeneratedColumn('uuid') + id: string = uuidv4(); + + @CreateDateColumn() + createdAt!: Date; + + @Column() + name!: string; + + @OneToMany(() => Version, version => version.model, { cascade: true }) + versions!: Relation; + + @ManyToOne(() => Increment, increment => increment.models, { onDelete: 'CASCADE' }) + @JoinColumn({name: 'incrementId'}) + increment!: Relation; + + @Column() + incrementId!: string; + + // Method to convert dates to strings + toJSON() { + return { + ...this, + createdAt: this.createdAt.toISOString(), + versions: this.versions ? this.versions.map(version => version.toJSON()) : [], + }; + } +} \ No newline at end of file diff --git a/src/main/models/Product.ts b/src/main/models/Product.ts new file mode 100644 index 0000000..d8ce1cd --- /dev/null +++ b/src/main/models/Product.ts @@ -0,0 +1,59 @@ +import { + Column, + CreateDateColumn, + Entity, + OneToMany, + JoinColumn, + PrimaryGeneratedColumn, + Relation +} from 'typeorm'; +import { v4 as uuidv4 } from 'uuid'; + +import { Responsible } from './Responsible'; +import { Increment } from './Increment'; + +export interface ResponsibleInput { + firstName: string; + lastName: string; + role?: string; +} + +@Entity('Product') +export class Product { + @PrimaryGeneratedColumn('uuid') + id: string = uuidv4(); + + @CreateDateColumn() + createdAt!: Date; + + @Column() + name!: string; + + @Column({ type: 'text', nullable: true }) + description!: string | null; + + @Column({ type: 'datetime', nullable: true }) + startsAt!: Date | null; + + @Column({ type: 'datetime', nullable: true }) + endsAt!: Date | null; + + @OneToMany(() => Responsible, responsible => responsible.product, { cascade: true }) + responsibles!: Relation; + + @OneToMany(() => Increment, increment => increment.product, { cascade: true }) + increments!: Relation; + + latestIncrementId?: string | null; + + // Method to convert dates to strings + toJSON() { + return { + ...this, + createdAt: this.createdAt.toISOString(), + startsAt: this.startsAt ? this.startsAt.toISOString() : null, + endsAt: this.endsAt ? this.endsAt.toISOString() : null, + increments: this.increments ? this.increments.map(increment => increment.toJSON()) : [], + }; + } +} \ No newline at end of file diff --git a/src/main/models/Responsible.ts b/src/main/models/Responsible.ts new file mode 100644 index 0000000..0d6c4b6 --- /dev/null +++ b/src/main/models/Responsible.ts @@ -0,0 +1,33 @@ +import { + Column, + Entity, + JoinColumn, + ManyToOne, + PrimaryGeneratedColumn, + Relation +} from 'typeorm'; +import { v4 as uuidv4 } from 'uuid'; + +import { Product } from './Product'; + +@Entity('Responsible') +export class Responsible { + @PrimaryGeneratedColumn('uuid') + id: string = uuidv4(); + + @Column() + firstName!: string; + + @Column() + lastName!: string; + + @Column({ type: 'text', nullable: true }) + role!: string | null; + + @ManyToOne(() => Product, product => product.responsibles, { onDelete: 'CASCADE' }) + @JoinColumn({name: 'productId'}) + product!: Relation; + + @Column() + productId!: string; +} diff --git a/src/main/models/Setting.ts b/src/main/models/Setting.ts new file mode 100644 index 0000000..c99dbd1 --- /dev/null +++ b/src/main/models/Setting.ts @@ -0,0 +1,14 @@ +import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"; +import { v4 as uuidv4 } from 'uuid'; + +@Entity('Setting') +export class Setting { + @PrimaryGeneratedColumn('uuid') + id: string = uuidv4(); + + @Column() + key!: string; + + @Column() + value!: string; +} diff --git a/src/main/models/Version.ts b/src/main/models/Version.ts new file mode 100644 index 0000000..1a0858f --- /dev/null +++ b/src/main/models/Version.ts @@ -0,0 +1,56 @@ +import { + CreateDateColumn, + Entity, + PrimaryGeneratedColumn, + Column, + ManyToOne, + JoinColumn, + Relation +} from 'typeorm'; +import { v4 as uuidv4 } from 'uuid'; +import { Model } from './Model'; + +@Entity('Version') +export class Version { + @PrimaryGeneratedColumn('uuid') + id: string = uuidv4(); + + @CreateDateColumn() + createdAt!: Date; + + @Column() + payload!: string; + + @ManyToOne(() => Model, model => model.versions, { onDelete: 'CASCADE' }) + @JoinColumn({ name: 'modelId' }) + model!: Relation; + + @Column() + modelId!: string; + + @Column() + versionIndex!: number; + + @Column() + thumbnail!: string; + + @Column({ type: 'float', nullable: true}) + x!: number | null; + + @Column({ type: 'float', nullable: true}) + y!: number | null; + + @Column({ type: 'float', nullable: true}) + height!: number | null; + + @Column({ type: 'float', nullable: true}) + width!: number | null; + + // Method to convert dates to strings + toJSON() { + return { + ...this, + createdAt: this.createdAt.toISOString(), + }; + } +} diff --git a/src/main/preload.ts b/src/main/preload.ts new file mode 100644 index 0000000..71f42d7 --- /dev/null +++ b/src/main/preload.ts @@ -0,0 +1,82 @@ +// Disable no-unused-vars, broken for spread args +/* eslint no-unused-vars: off */ +import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron'; + +// const electronHandler = { +// ipcRenderer: { +// sendMessage(channel: Channels, ...args: unknown[]) { +// ipcRenderer.send(channel, ...args); +// }, +// on(channel: Channels, func: (...args: unknown[]) => void) { +// const subscription = (_event: IpcRendererEvent, ...args: unknown[]) => +// func(...args); +// ipcRenderer.on(channel, subscription); + +// return () => { +// ipcRenderer.removeListener(channel, subscription); +// }; +// }, +// once(channel: Channels, func: (...args: unknown[]) => void) { +// ipcRenderer.once(channel, (_event, ...args) => func(...args)); +// }, +// }, +// }; + +// contextBridge.exposeInMainWorld('electron', electronHandler); +// preload.js + +// In a suitable TypeScript file (e.g., typings.d.ts or directly in Sidebar.tsx) + +// export type Channels = 'pong'; + +// TODO: change "payload: any" to respective types. +const electronHandler = { + // general + env: process.env.NODE_ENV, + openFilePicker: () => ipcRenderer.invoke('open-file-dialog'), + openDirectoryPicker: () => ipcRenderer.invoke('open-directory-dialog'), + createDatabase: (path: string) => ipcRenderer.invoke('create-database', path), + openDatabase: (path: string) => ipcRenderer.invoke('open-database', path), + getDefaultDbPath: () => ipcRenderer.invoke('get-default-db-path'), + getCurrentDbPath: () => ipcRenderer.invoke('get-current-db-path'), + getGridType: () => ipcRenderer.invoke('get-grid-type'), + setGridType: (value: string) => ipcRenderer.invoke('set-grid-type', value), + getExplicitObjectSelection: () => ipcRenderer.invoke('get-explicit-object-selection'), + setExplicitObjectSelection: (value: boolean) => ipcRenderer.invoke('set-explicit-object-selection', value), + + // product + getAllProducts: (payload: any) => ipcRenderer.invoke('get-all-products', payload), + getProductById: (payload: any) => ipcRenderer.invoke('get-product-by-id', payload), + createProduct: (payload: any) => ipcRenderer.invoke('create-product', payload), + updateProduct: (payload: any) => ipcRenderer.invoke('update-product', payload), + deleteProduct: (payload: any) => ipcRenderer.invoke('delete-product', payload), + // increment + getAllIncrements: (payload: any) => ipcRenderer.invoke('get-all-increments', payload), + getIncrementById: (payload: any) => ipcRenderer.invoke('get-increment-by-id', payload), + getLatestIncrement: (payload: any) => ipcRenderer.invoke('get-latest-increment', payload), + createIncrement: (payload: any) => ipcRenderer.invoke('create-increment', payload), + updateIncrement: (payload: any) => ipcRenderer.invoke('update-increment', payload), + deleteIncrement: (payload: any) => ipcRenderer.invoke('delete-increment', payload), + // model + getAllModels: (payload: any) => ipcRenderer.invoke('get-all-models', payload), + getModelById: (payload: any) => ipcRenderer.invoke('get-model-by-id', payload), + createModel: (payload: any) => ipcRenderer.invoke('create-model', payload), + updateModel: (payload: any) => ipcRenderer.invoke('update-model', payload), + deleteModel: (payload: any) => ipcRenderer.invoke('delete-model', payload), + // version + getAllVersions: (payload: any) => ipcRenderer.invoke('get-all-versions', payload), + getVersionById: (payload: any) => ipcRenderer.invoke('get-version-by-id', payload), + getLatestVersion: (payload: any) => ipcRenderer.invoke('get-latest-version', payload), + createVersion: (payload: any) => ipcRenderer.invoke('create-version', payload), + deleteVersion: (payload: any) => ipcRenderer.invoke('delete-version', payload), +}; + +const rendererApiHandler = { +}; + +contextBridge.exposeInMainWorld('electron', electronHandler); +// contextBridge.exposeInMainWorld('rendererApi', rendererApiHandler); + +export type ElectronHandler = typeof electronHandler; +// export type RendererApiHandler = typeof rendererApiHandler; + diff --git a/src/main/repositories/IncrementRepository.ts b/src/main/repositories/IncrementRepository.ts new file mode 100644 index 0000000..bbac0e4 --- /dev/null +++ b/src/main/repositories/IncrementRepository.ts @@ -0,0 +1,72 @@ +import { AppDataSource } from '../database'; +import { Increment } from '../models/Increment'; + +export class IncrementRepository { + private incrementRepository = AppDataSource.getRepository(Increment); + + async createIncrement(increment: Increment): Promise { + return await this.incrementRepository.save(increment); + } + + async getAllIncrements(sortBy: string, sort: 'asc' | 'desc', productId?: string): Promise<[Increment[], number]> { + const where = productId ? { productId } : {}; + + const [increments, count] = await this.incrementRepository.findAndCount({ + where, + relations: [], + order: { + [sortBy]: sort, + }, + }); + + return [increments, count]; + } + + async getIncrementById(id: string, eager: boolean): Promise { + if (eager) { + return await this.incrementRepository.findOne({ + where: { id }, + relations: ['models', 'models.versions'], + }); + } else { + return await this.incrementRepository.findOne({ + where: { id }, + relations: [], + }); + } + } + + async getLatestIncrement(productId?: string): Promise { + const where = productId ? { productId } : {}; + + return await this.incrementRepository.findOne({ + where, + order: { + incrementIndex: 'DESC', + }, + }); + } + + async getLatestIncrementId(productId: string): Promise { + const latestIncrement = await AppDataSource.getRepository('Increment').findOne({ + where: { product: { id: productId } }, + order: { incrementIndex: 'DESC' }, + }); + + return latestIncrement?.id || null; + } + + async updateIncrement(id: string, data: Partial): Promise { + const increment = await this.incrementRepository.findOneBy({ id }); + if (!increment) { + return null; + } + Object.assign(increment, data); + return await this.incrementRepository.save(increment); + } + + async deleteIncrement(id: string): Promise { + await this.incrementRepository.delete(id); + } +} + diff --git a/src/main/repositories/ModelRepository.ts b/src/main/repositories/ModelRepository.ts new file mode 100644 index 0000000..3a894b5 --- /dev/null +++ b/src/main/repositories/ModelRepository.ts @@ -0,0 +1,56 @@ +import { AppDataSource } from '../database'; +import { Model } from '../models/Model'; + +export class ModelRepository { + private modelRepository = AppDataSource.getRepository(Model); + + // async createModel(data: Partial): Promise { + // const model = this.modelRepository.create(data); + // return await this.modelRepository.save(model); + // } + + async createModel(model: Model): Promise { + // const model = this.modelRepository.create(data); + return await this.modelRepository.save(model); + } + + async getAllModels(sortBy: string, sort: 'asc' | 'desc', incrementId?: string): Promise<[Model[], number]> { + const where = incrementId ? { incrementId } : {}; + + return await this.modelRepository.findAndCount({ + where, + order: { + [sortBy]: sort, + }, + relations: [] + }); + } + + async getModelById(id: string, eager: boolean): Promise { + if (eager) { + return await this.modelRepository.findOne({ + where: { id }, + relations: ['versions'], + }); + } else { + return await this.modelRepository.findOne({ + where: { id }, + relations: [] + }); + } + } + + async updateModel(id: string, data: Partial): Promise { + const model = await this.modelRepository.findOneBy({ id }); + if (!model) { + return null; + } + + Object.assign(model, data); + return await this.modelRepository.save(model); + } + + async deleteModel(id: string): Promise { + await this.modelRepository.delete(id); + } +} diff --git a/src/main/repositories/ProductRepository.ts b/src/main/repositories/ProductRepository.ts new file mode 100644 index 0000000..3ecb525 --- /dev/null +++ b/src/main/repositories/ProductRepository.ts @@ -0,0 +1,58 @@ +import { AppDataSource } from '../database'; +import { Product } from '../models/Product'; +// import { Responsible } from '../models/Responsible'; + +export class ProductRepository { + private productRepository = AppDataSource.getRepository(Product); + // private responsibleRepository = AppDataSource.getRepository(Responsible); + + + async createProduct(product: Product): Promise { + const newProduct = await this.productRepository.save(product); + return newProduct; + } + + async getAllProducts(limit: number, offset: number, sort: 'asc' | 'desc', sortby: string): Promise<[Product[], number]> { + const [products, count] = await this.productRepository.findAndCount({ + relations: ['responsibles'], + take: limit, + skip: offset, + order: { + [sortby]: sort, + }, + }); + + return [products, count]; + } + + async getProductById(id: string, eager: boolean): Promise { + if (!id) { + return null; + } + + if (eager) { + return await this.productRepository.findOne({ + where: { id }, + relations: ['responsibles', 'increments', 'increments.models', 'increments.models.versions'], + }); + } else { + return await this.productRepository.findOne({ + where: { id }, + relations: ['responsibles'], + }); + } + } + + async updateProduct(id: string, data: any): Promise { + const product = await this.productRepository.findOneBy({ id }); + + if (!product) { + return null; + } + return await this.productRepository.save(data); + } + + async deleteProduct(id: string): Promise { + await this.productRepository.delete({ id }); + } +} diff --git a/src/main/repositories/ResponsibleRepository.ts b/src/main/repositories/ResponsibleRepository.ts new file mode 100644 index 0000000..25bfab7 --- /dev/null +++ b/src/main/repositories/ResponsibleRepository.ts @@ -0,0 +1,38 @@ +import { AppDataSource } from '../database'; +import { Responsible } from '../models/Responsible'; + +export class ResponsibleRepository { + private responsibleRepository = AppDataSource.getRepository(Responsible); + + async createResponsible(responsible: Responsible): Promise { + return await this.responsibleRepository.save(responsible); + } + + async getAllResponsibles(productId?: string): Promise<[Responsible[], number]> { + if (productId) { + return await this.responsibleRepository.findAndCount({ + where: { productId } + }); + } else { + return await this.responsibleRepository.findAndCount(); + } + } + + async getResponsibleById(id: string): Promise { + return await this.responsibleRepository.findOneBy({ id }); + } + + async updateResponsible(id: string, data: Partial): Promise { + const responsible = await this.responsibleRepository.findOneBy({ id }); + if (!responsible) { + return null; + } + + Object.assign(responsible, data); + return await this.responsibleRepository.save(responsible); + } + + async deleteResponsible(id: string): Promise { + await this.responsibleRepository.delete(id); + } +} diff --git a/src/main/repositories/SettingRepository.ts b/src/main/repositories/SettingRepository.ts new file mode 100644 index 0000000..77dcfa3 --- /dev/null +++ b/src/main/repositories/SettingRepository.ts @@ -0,0 +1,16 @@ +import { AppDataSource } from '../database'; +import { Setting } from '../models/Setting'; + +export class SettingRepository { + private settingRepository = AppDataSource.getRepository(Setting); + + async getSettingByKey(key: string): Promise { + return await this.settingRepository.findOne({ + where: { key }, + }); + } + + async saveSetting(setting: Setting): Promise { + return await this.settingRepository.save(setting); + } +} diff --git a/src/main/repositories/VersionRepository.ts b/src/main/repositories/VersionRepository.ts new file mode 100644 index 0000000..89fae92 --- /dev/null +++ b/src/main/repositories/VersionRepository.ts @@ -0,0 +1,61 @@ +import { AppDataSource } from '../database'; +import { Version } from '../models/Version'; + +export class VersionRepository { + private versionRepository = AppDataSource.getRepository(Version); + + async createVersion(data: Partial): Promise { + + const version = this.versionRepository.create(data); + const response = await this.versionRepository.save(version) + + return response; + } + + async getAllVersions(sortBy: string, sort: 'asc' | 'desc', modelId?: string): Promise<[Version[], number]> { + const where = modelId ? { modelId } : {}; + + const [versions, count] = await this.versionRepository.findAndCount({ + where, + order: { + [sortBy]: sort, + }, + }); + + return [versions, count]; + } + + async getVersionById(id: string): Promise { + return await this.versionRepository.findOneBy({ id }); + } + + async getLatestVersionByModelId(modelId: string): Promise { + return await this.versionRepository.findOne({ + where: { modelId }, + order: { + versionIndex: 'DESC', + }, + }); + } + + async countVersionsByModelId(modelId: string): Promise { + return await this.versionRepository.count({ where: { modelId } }); + } + + async deleteEarliestVersionByModelId(modelId: string): Promise { + const earliestVersion = await this.versionRepository.findOne({ + where: { modelId }, + order: { + versionIndex: 'ASC', + }, + }); + + if (earliestVersion) { + await this.versionRepository.remove(earliestVersion); + } + } + + async deleteVersion(id: string): Promise { + await this.versionRepository.delete(id); + } +} diff --git a/src/main/services/IncrementService.ts b/src/main/services/IncrementService.ts new file mode 100644 index 0000000..e17cc38 --- /dev/null +++ b/src/main/services/IncrementService.ts @@ -0,0 +1,60 @@ +import { IncrementRepository } from '../repositories/IncrementRepository'; +import { Increment } from '../models/Increment'; +import { ProductRepository } from '../repositories/ProductRepository'; +import { buildIncrementEntity } from '../helpers/entityBuilder'; + +export class IncrementService { + private incrementRepository = new IncrementRepository(); + private productRepository = new ProductRepository + + async createIncrement(data: Increment): Promise { + const { productId } = data; + + const product = await this.productRepository.getProductById(productId, false); + if (!product) { + throw new Error('Product not found'); + } + + // Find the latest version number for the given modelId + const latestIncrement = await this.incrementRepository.getLatestIncrement(productId) + // Set the new version number + const newIncrementIndex = latestIncrement ? latestIncrement.incrementIndex + 1 : 0; + // increment.incrementIndex = newIncrementIndex + + let increment: Increment = buildIncrementEntity({...data, incrementIndex: null}, newIncrementIndex) + increment.productId = productId + + const newIncrement = await this.incrementRepository.createIncrement(increment) + const serializedNewIncrement = newIncrement.toJSON() + + return serializedNewIncrement; + } + + async getAllIncrements(sortBy: string, sort: 'asc' | 'desc', productId?: string): Promise<{ increments: Increment[], incrementsCount: number }> { + const [increments, incrementsCount] = await this.incrementRepository.getAllIncrements(sortBy, sort, productId); + const serializedIncrements = increments.map(increment => increment.toJSON()); + return { increments: serializedIncrements, incrementsCount }; + } + + async getIncrementById(id: string, eager: boolean): Promise { + const increment = await this.incrementRepository.getIncrementById(id, eager) + const serializedIncrement = increment!.toJSON() + return serializedIncrement; + } + + async getLatestIncrement(productId?: string): Promise { + const increment = await this.incrementRepository.getLatestIncrement(productId) + const serializedIncrement = increment!.toJSON() + return serializedIncrement; + } + + async updateIncrement(id: string, data: Partial): Promise { + const increment = await this.incrementRepository.updateIncrement(id, data) + const serializedIncrement = increment!.toJSON() + return serializedIncrement; + } + + async deleteIncrement(id: string): Promise { + await this.incrementRepository.deleteIncrement(id); + } +} diff --git a/src/main/services/ModelService.ts b/src/main/services/ModelService.ts new file mode 100644 index 0000000..f6228d2 --- /dev/null +++ b/src/main/services/ModelService.ts @@ -0,0 +1,48 @@ +import { ModelRepository } from '../repositories/ModelRepository'; +import { Model } from '../models/Model'; +import { buildModelEntity } from '../helpers/entityBuilder'; +import { IncrementRepository } from '../repositories/IncrementRepository'; + +export class ModelService { + private modelRepository = new ModelRepository(); + private incrementRepository = new IncrementRepository(); + + async createModel(data: any): Promise { + const { incrementId } = data; + + const increment = await this.incrementRepository.getIncrementById(incrementId, false); + if (!increment) { + throw new Error('Product not found'); + } + + let model: Model = buildModelEntity(data) + model.incrementId = incrementId; + + const newModel = await this.modelRepository.createModel(model) + const serializedNewModel = newModel.toJSON() + + return serializedNewModel; + } + + async getAllModels(sortBy: string, sort: 'asc' | 'desc', incrementId?: string): Promise<{ models: Model[], modelsCount: number }> { + const [models, modelsCount] = await this.modelRepository.getAllModels(sortBy, sort, incrementId); + const serializedModels = models.map(model => model.toJSON()); + return { models: serializedModels, modelsCount }; + } + + async getModelById(id: string, eager: boolean): Promise { + const model = await this.modelRepository.getModelById(id, eager); + const serializedModel = model!.toJSON() + return serializedModel; + } + + async updateModel(id: string, data: Partial): Promise { + const model = await this.modelRepository.updateModel(id, data); + const serializedModel = model!.toJSON() + return serializedModel; + } + + async deleteModel(id: string): Promise { + await this.modelRepository.deleteModel(id); + } +} diff --git a/src/main/services/ProductService.ts b/src/main/services/ProductService.ts new file mode 100644 index 0000000..8594b98 --- /dev/null +++ b/src/main/services/ProductService.ts @@ -0,0 +1,99 @@ +import { ProductRepository } from '../repositories/ProductRepository'; +// import { ResponsibleRepository } from '../repositories/ResponsibleRepository'; +// import { IncrementService } from './IncrementService'; +import { Product } from '../models/Product'; +import { Responsible } from '../models/Responsible'; + +import { buildProductEntity, buildResponsibleEntity } from '../helpers/entityBuilder'; +import { ResponsibleRepository } from '../repositories/ResponsibleRepository'; +import { IncrementRepository } from '../repositories/IncrementRepository'; +import dataflow from '../../renderer/applets/model-editor/shapes/dataflow'; + +export class ProductService { + private productRepository = new ProductRepository(); + private responsibleRepository = new ResponsibleRepository(); + private incrementRepository = new IncrementRepository(); + + async createProduct(data: Product): Promise { + const product: Product = buildProductEntity(data) + const newProduct = await this.productRepository.createProduct(product) + const serializedProduct = newProduct.toJSON() + + return serializedProduct; + } + + async getAllProducts(limit: number, offset: number, sort: 'asc' | 'desc', sortby: string): Promise<{ products: Product[], productsCount: number }> { + const [products, count] = await this.productRepository.getAllProducts(limit, offset, sort, sortby); + + for (const product of products) { + product.latestIncrementId = await this.incrementRepository.getLatestIncrementId(product.id); + } + const serializedProducts = products.map(product => product.toJSON()); + + return { products: serializedProducts, productsCount: count }; + } + + async getProductById(id: string, eager: boolean): Promise { + const product = await this.productRepository.getProductById(id, eager); + const serializedProduct = product!.toJSON() + + return serializedProduct + } + + async updateProduct(id: string, data: any) { + const { responsibles } = data; + + const filteredResponsibles = responsibles.filter((resp: Responsible) => { + return (resp.firstName || resp.lastName) && { ...resp, role: resp.role || null }; + }); + + const product = await this.productRepository.getProductById(id, false); + + if (!product) { + throw new Error('Product not found'); + } + + // Get existing responsibles + const existingResponsibles = product.responsibles; + + // Create maps for quick lookup + const existingResponsibleMap = new Map(existingResponsibles.map((resp: any) => [resp.id, resp])); + const newResponsibleMap = new Map(filteredResponsibles.map((resp: any) => [resp.id, resp])); + + // Identify responsibles to delete + for (const existingResponsible of existingResponsibles) { + if (!newResponsibleMap.has(existingResponsible.id)) { + await this.responsibleRepository.deleteResponsible(existingResponsible.id); + } + } + + // Identify responsibles to insert or update + for (const newResponsible of filteredResponsibles) { + if (existingResponsibleMap.has(newResponsible.id)) { + // Update existing responsible if needed + const existingResponsible = existingResponsibleMap.get(newResponsible.id); + if (existingResponsible!.firstName !== newResponsible.firstName || + existingResponsible!.lastName !== newResponsible.lastName || + existingResponsible!.role !== newResponsible.role) { + await this.responsibleRepository.updateResponsible(newResponsible.id, newResponsible); + } + } else { + // Insert new responsible + const responsibleEntity = buildResponsibleEntity(newResponsible); + responsibleEntity.productId = product.id; // Ensure productId is set + await this.responsibleRepository.createResponsible(responsibleEntity); + product.responsibles.push(responsibleEntity); + } + } + + // Update the product with new data (excluding responsibles which are already handled) + const { responsibles: _, ...productData } = data; + return this.productRepository.updateProduct(product.id, productData); +} + + + + async deleteProduct(id: string): Promise { + await this.productRepository.deleteProduct(id); + } +} \ No newline at end of file diff --git a/src/main/services/ResponsibleService.ts b/src/main/services/ResponsibleService.ts new file mode 100644 index 0000000..740737f --- /dev/null +++ b/src/main/services/ResponsibleService.ts @@ -0,0 +1,40 @@ +import { ResponsibleRepository } from '../repositories/ResponsibleRepository'; +import { Responsible } from '../models/Responsible'; +import { ProductRepository } from '../repositories/ProductRepository'; +import { buildResponsibleEntity } from '../helpers/entityBuilder'; + +export class ResponsibleService { + private responsibleRepository = new ResponsibleRepository(); + private productRepository = new ProductRepository(); + + async createResponsible(data: any): Promise { + const { productId } = data; + + const product = await this.productRepository.getProductById(productId, false); + if (!product) { + throw new Error('Product not found'); + } + + let responsible: Responsible = buildResponsibleEntity(data) + responsible.productId = productId; + + return await this.responsibleRepository.createResponsible(responsible); + } + + async getAllResponsibles(productId?: string): Promise<{ responsibles: Responsible[], responsiblesCount: number }> { + const [responsibles, responsiblesCount] = await this.responsibleRepository.getAllResponsibles(productId); + return { responsibles, responsiblesCount }; + } + + async getResponsibleById(id: string): Promise { + return await this.responsibleRepository.getResponsibleById(id); + } + + async updateResponsible(id: string, data: Partial): Promise { + return await this.responsibleRepository.updateResponsible(id, data); + } + + async deleteResponsible(id: string): Promise { + await this.responsibleRepository.deleteResponsible(id); + } +} diff --git a/src/main/services/SettingService.ts b/src/main/services/SettingService.ts new file mode 100644 index 0000000..3b10c50 --- /dev/null +++ b/src/main/services/SettingService.ts @@ -0,0 +1,44 @@ +import fs from 'fs'; +import path from 'path'; + +import { initializeDataSource } from '../database'; + +import { SettingRepository } from '../repositories/SettingRepository'; +import { Setting } from '../models/Setting'; + +export class SettingService { + private settingRepository = new SettingRepository(); + + async createDbPathSetting(dbPath: string): Promise { + if (!fs.existsSync(dbPath)) { + throw new Error('The specified path does not exist'); + } + + const absolutePath = path.resolve(dbPath); + const newDatabasePath = path.join(absolutePath, 'database.sqlite'); + + if (!fs.existsSync(newDatabasePath)) { + fs.closeSync(fs.openSync(newDatabasePath, 'w')); + } + + let setting = await this.settingRepository.getSettingByKey('db-path'); + if (!setting) { + setting = new Setting(); + setting.key = 'db-path'; + setting.value = newDatabasePath; + } else { + setting.value = newDatabasePath; + } + + const savedSetting = await this.settingRepository.saveSetting(setting); + + // Initialize the data source with the new database path + await initializeDataSource(newDatabasePath); + + return savedSetting; + } + + async getSettingByKey(key: string): Promise { + return await this.settingRepository.getSettingByKey(key); + } +} diff --git a/src/main/services/VersionService.ts b/src/main/services/VersionService.ts new file mode 100644 index 0000000..12c0d8f --- /dev/null +++ b/src/main/services/VersionService.ts @@ -0,0 +1,83 @@ +import { VersionRepository } from '../repositories/VersionRepository'; +import { Version } from '../models/Version'; +import { buildVersionEntity } from '../helpers/entityBuilder'; +import { ModelRepository } from '../repositories/ModelRepository'; + +export class VersionService { + private versionRepository = new VersionRepository(); + private modelRepository = new ModelRepository(); + + + // async createVersion(data: any): Promise { + // const { modelId } = data; + + // const model = await this.modelRepository.getModelById(modelId, false); + // if (!model) { + // throw new Error('Product not found'); + // } + + // // Find the latest version number for the given modelId + // const latestVersion = await this.versionRepository.getLatestVersionByModelId(modelId) + // // Set the new version number + // const newVersionIndex = latestVersion ? latestVersion.versionIndex + 1 : 0; + // // version.versionIndex = newVersionNumber + + // let version: Version = buildVersionEntity(data, newVersionIndex) + // version.modelId = modelId + + // return await this.versionRepository.createVersion(version); + // } + + async createVersion(data: any): Promise { + const { modelId } = data; + + const model = await this.modelRepository.getModelById(modelId, false); + if (!model) { + throw new Error('Model not found'); + } + + // Find the latest version number for the given modelId + const latestVersion = await this.versionRepository.getLatestVersionByModelId(modelId); + const newVersionIndex = latestVersion ? latestVersion.versionIndex + 1 : 0; + + // Build the new version entity + let version: Version = buildVersionEntity(data, newVersionIndex); + version.modelId = modelId; + + // Count the existing versions for the model + const versionCount = await this.versionRepository.countVersionsByModelId(modelId); + + // Check if the version count exceeds 1000 + if (versionCount >= 1000) { + // Delete the earliest version + await this.versionRepository.deleteEarliestVersionByModelId(modelId); + } + + const newVersion = await this.versionRepository.createVersion(version); + const serializedNewVersion = newVersion.toJSON() + + return serializedNewVersion; + } + + async getAllVersions(sortBy: string, sort: 'asc' | 'desc', modelId?: string): Promise<{ versions: Version[], versionsCount: number }> { + const [versions, versionsCount] = await this.versionRepository.getAllVersions(sortBy, sort, modelId); + const serializedVersions = versions.map(version => version.toJSON()) + return { versions: serializedVersions, versionsCount }; + } + + async getVersionById(id: string): Promise { + const version = await this.versionRepository.getVersionById(id); + const serializedVersion = version!.toJSON() + return serializedVersion; + } + + async getLatestVersionByModelId(modelId: string): Promise { + const version = await this.versionRepository.getLatestVersionByModelId(modelId); + const serializedVerison = version!.toJSON() + return serializedVerison; + } + + async deleteVersion(id: string): Promise { + await this.versionRepository.deleteVersion(id); + } +} diff --git a/src/main/util.ts b/src/main/util.ts new file mode 100644 index 0000000..7775eda --- /dev/null +++ b/src/main/util.ts @@ -0,0 +1,13 @@ +/* eslint import/prefer-default-export: off */ +import { URL } from 'url'; +import path from 'path'; + +export function resolveHtmlPath(htmlFileName: string) { + if (process.env.NODE_ENV === 'development') { + const port = process.env.PORT || 1212; + const url = new URL(`http://localhost:${port}`); + url.pathname = htmlFileName; + return url.href; + } + return `file://${path.resolve(__dirname, '../renderer/', htmlFileName)}`; +} diff --git a/src/renderer/App.css b/src/renderer/App.css new file mode 100644 index 0000000..616d9a4 --- /dev/null +++ b/src/renderer/App.css @@ -0,0 +1,62 @@ +/* + * @NOTE: Prepend a `~` to css file paths that are in your node_modules + * See https://github.com/webpack-contrib/sass-loader#imports + */ +body { + position: relative; + color: white; + height: 100vh; + background: linear-gradient( + 200.96deg, + #fedc2a -29.09%, + #dd5789 51.77%, + #7a2c9e 129.35% + ); + font-family: sans-serif; + overflow-y: hidden; + display: flex; + justify-content: center; + align-items: center; +} + +button { + background-color: white; + padding: 10px 20px; + border-radius: 10px; + border: none; + appearance: none; + font-size: 1.3rem; + box-shadow: 0px 8px 28px -6px rgba(24, 39, 75, 0.12), + 0px 18px 88px -4px rgba(24, 39, 75, 0.14); + transition: all ease-in 0.1s; + cursor: pointer; + opacity: 0.9; +} + +button:hover { + transform: scale(1.05); + opacity: 1; +} + +li { + list-style: none; +} + +a { + text-decoration: none; + height: fit-content; + width: fit-content; + margin: 10px; +} + +a:hover { + opacity: 1; + text-decoration: none; +} + +.Hello { + display: flex; + justify-content: center; + align-items: center; + margin: 20px 0; +} diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx new file mode 100644 index 0000000..dfdc7c0 --- /dev/null +++ b/src/renderer/App.tsx @@ -0,0 +1,88 @@ +import React, { useEffect } from 'react'; +import { HashRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; +import { Menu, SidebarPushable, SidebarPusher } from 'semantic-ui-react'; +import Products from './components/products/Products'; +import Product from './components/products/Product'; +import TopBar from './components/TopBar'; +import ModelEditor from './applets/model-editor/ModelEditor'; +import SideBar from './components/SideBar'; +import Footer from './components/Footer'; +import { ToastManager } from './components/ToastManager'; +import { useDispatch, Provider, useSelector } from 'react-redux'; +import store, { AppDispatch, RootState } from './store'; // Ensure this imports your configured Redux store + +import { + showToast, + setDatabasePath, + setGridVisible, + setExplicitObjectSelection, +} from './store/SettingsStore'; // Adjust the import path as necessary +import { path } from '@antv/x6/lib/registry/marker/path'; +import { current } from '@reduxjs/toolkit'; + +const AppWrapper = () => { + return ( + + + + + + ); +}; + +const App: React.FC = () => { + const { + path + } = useSelector((state: RootState) => state.settings); + + const dispatch = useDispatch(); + + useEffect(() => { + window.electron.getCurrentDbPath().then((currentPath: string) => { + dispatch(setDatabasePath(currentPath)); + dispatch( + showToast({ + promise: Promise.resolve(), // Resolve immediately since there's no async operation + loadingMessage: '', // No loading message needed + successMessage: `Current database: ${currentPath}`, // Success message with grid type + errorMessage: '', // No error message needed + }) + ) + }); + window.electron.getGridType().then((currentGridType: 'none' | 'dot' | 'mesh') => { + dispatch(setGridVisible(currentGridType || 'none')) + }) + window.electron.getExplicitObjectSelection().then((explicitObjectSelection: boolean) => { + dispatch(setExplicitObjectSelection(explicitObjectSelection || false)) + }) + + }, []); + + return ( +
+ + + + + +
+ + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
+
+ + + +
+ ); +}; + +export default AppWrapper; diff --git a/src/renderer/applets/model-editor/ModelEditor.css b/src/renderer/applets/model-editor/ModelEditor.css new file mode 100644 index 0000000..1d5d010 --- /dev/null +++ b/src/renderer/applets/model-editor/ModelEditor.css @@ -0,0 +1,18 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.save-and-close-button { + position: absolute; + right: 0; /* Aligns the button to the right */ + height: 32px +} + +.selection { + border: 1px solid #2185d0 !important; +} \ No newline at end of file diff --git a/src/renderer/applets/model-editor/ModelEditor.tsx b/src/renderer/applets/model-editor/ModelEditor.tsx new file mode 100644 index 0000000..4cc9528 --- /dev/null +++ b/src/renderer/applets/model-editor/ModelEditor.tsx @@ -0,0 +1,260 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; +import { useDispatch, useSelector } from 'react-redux'; +import { Cell, Graph, Rectangle } from '@antv/x6'; +import { Breadcrumb, Dimmer, Label, Loader, Message } from 'semantic-ui-react'; +import toast, { Toaster } from 'react-hot-toast'; + +import system from './shapes/system'; +import dataflow from './shapes/dataflow'; +import actor from './shapes/actor'; +import zone from './shapes/zone'; + +import StencilContainer from './components/Stencil'; +import Keys from './components/Keys'; +import Events from './components/Events'; +import Toolbar from './components/Toolbar'; + +import ActorModal from './components/ActorModal'; +import SystemModal from './components/SystemModal'; +import DataflowModal from './components/DataflowModal'; +import ZoneModal from './components/ZoneModal'; + +import setup from './setup'; +import tools from './tools'; + +import { RootState, AppDispatch } from '../../store'; + +import { fetchProduct } from '../../store/ProductsStore'; +import { fetchIncrement } from '../../store/IncrementsStore'; +import { fetchModel } from '../../store/ModelsStore'; +import { addLatestVersion, fetchLatestVersion, } from '../../store/VersionsStore'; +import { showToast, hideToast } from '../../store/SettingsStore'; + +import './ModelEditor.css'; +import ExportModal from './components/ExportModal'; +import ImportModal from './components/ImportModal'; + +import { compareHashes } from '../../utils'; +import { ipcRenderer } from 'electron'; +import { setSystemModalOpen } from '../../store/ModelEditorStore'; + +const ModelEditor: React.FC = () => { + const { productId, incrementId, modelId } = useParams(); + const navigate = useNavigate(); + const dispatch = useDispatch(); + + const containerRef = useRef(null); + const minimapRef = useRef(null); + const isGraphInitialized = useRef(false); + + // global redux states + const { product, productIsLoading, productError } = useSelector((state: RootState) => state.products); + const { increment, incrementIsLoading, incrementError } = useSelector((state: RootState) => state.increments); + const { model, modelIsLoading, modelError } = useSelector((state: RootState) => state.models); + const { latestVersion, latestVersionIsLoading, latestVersionIsLoaded, latestVersionError } = useSelector((state: RootState) => state.versions); + const { gridVisible } = useSelector((state: RootState) => state.settings); + const state = useSelector((state: RootState) => state); + + + // local states + const [graph, setGraph] = useState(); + const [isFirstLoad, setIsFirstLoad] = useState(true); + + // global redux states + const { + actorModalOpen, + systemModalOpen, + zoneModalOpen, + dataflowModalOpen + } = useSelector((state: RootState) => state.modelEditor) + + const { + sidebarVisible + } = useSelector((state: RootState) => state.settings) + + // fetching objects + useEffect(() => { + if (productId && incrementId && modelId) { + dispatch(fetchProduct({ productId, isEagerLoading: false })); + dispatch(fetchIncrement({ incrementId, isEagerLoading: false })); + dispatch(fetchModel({ modelId, isEagerLoading: false })); + dispatch(fetchLatestVersion({ modelId })); + } + }, [dispatch, productId, incrementId, modelId, latestVersion!.id]); + + // load latest graph + useEffect(() => { + if (graph && latestVersion && latestVersion.payload && latestVersion.payload.cells) { + const cells: Cell[] = latestVersion.payload.cells; + graph.fromJSON(cells); + + if (isFirstLoad) { + const { x, y, height, width } = latestVersion + + if (x && y && height && width) { + graph.zoomToRect({x, y, height, width}) + } else { + graph.zoomToFit({padding: {left: 200, right: 200}}) + } + setIsFirstLoad(false) + } + } + }, [dispatch, latestVersion]); + + useEffect(() => { + if (containerRef && containerRef.current) { + const modalsOpen = actorModalOpen || systemModalOpen || dataflowModalOpen || zoneModalOpen + + if (!modalsOpen) { + containerRef.current.focus() + } + } +}, [ + actorModalOpen, + systemModalOpen, + zoneModalOpen, + dataflowModalOpen +]) + + // graph initialization + useEffect(() => { + async function initializeGraph() { + if (!containerRef.current) return; + if (!minimapRef.current) return; + if (isGraphInitialized.current) return; + + // Setup graph instance + const graphInstance = setup.create(containerRef.current, gridVisible); + + // Register custom shapes and tools before setting the graph + actor.register(); + dataflow.register(); + system.register(); + zone.register(); + tools.register(); + + setGraph(graphInstance); + isGraphInitialized.current = true; // Mark the graph as initialized + containerRef.current.focus(); + } + initializeGraph(); + }, []); + + useEffect(() => { + if (!sidebarVisible && containerRef && containerRef.current) { + containerRef.current.focus() + } + }, [sidebarVisible]) + + useEffect(() => { + updateGrid(); + }, [gridVisible]); + + // Function to update the grid + const updateGrid = () => { + if (graph) { + graph.hideGrid(); + if (gridVisible !== 'none') { + graph.showGrid(); + graph.drawGrid({ type: gridVisible }); + } + } + }; + + // Function to save the current model + const saveModel = async () => { + if (modelId && graph && latestVersion) { + const oldGraph = latestVersion.payload.cells; + const newGraph = graph.toJSON().cells; + + if (compareHashes(oldGraph, newGraph) === true) { + // if hashes match, we do not save. + return; + } + const {x, y, height, width}: Rectangle = graph.getGraphArea() + const promise = dispatch(addLatestVersion({ modelId, graph, x, y, height, width })).unwrap() + dispatch( + showToast({ + promise: promise, // Resolve immediately since there's no async operation + loadingMessage: 'Saving threat model...', // No loading message needed + successMessage: `Threat model saved`, // Success message with grid type + errorMessage: 'Failed to save threat model', // No error message needed + }) + ); + + } else { + return; + } + }; + + const handleNavigate = async (path: string) => { + await saveModel(); + navigate(path); + }; + + const handleModalClose = () => { + console.log('') + }; + + return ( +
+
+ + handleNavigate(`/products`)}> + Products + + + handleNavigate(`/products/${product!.id}`)}> + {product?.name} + + + handleNavigate(`/products/${product!.id}/increments/${increment!.id}`)}> + {increment?.name} + + + {model?.name} + + + {/* Loader */} + {(productIsLoading || incrementIsLoading || modelIsLoading || latestVersionIsLoading) && ( + + Loading Model... + + )} + + {/* Error handling */} + {(productError || incrementError || modelError || latestVersionError) && ( + + Error +

{modelError}

+
+ )} + + {/* Normal behavior */} + {product && increment && model && latestVersion && graph && ( +
+ + + + + + {/* Modals */} + + + + + + +
+ )} + +
+ +
+
+
+ ); +}; + +export default ModelEditor; diff --git a/src/renderer/applets/model-editor/actions.tsx b/src/renderer/applets/model-editor/actions.tsx new file mode 100644 index 0000000..91e9d65 --- /dev/null +++ b/src/renderer/applets/model-editor/actions.tsx @@ -0,0 +1,106 @@ +import { Graph } from "@antv/x6"; + + +const exportAction = (graph: Graph) => { + graph.exportPNG('export'); + return true; +} + +const importAction = () => { + //Todo + return true; +} + +const fitViewAction = (graph: Graph) => { + graph.zoomToFit({padding: {left: 200, right: 200}}) + return true; +} + +const zoomInAction = (graph: Graph) => { + graph.zoom(0.2) + // graph.drawGrid() + return true; +} + +const zoomOutAction = (graph: Graph) => { + graph.zoom(-0.2) + return true; +} + +const undoAction = (graph: Graph) => { + if (graph.canUndo()) { + graph.undo() + return true; + } + return false +} + +const redoAction = (graph: Graph) => { + if (graph.canRedo()) { + graph.redo() + return true; + } + return false +} + +const selectAllAction = (graph: Graph) => { + const cells = graph.getCells() + if (cells.length > 0) { + graph.select(cells); + return true; + } + return false; +} + +const cutAction = (graph: Graph) => { + const cells = graph.getSelectedCells() + if (cells.length) { + graph.cut(cells) + return true; + } + return false +} + +const copyAction = (graph: Graph) => { + const cells = graph.getSelectedCells(); + if (cells.length) { + graph.copy(cells); + return true; + } + return false; +} + +const pasteAction = (graph: Graph) => { + if (!graph.isClipboardEmpty()) { + const cells = graph.paste({ offset: 32 }) + graph.cleanSelection() + graph.select(cells) + return true; + } + return false +} + +const deleteAction = (graph: Graph) => { + const cells = graph.getSelectedCells() + if (cells.length) { + graph.removeCells(cells) + return true; + } else { + return false; + } +} + +export default { + exportAction, + importAction, + undoAction, + redoAction, + selectAllAction, + cutAction, + copyAction, + pasteAction, + deleteAction, + fitViewAction, + zoomInAction, + zoomOutAction +}; \ No newline at end of file diff --git a/src/renderer/applets/model-editor/components/ActorModal.tsx b/src/renderer/applets/model-editor/components/ActorModal.tsx new file mode 100644 index 0000000..99ff04e --- /dev/null +++ b/src/renderer/applets/model-editor/components/ActorModal.tsx @@ -0,0 +1,93 @@ +import React from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { Graph } from '@antv/x6'; + +import Actor from '../shapes/actor' + +import { + setActorModalOpen, + setActorName, + setActorDescription, +} from '../../../store/ModelEditorStore'; + +import { RootState, AppDispatch } from '../../../store'; + +import { Form, Modal, TextAreaProps } from 'semantic-ui-react'; + +interface ActorModalProps { + graph: Graph; +} + +const ActorModal: React.FC = ({ graph }) => { + const dispatch = useDispatch(); + + // global redux states + const { + actorModalOpen, + actorModalSelectedCell, + actorName, + actorDescription + } = useSelector((state: RootState) => state.modelEditor) + + + const handleSubmit = () => { + + if (actorModalSelectedCell) { + const cell = graph.getCellById(actorModalSelectedCell); + if (cell.isNode()) { + + const attrs = Actor.setActorAttrs(actorName); + // todo: set Description + cell.setAttrs(attrs); + cell.setData({description: actorDescription}) + } + dispatch(setActorModalOpen(false)); + } + }; + + const handleClose = () => { + dispatch(setActorModalOpen(false)) + } + + const handleNameChange = (event: React.ChangeEvent) => { + dispatch(setActorName(event.target.value)); + }; + + + const handleDescriptionChange = (_e: React.ChangeEvent, data: TextAreaProps) => { + dispatch(setActorDescription(data.value as string)) + }; + + return ( + + Edit Actor + +
+ + + + + + Submit + Cancel + + +
+
+ ); +} + +export default ActorModal; \ No newline at end of file diff --git a/src/renderer/applets/model-editor/components/DataflowModal.tsx b/src/renderer/applets/model-editor/components/DataflowModal.tsx new file mode 100644 index 0000000..dff043a --- /dev/null +++ b/src/renderer/applets/model-editor/components/DataflowModal.tsx @@ -0,0 +1,150 @@ +import React from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { Graph } from '@antv/x6'; +import type { DataflowStride } from '../../../store/ModelEditorStore'; +import Dataflow from '../shapes/dataflow' + +import { + // setTextMode, + setDataflowModalOpen, + setDataflowLabel, + setDataflowProtocol, + setDataflowStride +} from '../../../store/ModelEditorStore'; + +import { RootState } from '../../../store'; +import { Checkbox, Form, Modal } from 'semantic-ui-react'; + +interface DataflowModalProps { + graph: Graph; +} + +const DataflowModal: React.FC = ({ graph }) => { + const dispatch = useDispatch(); + + // global redux states + const { + dataflowLabel, + dataflowProtocol, + dataflowModalSelectedCell, + dataflowModalOpen, + dataflowStride + } = useSelector((state: RootState) => state.modelEditor) + + const handleSubmit = () => { + if (dataflowModalSelectedCell) { + const cell = graph.getCellById(dataflowModalSelectedCell); + if (cell.isEdge()) { + + const strideString = Object.keys(dataflowStride) + .filter(key => dataflowStride[key as keyof DataflowStride]) + .map(key => key.charAt(0).toUpperCase()) + .join(' '); + + const label = Dataflow.setDataflowLabel(dataflowLabel, dataflowProtocol, strideString); + cell.setLabelAt(0, label); + + console.log(cell.getLabelAt(0)); + } + dispatch(setDataflowModalOpen(false)); + } + }; + + const handleLabelChange = (event: React.ChangeEvent) => { + dispatch(setDataflowLabel(event.target.value)); + }; + + const handleProtocolChange = (event: React.ChangeEvent) => { + dispatch(setDataflowProtocol(event.target.value)); + }; + + const handleStrideChange = (key: keyof DataflowStride) => { + const updatedDataflowStride = { + ...dataflowStride, + [key]: !dataflowStride[key], + }; + dispatch(setDataflowStride(updatedDataflowStride)); + }; + + return ( + dispatch(setDataflowModalOpen(false))} dimmer="blurring"> + Edit Dataflow + +
+ + + + +
+ + + + Spoofing} + checked={dataflowStride.spoofing} + onChange={() => handleStrideChange('spoofing')} + /> + + + Tampering} + checked={dataflowStride.tampering} + onChange={() => handleStrideChange('tampering')} + /> + + + Repudiation} + checked={dataflowStride.repudiation} + onChange={() => handleStrideChange('repudiation')} + /> + + + Information disclosure} + checked={dataflowStride.informationDisclosure} + onChange={() => handleStrideChange('informationDisclosure')} + /> + + + Denial of service} + checked={dataflowStride.denialOfService} + onChange={() => handleStrideChange('denialOfService')} + /> + + + Elevate privilege} + checked={dataflowStride.elevatePrivilege} + onChange={() => handleStrideChange('elevatePrivilege')} + /> + + +
+ + + Submit + dispatch(setDataflowModalOpen(false))}>Cancel + + +
+
+ ); +} + +export default DataflowModal; \ No newline at end of file diff --git a/src/renderer/applets/model-editor/components/Events.tsx b/src/renderer/applets/model-editor/components/Events.tsx new file mode 100644 index 0000000..e764048 --- /dev/null +++ b/src/renderer/applets/model-editor/components/Events.tsx @@ -0,0 +1,276 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { Cell, Edge, Graph, Node } from '@antv/x6'; +import { useDispatch, useSelector } from 'react-redux'; + +import { + setTextModeSelectedCell, + setTextModeInputValue, + + setSelectedNodeId, + setSelectedEdgeId, + + setDataflowLabel, + setDataflowProtocol, + setDataflowStride, + setDataflowModalSelectedCell, + setDataflowModalOpen, + + setActorModalOpen, + setActorModalSelectedCell, + setActorName, + setActorDescription, + + setSystemModalOpen, + setSystemModalSelectedCell, + setSystemName, + setSystemStack, + setSystemDescription, + + setZoneModalSelectedCell, + setZoneModalOpen, + setZoneName, + setZoneTrustLevel, + setZoneDescription, +} from '../../../store/ModelEditorStore'; + +import type { DataflowStride } from '../../../store/ModelEditorStore'; + +import Dataflow from '../shapes/dataflow'; +import { AppDispatch, RootState } from '../../../store'; + +interface EventsProps { + graph: Graph; +} + +const GraphEvents: React.FC = ({ graph }) => { + const dispatch = useDispatch(); + + const { + selectedNodeId, + selectedEdgeId, + } = useSelector((state: RootState) => state.modelEditor); + + const { + explicitObjectSelection + } = useSelector((state: RootState) => state.settings); + + // Set to track processed nodes + const processedNodes = useRef>(new Set()); + + useEffect(() => { + // Function to handle what happens when a new node is added + const nodeAdded = (node: Node) => { + console.log("Dataflow added..."); + + // Convert dataflow to edge when added to canvas + if (node.shape === 'dataflow-stencil') { + // Check for duplicate node IDs + if (processedNodes.current.has(node.id)) { + node.remove(); + return; + } + + Dataflow.createEdge(graph, node); + node.remove(); + + // Add node ID to the processed set + processedNodes.current.add(node.id); + } + }; + + graph.on('node:added', ({ node }) => nodeAdded(node)); + + return () => { + graph.off('node:added', nodeAdded); + }; + }, []); + + useEffect(() => { + // edge events + const edgeSelected = ({ cell }: { cell: Cell }) => { + if (cell.isEdge()) { + dispatch(setSelectedEdgeId(cell.id)); + cell.addTools([ + 'edge-vertices', + 'edge-source-handle', + 'edge-target-handle', + ]); + } + }; + + const edgeUnselected = ({ cell }: { cell: Cell }) => { + if (cell.isEdge() && selectedEdgeId && cell.id === selectedEdgeId) { + dispatch(setSelectedEdgeId(null)); + } + cell.removeTools(); + }; + + const mapStringToDataflowStride = (input: string): DataflowStride => { + // Strip all non-STRIDE characters from the input string + const sanitizedInput = input.replace(/[^STRIDEstride]/g, ''); + + // Create a default DataflowStride object with all values set to false + const result: DataflowStride = { + spoofing: false, + tampering: false, + repudiation: false, + informationDisclosure: false, + denialOfService: false, + elevatePrivilege: false, + }; + + // Map characters to their corresponding boolean values + for (const char of sanitizedInput) { + switch (char.toUpperCase()) { + case 'S': + result.spoofing = true; + break; + case 'T': + result.tampering = true; + break; + case 'R': + result.repudiation = true; + break; + case 'I': + result.informationDisclosure = true; + break; + case 'D': + result.denialOfService = true; + break; + case 'E': + result.elevatePrivilege = true; + break; + default: + // This case should never be reached due to the sanitization step + break; + } + } + + return result; + }; + + const edgeContextmenu = ({ cell, e }: { cell: Cell, e: MouseEvent }) => { + if (graph.getSelectedCells().length <= 1 && cell.isEdge()) { + if (!explicitObjectSelection || (selectedEdgeId && cell.id === selectedEdgeId)) { + e.stopPropagation(); + e.preventDefault(); + // Perform your action here for the selected edge and context menu click + const label = cell.getLabelAt(0)!.attrs!.label!.text! as string; + const protocol = cell.getLabelAt(0)!.attrs!.protocol!.text! as string; + const stride = mapStringToDataflowStride(cell.getLabelAt(0)!.attrs!.stride!.text! as string); + // const description = cell.getData().description! + dispatch(setDataflowLabel(label)); + dispatch(setDataflowProtocol(protocol)); + dispatch(setDataflowStride(stride)); + dispatch(setDataflowModalSelectedCell(cell.id)); + dispatch(setDataflowModalOpen(true)); + } + } + }; + + // node events + const nodeSelected = ({ cell }: { cell: Cell }) => { + if (cell.isNode()) { + dispatch(setSelectedEdgeId(null)); + dispatch(setSelectedNodeId(cell.id)); + } + }; + + const nodeUnselected = ({ cell }: { cell: Cell }) => { + if (cell.isNode() && selectedNodeId && cell.id === selectedNodeId) { + dispatch(setSelectedNodeId(null)); + dispatch(setSelectedEdgeId(null)); + } + }; + + const nodeContextmenu = ({ cell, e }: { cell: Cell, e: MouseEvent }) => { + if (graph.getSelectedCells().length <= 1 && cell.isNode()) { + if (!explicitObjectSelection || (selectedNodeId && cell.id === selectedNodeId)) { + e.stopPropagation(); + e.preventDefault(); + const inputValue = cell.getAttrs()!.text!.text! as string; + dispatch(setTextModeInputValue(inputValue)); + dispatch(setTextModeSelectedCell(cell.id)); + + if (cell.shape === 'actor') { + const name = cell.getAttrs()!.name!.text! as string; + const description = cell.getData()!.description! as string; + + dispatch(setActorName(name)); + dispatch(setActorDescription(description)); + dispatch(setActorModalSelectedCell(cell.id)); + dispatch(setActorModalOpen(true)); + + } else if (cell.shape === 'system') { + const name = cell.getAttrs()!.name!.text! as string; + const stack = cell.getAttrs()!.stack!.text! as string; + const description = cell.getData()!.description! as string; + dispatch(setSystemName(name)); + dispatch(setSystemStack(stack)); + dispatch(setSystemDescription(description)); + dispatch(setSystemModalSelectedCell(cell.id)); + dispatch(setSystemModalOpen(true)); + + } else if (cell.shape === 'zone') { + const name = cell.getAttrs()!.name!.text! as string; + const trustLevel = cell.getAttrs()!.trustLevel!.text! as string; + const description = cell.getData()!.description! as string; + + dispatch(setZoneName(name)); + dispatch(setZoneTrustLevel(trustLevel)); + dispatch(setZoneDescription(description)); + dispatch(setZoneModalSelectedCell(cell.id)); + dispatch(setZoneModalOpen(true)); + } + } + } + }; + + const updateZIndex = (cell: Cell, parentZIndex: number) => { + const newZIndex = parentZIndex + 1; + cell.setZIndex(newZIndex); + + // Recursively update zIndex of all children + const children = cell.getChildren(); + if (children) { + children.forEach(child => { + updateZIndex(child, newZIndex); + }); + } + }; + + const nodeEmbed = ({ cell }: { cell: Cell }) => { + if (cell.hasParent()) { + const parent = cell.getParent(); + if (parent) { + const parentZIndex = parent.getZIndex() || 0; + updateZIndex(cell, parentZIndex); + } + } + }; + + // Registering event listeners + graph.on('edge:selected', edgeSelected); + graph.on('edge:unselected', edgeUnselected); + graph.on('edge:contextmenu', edgeContextmenu); + graph.on('node:selected', nodeSelected); + graph.on('node:unselected', nodeUnselected); + graph.on('node:contextmenu', nodeContextmenu); + graph.on('node:change:parent', nodeEmbed); + + return () => { + graph.off('edge:selected', edgeSelected); + graph.off('edge:unselected', edgeUnselected); + graph.off('edge:contextmenu', edgeContextmenu); + graph.off('node:selected', nodeSelected); + graph.off('node:unselected', nodeUnselected); + graph.off('node:contextmenu', nodeContextmenu); + graph.off('node:change:parent', nodeEmbed); + }; + }, [selectedNodeId, selectedEdgeId, explicitObjectSelection]); + + // This component doesn't render anything itself + return null; +}; + +export default GraphEvents; diff --git a/src/renderer/applets/model-editor/components/ExportModal.tsx b/src/renderer/applets/model-editor/components/ExportModal.tsx new file mode 100644 index 0000000..ba63057 --- /dev/null +++ b/src/renderer/applets/model-editor/components/ExportModal.tsx @@ -0,0 +1,107 @@ +// File: /mnt/data/code_extracted/frontend/src/applets/model-editor/components/ExportModal.tsx +import React, { useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { Modal, Form, Radio } from 'semantic-ui-react'; + +import { Graph } from '@antv/x6'; + +import { AppDispatch } from '../../../store'; + +import { + exportGraph, + setExportModalOpen +} from '../../../store/ModelEditorStore'; +import { showToast } from '../../../store/SettingsStore'; + +interface ExportModalProps { + graph: Graph, + filename: string +} + +const ExportModal: React.FC = ({graph, filename}) => { + const dispatch = useDispatch(); + const { + isExportModalOpen + } = useSelector((state: any) => state.modelEditor); + + const [format, setFormat] = useState('json'); + // const [directory, setDirectory] = useState(''); + + const handleExport = async () => { + try { + dispatch(exportGraph({ format, filename, graph })); + dispatch(setExportModalOpen(false)); + } catch (error) { + console.log(error); + } + }; + + const handleClose = () => { + dispatch(setExportModalOpen(false)); + }; + + if (!isExportModalOpen) return null; + + return ( + + + {'Export current model'} + + +
+ + + + + setFormat('json')} + /> + + + setFormat('png')} + /> + + + setFormat('jpeg')} + /> + + + setFormat('svg')} + /> + + + + + + Export + + + Cancel + + +
+
+
+ ); +}; + +export default ExportModal; diff --git a/src/renderer/applets/model-editor/components/ImportModal.tsx b/src/renderer/applets/model-editor/components/ImportModal.tsx new file mode 100644 index 0000000..b6470dd --- /dev/null +++ b/src/renderer/applets/model-editor/components/ImportModal.tsx @@ -0,0 +1,241 @@ +import React, { useCallback, useRef, useState, useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { Modal, Form } from 'semantic-ui-react'; +import { Graph } from "@antv/x6"; + +import { AppDispatch } from '../../../store'; + +import { + importGraph, + setImportModalOpen +} from '../../../store/ModelEditorStore'; + +import { + ImportOutlined +} from '@ant-design/icons'; +import { showToast, hideToast } from '../../../store/SettingsStore'; + +interface ImportModalProps { + graph: Graph +} + +const ImportModal: React.FC = ({ graph }) => { + const dispatch = useDispatch(); + const { + isImportModalOpen + } = useSelector((state: any) => state.modelEditor); + + const [isDragging, setIsDragging] = useState(false); + const [error, setError] = useState(null); + const [fileName, setFileName] = useState(null); + const [jsonData, setJsonData] = useState(null); + const [isFileValid, setIsFileValid] = useState(false); + const fileInputRef = useRef(null); + + const handleDragOver = (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + setIsDragging(true); + }; + + const handleDragLeave = (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + setIsDragging(false); + }; + + const handleFileUpload = (fileContent: any) => { + setJsonData(fileContent); + }; + + const handleDrop = useCallback( + (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + setIsDragging(false); + + const files = e.dataTransfer.files; + if (files.length <= 0) { + setError('No files selected.'); + setFileName(null); + setIsFileValid(false); + return; + } + if (files.length > 1) { + setError('Only one file allowed.'); + setFileName(null); + setIsFileValid(false); + return; + } + + const file = files[0]; + if (file) { + if (file.type === 'application/json') { + const reader = new FileReader(); + reader.onload = (event) => { + try { + const fileContent = JSON.parse(event.target?.result as string); + handleFileUpload(fileContent); + setFileName(file.name); + setError(null); // Clear the error when a valid file is selected + setIsFileValid(true); + } catch (err) { + setError('Error parsing JSON file'); + setFileName(null); + setIsFileValid(false); + } + }; + reader.readAsText(file); + } else { + setError('Invalid file type. Only JSON files allowed.'); + setFileName(null); + setIsFileValid(false); + } + } else { + setError('No file selected. Please select a valid JSON file.'); + setFileName(null); + setIsFileValid(false); + } + }, + [handleFileUpload] + ); + + const handleFileChange = useCallback( + (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (file) { + if (file.type === 'application/json') { + const reader = new FileReader(); + reader.onload = (event) => { + try { + const fileContent = JSON.parse(event.target?.result as string); + handleFileUpload(fileContent); + setFileName(file.name); + setError(null); // Clear the error when a valid file is selected + setIsFileValid(true); + } catch (err) { + setError('Error parsing JSON file'); + setFileName(null); + setIsFileValid(false); + } + }; + reader.readAsText(file); + } else { + setError('Invalid file type. Only JSON files allowed.'); + setFileName(null); + setIsFileValid(false); + } + } else { + setError('No file selected. Please select a valid JSON file.'); + setFileName(null); + setIsFileValid(false); + } + }, + [handleFileUpload] + ); + + const handleClick = () => { + fileInputRef.current?.click(); + }; + + const handleImport = async () => { + if (graph && jsonData) { + try { + const promise = dispatch(importGraph({ graph, jsonData })).unwrap(); + dispatch(setImportModalOpen(false)); + + dispatch( + showToast({ + promise: promise, + loadingMessage: 'Importing threat model...', + successMessage: 'Threat model imported successfully', + errorMessage: 'Failed to import threat model', + }) + ); + + await promise; + + setFileName(null); + setJsonData(null); + setError(null); + setIsFileValid(false); + } catch (error) { + setFileName(null); + setJsonData(null); + setError(null); + setIsFileValid(false); + } + } else { + setError("No file selected"); + } + }; + + const handleClose = () => { + dispatch(setImportModalOpen(false)); + setFileName(null); + setJsonData(null); + setError(null); + setIsFileValid(false); + }; + + useEffect(() => { + if (!isImportModalOpen) { + setFileName(null); + setJsonData(null); + setError(null); + setIsFileValid(false); + } + }, [isImportModalOpen]); + + if (!isImportModalOpen) return null; + + return ( + + + {'Import existing model'} + + +
+ +
+ + {!fileName &&

Drag and drop a JSON file here, or click to select a file.

} + {fileName &&

Selected file: {fileName}

} + {error &&

{error}

} + +
+
+ + + Import + + + Cancel + + +
+
+
+ ); +}; + +export default ImportModal; diff --git a/src/renderer/applets/model-editor/components/Keys.tsx b/src/renderer/applets/model-editor/components/Keys.tsx new file mode 100644 index 0000000..9d20c31 --- /dev/null +++ b/src/renderer/applets/model-editor/components/Keys.tsx @@ -0,0 +1,281 @@ +/** TODOS + * cmd+a -> select all + */ +import React, { useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { AppDispatch, RootState } from '../../../store'; +import { Graph, Rectangle } from '@antv/x6'; + +import { useParams } from 'react-router-dom'; + +import Actions from '../actions' +import { + setExportModalOpen, + setImportModalOpen, + setExportPressed, + setImportPressed, + setFitViewPressed, + setZoomInPressed, + setZoomOutPressed, + setUndoPressed, + setRedoPressed, + setCutPressed, + setCopyPressed, + setPastePressed, + setDeletePressed, + setSavePressed, + setSelectAllPressed, +} from '../../../store/ModelEditorStore' + +import { + addLatestVersion +} from '../../../store/VersionsStore' +import { showToast } from '../../../store/SettingsStore'; +import { compareHashes } from '../../../utils'; + +interface KeysProps { + graph: Graph; +} + +const Keys: React.FC = ({ graph }) => { + const dispatch = useDispatch(); + const { modelId } = useParams(); + + const { + latestVersion + } = useSelector((state: RootState) => state.versions); + + const { + actorModalOpen, + systemModalOpen, + zoneModalOpen, + dataflowModalOpen + } = useSelector((state: RootState) => state.modelEditor); + + // suppress default key shortcuts... + useEffect(() => { + const handleKeyPress = (event:KeyboardEvent) => { + // Check if Cmd (metaKey on Mac) is pressed along with "+" (equal sign key with shift) + if (event.metaKey && event.key === '+') { + event.preventDefault(); // Prevent the default action (zoom in this case) + } + + // Check if Cmd (metaKey on Mac) is pressed along with "-" (equal sign key with shift) + if (event.metaKey && event.key === '-') { + event.preventDefault(); // Prevent the default action (zoom in this case) + } + + // Check if Cmd (metaKey on Mac) is pressed along with "s" (equal sign key with shift) + if (event.metaKey && event.key === 's') { + event.preventDefault(); // Prevent the default action (zoom in this case) + } + + // Check if Cmd (metaKey on Mac) is pressed along with "s" (equal sign key with shift) + if (event.metaKey && event.key === 'a') { + // do not prevent default behavior of ctrl/meta + a when any modal is open + const except = actorModalOpen || systemModalOpen || zoneModalOpen || dataflowModalOpen + + if (!except) { + event.preventDefault(); // Prevent the default action (zoom in this case) + } + } + + // Check if Cmd + Space is pressed + if (event.metaKey && event.key === ' ') { + event.preventDefault(); // Prevent the default action (Spotlight search on Mac) + } + }; + + // Add event listener for keydown + document.addEventListener('keydown', handleKeyPress); + + // Cleanup the event listener on component unmount + return () => { + document.removeEventListener('keydown', handleKeyPress); + }; + }, [ + actorModalOpen, + systemModalOpen, + zoneModalOpen, + dataflowModalOpen + ]); + + // Update ref whenever `isTextMode` changes + // useEffect(() => { + // // isTextModeRef.current = isTextMode; + // Tools.toggleTextMode(graph.getCells(), isTextMode) + // }, [isTextMode]); + + // Function to register all keybindings + const registerKeyBindings = () => { + + const handleSaveSubmit = async () => { + if (modelId && graph && latestVersion) { + const oldGraph = latestVersion.payload.cells + const newGraph =graph.toJSON().cells + + if (compareHashes(oldGraph, newGraph) === true) { + // if hashes match, we do not save. + return false; + } + + const { x, y, height, width }: Rectangle = graph.getGraphArea() + const promise = dispatch(addLatestVersion({graph, modelId, x, y, height, width})) + + dispatch(showToast({ + promise, + loadingMessage: 'Saving threat model...', + successMessage: 'Threat model saved', + errorMessage: 'Failed to save threat model', + })); + return true; + } + return false; + } + + // save -> ctrl/meta + s + const registerSaveKeys = async () => { + graph.bindKey(['meta+s', 'ctrl+s'], async () => { + if (await handleSaveSubmit()) { + dispatch(setSavePressed(true)) + } + }) + } + + // export -> ctrl/meta + e + const registerExportKeys = async () => { + graph.bindKey(['meta+e', 'ctrl+e'], async () => { + dispatch(setExportModalOpen(true)); + dispatch(setExportPressed(true)) + }) + } + + // import -> ctrl/meta + i + const registerImportKeys = async () => { + graph.bindKey(['meta+i', 'ctrl+i'], async () => { + dispatch(setImportModalOpen(true)); + dispatch(setImportPressed(true)) + }) + } + + // fit view -> ctrl/meta + whitespace + const registerFitViewKeys = () => { + graph.bindKey(['meta+space', 'ctrl+space'], () => { + if (Actions.fitViewAction(graph)) { + dispatch(setFitViewPressed(true)) + } + }) + } + + // zoom in -> ctrl/meta + "-" + const registerZoomInKeys = () => { + graph.bindKey(['meta+=', 'ctrl+='], () => { + if (Actions.zoomInAction(graph)) { + dispatch(setZoomInPressed(true)) + } + }) + } + + // zoom out -> ctrl/meta + "+" + const registerZoomOutKeys = () => { + graph.bindKey(['meta+-', 'ctrl+-'], () => { + if (Actions.zoomOutAction(graph)) { + dispatch(setZoomOutPressed(true)) + } + }) + } + + + // undo -> ctrl/meta + z + const registerUndoKeys = () => { + graph.bindKey(['meta+z', 'ctrl+z'], () => { + if (Actions.undoAction(graph)) { + dispatch(setUndoPressed(true)) + } + }) + } + + // redo -> ctrl/meta + shift + z + const registerRedoKeys = () => { + graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => { + if (Actions.redoAction(graph)) { + dispatch(setRedoPressed(true)) + } + }) + } + + // cut -> ctrl/meta + a + const registerSelectAllKeys = () => { + graph.bindKey(['meta+a', 'ctrl+a'], () => { + if (Actions.selectAllAction(graph)) { + dispatch(setSelectAllPressed(true)) + } + }) + } + + // cut -> ctrl/meta + x + const registerCutKeys = () => { + graph.bindKey(['meta+x', 'ctrl+x'], () => { + if (Actions.cutAction(graph)) { + dispatch(setCutPressed(true)) + } + }) + } + + // copy -> ctrl/meta + c + const registerCopyKeys = () => { + graph.bindKey(['meta+c', 'ctrl+c'], () => { + if (Actions.copyAction(graph)) { + dispatch(setCopyPressed(true)) + } + }); + }; + + // paste -> ctrl/meta + v + const registerPasteKeys = () => { + graph.bindKey(['meta+v', 'ctrl+v'], () => { + if (Actions.pasteAction(graph)) { + dispatch(setPastePressed(true)) + } + }) + } + + // delete -> backspace + const registerDeleteKeys = () => { + graph.bindKey('backspace', () => { + if (Actions.deleteAction(graph)) { + dispatch(setDeletePressed(true)) + } + }) + } + + registerSaveKeys(); + registerExportKeys(); + registerImportKeys(); + registerZoomInKeys(); + registerZoomOutKeys(); + registerFitViewKeys(); + registerSelectAllKeys(); + registerCutKeys(); + registerCopyKeys(); + registerPasteKeys(); + registerUndoKeys(); + registerRedoKeys(); + registerDeleteKeys(); + }; + + useEffect(() => { + registerKeyBindings(); + + // Cleanup function to unbind all keybindings when the component unmounts + return () => { + // Here you would remove all the bindings to avoid memory leaks + // This might depend on the API provided by @antv/x6 for unbinding + }; + }, /*[graph, dispatch, isTextMode]*/); // Add dependencies as needed + + // Component doesn't render anything, so return null + return null; +}; + +export default Keys; \ No newline at end of file diff --git a/src/renderer/applets/model-editor/components/Stencil.tsx b/src/renderer/applets/model-editor/components/Stencil.tsx new file mode 100644 index 0000000..e81872b --- /dev/null +++ b/src/renderer/applets/model-editor/components/Stencil.tsx @@ -0,0 +1,72 @@ +import React, { useEffect, useRef } from 'react'; +import { Graph } from '@antv/x6'; +import { Stencil } from '@antv/x6-plugin-stencil'; + +import actor from '../shapes/system'; +import system from '../shapes/actor'; +import zone from '../shapes/zone'; +import dataflow from '../shapes/dataflow'; + +interface StencilContainerProps { + graph: Graph; +} + +const StencilContainer: React.FC = ({ graph }) => { + const stencilContainerRef = useRef(null); + + const stencilContainerStyle: React.CSSProperties = { + position: 'absolute', + left: '32px', + top: '130px', + width: '135px', + height: '400px', + zIndex: 2, + } + + useEffect(() => { + if (!graph) { + console.error('Graph is not provided'); + return; + } + + if (graph && stencilContainerRef.current) { + const stencil = new Stencil({ + target: graph, + stencilGraphWidth: 250, + stencilGraphHeight: 350, + collapsable: false, + groups: [ + { + name: 'group1', + }, + ], + layoutOptions: { + columns: 1, + }, + }); + + stencilContainerRef.current.appendChild(stencil.container); + + const a = actor.create(graph); + const s = system.create(graph); + const d = dataflow.createEdgeStencil(graph); + const z = zone.create(graph); + + stencil.load([a, s, d, z], 'group1'); + } + + // Assuming you might want to perform some cleanup or further actions + // return () => { + // // Cleanup logic here if necessary + // }; + }, [graph]); // Effect depends on `graph` prop + + // Since this component is used for side effects rather than rendering, return null + return ( +
+
+
+ ) +}; + +export default StencilContainer; \ No newline at end of file diff --git a/src/renderer/applets/model-editor/components/SystemModal.tsx b/src/renderer/applets/model-editor/components/SystemModal.tsx new file mode 100644 index 0000000..ac209be --- /dev/null +++ b/src/renderer/applets/model-editor/components/SystemModal.tsx @@ -0,0 +1,108 @@ +import React from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { Graph } from '@antv/x6'; + +import System from '../shapes/system' + +import { + setSystemDescription, + setSystemModalOpen, + setSystemName, + setSystemStack, +} from '../../../store/ModelEditorStore'; + +import { RootState, AppDispatch } from '../../../store'; + +import { Form, Modal, TextAreaProps } from 'semantic-ui-react'; + +interface SystemModalProps { + graph: Graph; + onClose: () => void +} + +const SystemModal: React.FC = ({ graph, onClose }) => { + const dispatch = useDispatch(); + + // global redux states + const { + systemModalOpen, + systemModalSelectedCell, + systemName, + systemStack, + systemDescription, + // textModeInputValue, + // textModeSelectedCell, + } = useSelector((state: RootState) => state.modelEditor) + + const handleSubmit = () => { + if (systemModalSelectedCell) { + const cell = graph.getCellById(systemModalSelectedCell); + if (cell.isNode()) { + + const attrs = System.setSystemAttrs(systemName, systemStack); + // todo: set Description + cell.setAttrs(attrs); + cell.setData({description: systemDescription}) + } + dispatch(setSystemModalOpen(false)); + } + }; + + const handleClose = () => { + dispatch(setSystemModalOpen(false)) + onClose() + } + + const handleNameChange = (event: React.ChangeEvent) => { + dispatch(setSystemName(event.target.value)); + }; + + const handleStackChange = (event: React.ChangeEvent) => { + dispatch(setSystemStack(event.target.value)); + }; + + const handleDescriptionChange = (_e: React.ChangeEvent, data: TextAreaProps) => { + dispatch(setSystemDescription(data.value as string)) + }; + + return ( + + Edit System + +
+ + + + + + + + Submit + Cancel + + +
+
+ ); +} + +export default SystemModal; \ No newline at end of file diff --git a/src/renderer/applets/model-editor/components/Toolbar.tsx b/src/renderer/applets/model-editor/components/Toolbar.tsx new file mode 100644 index 0000000..a7bc0bd --- /dev/null +++ b/src/renderer/applets/model-editor/components/Toolbar.tsx @@ -0,0 +1,337 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; +import { useDispatch, useSelector } from 'react-redux'; +import { RootState, AppDispatch } from '../../../store'; +import actions from '../actions'; +import { + setSavePressed, + setExportPressed, + setImportPressed, + setFitViewPressed, + setZoomInPressed, + setZoomOutPressed, + setUndoPressed, + setRedoPressed, + setSelectAllPressed, + setCutPressed, + setCopyPressed, + setPastePressed, + setDeletePressed, + setExportModalOpen, + setImportModalOpen, +} from '../../../store/ModelEditorStore'; +import { showToast } from '../../../store/SettingsStore'; +import { addLatestVersion } from '../../../store/VersionsStore'; +import { Graph, Rectangle } from '@antv/x6'; +import { Toolbar } from '@antv/x6-react-components'; +import '@antv/x6-react-components/es/menu/style/index.css'; +import '@antv/x6-react-components/es/toolbar/style/index.css'; +import '@antv/x6-react-components/es/color-picker/style/index.css'; +import 'antd/dist/reset.css'; +import { + SaveOutlined, + ExportOutlined, + ImportOutlined, + ZoomInOutlined, + ZoomOutOutlined, + RedoOutlined, + UndoOutlined, + DeleteOutlined, + CompressOutlined, + ScissorOutlined, + CopyOutlined, + SnippetsOutlined, + CloseOutlined, + ExpandOutlined, +} from '@ant-design/icons'; +import { compareHashes } from '../../../utils'; + +const Item = Toolbar.Item; // eslint-disable-line +const Group = Toolbar.Group; // eslint-disable-line + +interface CustomToolbarProps { + graph: Graph; +} + +const CustomToolbar: React.FC = ({ graph }) => { + + const dispatch = useDispatch(); + const navigate = useNavigate(); + const { productId, incrementId, modelId } = useParams(); + + const { + isSavePressed, + isExportPressed, + isImportPressed, + isFitViewPressed, + isZoomInPressed, + isZoomOutPressed, + isUndoPressed, + isRedoPressed, + isSelectAllPressed, + isCutPressed, + isCopyPressed, + isPastePressed, + isDeletePressed, + } = useSelector((state: RootState) => state.modelEditor); + + const { latestVersion } = useSelector((state: RootState) => state.versions); + + const [, setModelIdParam] = useState(); + const [canRedo, setCanRedo] = useState(false); + const [canUndo, setCanUndo] = useState(false); + + useEffect(() => { + setModelIdParam(modelId); + + let timerId: number | undefined; + if (isSavePressed) { + timerId = window.setTimeout(() => { + dispatch(setSavePressed(false)); + }, 100); + } + if (isExportPressed) { + timerId = window.setTimeout(() => { + dispatch(setExportPressed(false)); + }, 100); + } + if (isImportPressed) { + timerId = window.setTimeout(() => { + dispatch(setImportPressed(false)); + }, 100); + } + if (isFitViewPressed) { + timerId = window.setTimeout(() => { + dispatch(setFitViewPressed(false)); + }, 100); + } + if (isZoomInPressed) { + timerId = window.setTimeout(() => { + dispatch(setZoomInPressed(false)); + }, 100); + } + if (isZoomOutPressed) { + timerId = window.setTimeout(() => { + dispatch(setZoomOutPressed(false)); + }, 100); + } + if (isUndoPressed) { + timerId = window.setTimeout(() => { + dispatch(setUndoPressed(false)); + }, 100); + } + if (isRedoPressed) { + timerId = window.setTimeout(() => { + dispatch(setRedoPressed(false)); + }, 100); + } + if (isSelectAllPressed) { + timerId = window.setTimeout(() => { + dispatch(setSelectAllPressed(false)); + }, 100); + } + if (isCutPressed) { + timerId = window.setTimeout(() => { + dispatch(setCutPressed(false)); + }, 100); + } + if (isCopyPressed) { + timerId = window.setTimeout(() => { + dispatch(setCopyPressed(false)); + }, 100); + } + if (isPastePressed) { + timerId = window.setTimeout(() => { + dispatch(setPastePressed(false)); + }, 100); + } + if (isDeletePressed) { + timerId = window.setTimeout(() => { + dispatch(setDeletePressed(false)); + }, 100); + } + return () => { + if (timerId) clearTimeout(timerId); + }; + }, [ + isSavePressed, + isExportPressed, + isImportPressed, + isFitViewPressed, + isZoomInPressed, + isZoomOutPressed, + isUndoPressed, + isRedoPressed, + isSelectAllPressed, + isCutPressed, + isCopyPressed, + isPastePressed, + isDeletePressed, + modelId, + ]); + + useEffect(() => { + graph.on('history:change', () => { + setCanRedo(graph.canRedo()); + setCanUndo(graph.canUndo()); + }); + }, [graph]); + + const handleSaveSubmit = async () => { + if (modelId && latestVersion) { + const oldGraph = latestVersion.payload.cells; + const newGraph = graph.toJSON().cells; + + if (compareHashes(oldGraph, newGraph) === true) { + return; + } + + const { x, y, height, width }: Rectangle = graph.getGraphArea() + const promise = dispatch(addLatestVersion({ modelId, graph, x, y, height, width })); + dispatch( + showToast({ + promise, + loadingMessage: 'Saving threat model...', + successMessage: 'Threat model saved', + errorMessage: 'Failed to save threat model', + }) + ); + } + }; + + const handleSaveAndCloseSubmit = async () => { + await handleSaveSubmit(); + navigate(`/products/${productId}/increments/${incrementId}`); + }; + + return ( +
+ + {/* Save group */} + + } + onClick={handleSaveSubmit} + /> + } + onClick={() => dispatch(setExportModalOpen(true))} + /> + } + onClick={() => dispatch(setImportModalOpen(true))} + /> + + + {/* Zoom group */} + + actions.fitViewAction(graph)} + icon={} + /> + actions.zoomInAction(graph)} + active={isZoomInPressed} + icon={} + /> + actions.zoomOutAction(graph)} + active={isZoomOutPressed} + icon={} + /> + + + {/* History group */} + + } + disabled={!canUndo} + active={isUndoPressed} + onClick={() => actions.undoAction(graph)} + /> + } + disabled={!canRedo} + active={isRedoPressed} + onClick={() => actions.redoAction(graph)} + /> + + + {/* Interaction group */} + + } + disabled={false} + tooltip="Select all (ctrl/cmd + a)" + active={isSelectAllPressed} + onClick={() => actions.selectAllAction(graph)} + /> + } + disabled={false} + tooltip="Cut (ctrl/cmd + x)" + active={isCutPressed} + onClick={() => actions.cutAction(graph)} + /> + } + disabled={false} + tooltip="Copy (ctrl/cmd + c)" + active={isCopyPressed} + onClick={() => actions.copyAction(graph)} + /> + } + disabled={false} + tooltip="Paste (ctrl/cmd + v)" + active={isPastePressed} + onClick={() => actions.pasteAction(graph)} + /> + } + disabled={false} + tooltip="Delete (backspace)" + active={isDeletePressed} + onClick={() => actions.deleteAction(graph)} + /> + + + {/* Save and close */} + } + tooltip="Save and Close Threat Model Editor" + onClick={handleSaveAndCloseSubmit} + /> + +
+ ); +}; + +export default CustomToolbar; diff --git a/src/renderer/applets/model-editor/components/ZoneModal.tsx b/src/renderer/applets/model-editor/components/ZoneModal.tsx new file mode 100644 index 0000000..f911a56 --- /dev/null +++ b/src/renderer/applets/model-editor/components/ZoneModal.tsx @@ -0,0 +1,129 @@ +import React from 'react'; + +import { useDispatch, useSelector } from 'react-redux'; +import { Graph } from '@antv/x6'; + +import Zone from '../shapes/zone' + +import { + setZoneModalOpen, + setZoneName, + setZoneTrustLevel, + setZoneDescription, +} from '../../../store/ModelEditorStore'; + +import { RootState, AppDispatch } from '../../../store'; + +import { Form, Modal, Radio, TextAreaProps } from 'semantic-ui-react'; + +interface ZoneModalProps { + graph: Graph; +} + +const ZoneModal: React.FC = ({ graph }) => { + const dispatch = useDispatch(); + + // global redux states + const { + zoneModalOpen, + zoneModalSelectedCell, + zoneName, + zoneTrustLevel, + zoneDescription + } = useSelector((state: RootState) => state.modelEditor) + + const handleSubmit = () => { + if (zoneModalSelectedCell) { + const cell = graph.getCellById(zoneModalSelectedCell); + if (cell.isNode()) { + + const attrs = Zone.setZoneAttrs(zoneName, zoneTrustLevel); + cell.setAttrs(attrs); + cell.setData({description: zoneDescription}) + } + dispatch(setZoneModalOpen(false)); + } + }; + + const handleClose = () => { + dispatch(setZoneModalOpen(false)) + } + + const handleNameChange = (event: React.ChangeEvent) => { + dispatch(setZoneName(event.target.value)); + }; + + const handleTrustLevelChange = (value: string) => { + dispatch(setZoneTrustLevel(value)); + }; + + const handleDescriptionChange = (_e: React.ChangeEvent, data: TextAreaProps) => { + dispatch(setZoneDescription(data.value as string)) + }; + + return ( + + Edit Zone + +
+ + +
+ + + + handleTrustLevelChange('')} + /> + + + handleTrustLevelChange('untrusted')} + /> + + + handleTrustLevelChange('trusted')} + /> + + +
+ + + + + Submit + Cancel + + +
+
+ ); +} + +export default ZoneModal; \ No newline at end of file diff --git a/src/renderer/applets/model-editor/index.tsx b/src/renderer/applets/model-editor/index.tsx new file mode 100644 index 0000000..6321bd9 --- /dev/null +++ b/src/renderer/applets/model-editor/index.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import ModelEditor from './ModelEditor'; // Assuming App.tsx is your main component +import './index.css' + +import 'semantic-ui-css/semantic.min.css'; + +ReactDOM.render( + + + , + document.getElementById('root') +) \ No newline at end of file diff --git a/src/renderer/applets/model-editor/setup.tsx b/src/renderer/applets/model-editor/setup.tsx new file mode 100644 index 0000000..b7d8eaf --- /dev/null +++ b/src/renderer/applets/model-editor/setup.tsx @@ -0,0 +1,160 @@ +import { Graph } from '@antv/x6' +import { Transform } from '@antv/x6-plugin-transform' +import { Selection } from '@antv/x6-plugin-selection' +import { Snapline } from '@antv/x6-plugin-snapline' +import { Keyboard } from '@antv/x6-plugin-keyboard' +import { Clipboard } from '@antv/x6-plugin-clipboard' +import { History } from '@antv/x6-plugin-history' +// import { MiniMap } from '@antv/x6-plugin-minimap' +import { Export } from '@antv/x6-plugin-export' + +import './ModelEditor.css' + +const topbar = document.getElementById('topbar'); +const toolbar = document.getElementById('toolbar'); +const topbarHeight = topbar ? topbar.offsetHeight : 0; +const toolbarHeight = toolbar ? toolbar.offsetHeight : 0; + +const graphHeight = window.innerHeight - topbarHeight - toolbarHeight; + + + +// const create = (container: HTMLDivElement, minimap: HTMLDivElement) => new Graph({ +const create = (container: HTMLDivElement, gridVisible: 'none' | 'dot' | 'mesh') => new Graph({ + container: container, + grid: { + visible: gridVisible === 'none' ? false : true, + type: gridVisible === 'dot' ? 'dot': 'mesh', // 'dot' | 'fixedDot' | 'mesh' + }, + width: window.innerWidth, + // height: window.innerHeight, + height: graphHeight, + panning: { + enabled: true, + eventTypes: ['rightMouseDown', 'mouseWheel'] + // eventTypes: ['rightMouseDown'], + }, + mousewheel: { + enabled: true, + zoomAtMousePosition: true, + global: true, + minScale: 0.2, + // maxScale: 4, + factor: 1.1, + modifiers: ['ctrl'] + }, + connecting: { + router: { + name: 'normal', + args: { + offset: 'center', + }, + }, + connector: { + name: 'smooth', + args: { + radius: 2, + }, + }, + anchor: 'center', + connectionPoint: 'boundary', + allowPort: false, + allowLoop: true, + }, + highlighting: { + nodeAvailable: { + name: 'stroke', + args: { + attrs: { + 'stroke-width': '2', + padding: 0, + stroke: 'green', + }, + }, + }, + }, + embedding: { + enabled: true, + findParent({ node }) { + const bbox = node.getBBox() + return this.getNodes().filter( (node) => { + const data = node.getData<{parent:boolean}>() + if(data && data.parent) { + const targetBBox = node.getBBox() + return bbox.isIntersectWithRect(targetBBox) + } + return false + }) + }, + }, +}) +.use( + new Transform({ + resizing: true + }) +) +.use( + new Snapline() +) +.use( + new Selection({ + className: 'selection', + rubberband: true, + showNodeSelectionBox: true, + showEdgeSelectionBox: true, + strict: true, + movable: false, + multipleSelectionModifiers: 'shift', + pointerEvents: 'none', + }), +) +.use( + new Keyboard() +) +.use( + new Clipboard() +) +.use( + new History({ + beforeAddCommand: (event: string, args: any) => { + let keepItemInHistory: boolean = true + // Ensure args is not null and check for change events on edge vertices + if (args && args.current && args.current.items) { + const items = args.current.items + for (const item of items) { + if (item === 'edge-vertices' || 'edge-source-handle' || 'edge-target-handle') { + console.log("FALSE") + keepItemInHistory = false; + } + } + } + + if (args && args.previous && args.previous.items) { + const items = args.previous.items + for (const item of items) { + if (item === 'edge-vertices' || 'edge-source-handle' || 'edge-target-handle') { + console.log("FALSE") + keepItemInHistory = false; + } + } + } + + return keepItemInHistory + } + }) +) +// .use( +// new MiniMap({ +// container: minimap, +// width: 200, +// height: 160, +// padding: 10 +// }) +// ) +.use( + new Export() +) + +export default { + create +}; \ No newline at end of file diff --git a/src/renderer/applets/model-editor/shapes/actor.tsx b/src/renderer/applets/model-editor/shapes/actor.tsx new file mode 100644 index 0000000..c2373a5 --- /dev/null +++ b/src/renderer/applets/model-editor/shapes/actor.tsx @@ -0,0 +1,128 @@ +import { Graph } from "@antv/x6"; + +const setActorAttrs = (name: string) => { + return { + body: { + strokeWidth: 1, + stroke: 'black', + fill: 'white', + rx: 2, + ry: 2, + }, + name: { + text: name, + refY: 0.5, + refX: 0.5, + textAnchor: 'middle', + fontSize: 12 + }, + } +} + +const register = () => { + try { + Graph.registerNode( + 'actor', + { + inherit: 'rect', + width: 80, + height: 40, + cursor: 'grab', //TODO + + data: { + description: '', + }, + + markup: [ + { + tagName: 'rect', + selector: 'body' + }, + { + tagName: 'text', + selector: 'name', + }, + ], + // propHooks(meta) { + // const { name, attributes, ...others } = meta + + // if (!(name && attributes)) { + // return meta + // } + + // const rects = [ + // { type: 'name', text: name }, + // { type: 'attrs', text: attributes }, + // ] + + // let offsetY = 0 + // rects.forEach((rect) => { + // const height = rect.text.length * 12 + 16 + // ObjectExt.setByPath( + // others, + // `attrs/${rect.type}-text/text`, + // rect.text.join('\n'), + // ) + // ObjectExt.setByPath(others, `attrs/${rect.type}-rect/height`, height) + // ObjectExt.setByPath( + // others, + // `attrs/${rect.type}-rect/transform`, + // 'translate(0,' + offsetY + ')', + // ) + // offsetY += height + // }) + + // others.size = { width: 160, height: offsetY } + + // return others + // }, + }, + true, + ) + // Graph.registerNode( + // 'actor', + // { + // inherit: 'rect', + // width: 80, + // height: 40, + // cursor: 'grab', //TODO + // label: 'Actor', + // attrs: { + // body: { + // strokeWidth: 1, + // stroke: 'black', + // fill: 'white', + // rx: 2, + // ry: 2, + // }, + // text: { + // fontSize: 12, + // fill: 'black', + // }, + // }, + // data: { + // description: '', + // }, + // }, + // true, + // ) + } catch (error) { + console.log(error) + } +} + +const create = (graph: Graph) => { + const node = graph.createNode({ + shape: 'actor', + }) + const attrs = setActorAttrs('Actor') + node.setAttrs(attrs) + + return node; +} + +export default { + register, + create, + setActorAttrs +}; \ No newline at end of file diff --git a/src/renderer/applets/model-editor/shapes/dataflow.tsx b/src/renderer/applets/model-editor/shapes/dataflow.tsx new file mode 100644 index 0000000..8edcd59 --- /dev/null +++ b/src/renderer/applets/model-editor/shapes/dataflow.tsx @@ -0,0 +1,203 @@ +import { Graph, Node } from "@antv/x6"; + +// shape for stencil view +const registerEdgeStencil = () => { + Graph.registerNode( + 'dataflow-stencil', + { + inherit: 'path', + width: 80, + height: 40, + zIndex: 3, + markup: [ + { + tagName: 'path', + selector: 'boundary' + }, + { + tagName: 'text', + selector: 'label' + }, + ], + attrs: { + boundary: { + strokeWidth: 1.0, + stroke: 'black', + fill: 'transparent', + refD: 'M 30 20 C 80 20 65 100 110 100' + }, + label: { + text: 'Data flow', + fill: 'black', + textVerticalAnchor: 'middle' + }, + line: { + targetMarker: 'block', + sourceMarker: '' + } + }, + }, + true, + ) +} + +const createEdgeStencil = (graph: Graph) => { + return graph.createNode({ + shape: 'dataflow-stencil', + }) +} + +const registerEdge = () => { + try { + Graph.registerEdge( + 'dataflow-edge', + { + inherit: 'edge', + attrs: { + line: { + stroke: 'black', + strokeWidth: 0.8 + }, + }, + }, + true, + ) + } catch (error){ + console.log(error) + } +} + +const setDataflowLabel = (label: string, protocol: string, stride: string) => { + return { + markup: [ + { + tagName: "rect", + selector: "body" + }, + { + tagName: "text", + selector: "label" + }, + { + tagName: "rect", + selector: "protocolBody" + }, + { + tagName: "text", + selector: "protocol" + }, + { + tagName: "rect", + selector: "strideBody" + }, + { + tagName: "text", + selector: "stride" + } + ], + attrs: { + label: { + text: label, + fill: "#000", + fontSize: 12, + textAnchor: "middle", + textVerticalAnchor: "middle", + // pointerEvents: "none" + }, + body: { + ref: "label", + fill: "#fff", + // stroke: '#5755a1', + // strokeWidth: 2, + rx: 4, + ry: 4, + refWidth: '140%', + refHeight: '140%', + refX: '-20%', + refY: '-20%', + }, + protocol: { + ref: "label", + text: protocol, + fill: "white", + fontSize: 10, + textAnchor: "middle", + textVerticalAnchor: "middle", + pointerEvents: "none", + // refX: 16.5, + refY: -7 + }, + protocolBody: { + ref: "protocol", + fill: "black", + stroke: 'white', + strokeWidth: 2, + rx: 4, + ry: 4, + refWidth: '140%', + refHeight: '140%', + refX: '-20%', + refY: '-20%', + }, + stride: { + ref: "label", + text: stride, + fill: "#ff0000", + fontSize: 8, + textAnchor: "middle", + textVerticalAnchor: "middle", + pointerEvents: "none", + // refX: 16.5, + refY: 20 + }, + strideBody: { + ref: "stride", + fill: "#fff", + rx: 4, + ry: 4, + refWidth: '140%', + refHeight: '140%', + refX: '-20%', + refY: '-20%', + } + } + } +} + +// the actual edge after being dragged to canvas +const createEdge = (graph: Graph, node: Node) => { + const position = node.getPosition(); + const source = position; + const target = { + x: position.x + 100, + y: position.y + 50, + }; + + // Calculate the midpoint for the default vertex + const midpoint = { + x: (source.x + target.x) / 2, + y: (source.y + target.y) / 2, + }; + + const edge = graph.addEdge({ + shape: "dataflow-edge", + source: source, + target: target, + vertices: [midpoint] + }); + + const label = setDataflowLabel('Data flow', '', '') + edge.appendLabel(label) +}; + +const register = () => { + registerEdgeStencil() + registerEdge() +} + +export default { + register, + createEdgeStencil, + createEdge, + setDataflowLabel +}; \ No newline at end of file diff --git a/src/renderer/applets/model-editor/shapes/system.tsx b/src/renderer/applets/model-editor/shapes/system.tsx new file mode 100644 index 0000000..e174ef5 --- /dev/null +++ b/src/renderer/applets/model-editor/shapes/system.tsx @@ -0,0 +1,124 @@ +import { Graph } from "@antv/x6"; + +const setSystemAttrs = (name: string, stack: string) => { + return { + body: { + strokeWidth: 1, + }, + name: { + text: name, + refY: 0.5, + refX: 0.5, + textAnchor: 'middle', + fontSize: 12 + }, + stackBody: { + ref: "stack", + fill: "black", + stroke: 'white', + strokeWidth: 2, + rx: 4, + ry: 4, + refWidth: '140%', + refHeight: '140%', + refX: '-20%', + refY: '-20%', + }, + stack: { + ref: "name", + text: stack, + fill: "white", + fontSize: 10, + textAnchor: "middle", + textVerticalAnchor: "middle", + pointerEvents: "none", + refY: -7 + }, + } +} + +const register = () => { + try { + Graph.registerNode( + 'system', + { + inherit: 'circle', + width: 80, + height: 80, + data: { + description: '', + }, + markup: [ + { + tagName: 'circle', + selector: 'body' + }, + { + tagName: 'text', + selector: 'name', + }, + { + tagName: 'rect', + selector: 'stackBody' + }, + { + tagName: 'text', + selector: 'stack', + }, + ], + // propHooks(meta) { + // const { name, attributes, ...others } = meta + + // if (!(name && attributes)) { + // return meta + // } + + // const rects = [ + // { type: 'name', text: name }, + // { type: 'attrs', text: attributes }, + // ] + + // let offsetY = 0 + // rects.forEach((rect) => { + // const height = rect.text.length * 12 + 16 + // ObjectExt.setByPath( + // others, + // `attrs/${rect.type}-text/text`, + // rect.text.join('\n'), + // ) + // ObjectExt.setByPath(others, `attrs/${rect.type}-rect/height`, height) + // ObjectExt.setByPath( + // others, + // `attrs/${rect.type}-rect/transform`, + // 'translate(0,' + offsetY + ')', + // ) + // offsetY += height + // }) + + // others.size = { width: 160, height: offsetY } + + // return others + // }, + }, + true, + ) + } catch (error) { + console.log(error) + } +} + +const create = (graph: Graph) => { + const node = graph.createNode({ + shape: 'system', + }) + const attrs = setSystemAttrs('System', '') + node.setAttrs(attrs) + + return node; +} + +export default { + register, + create, + setSystemAttrs +}; \ No newline at end of file diff --git a/src/renderer/applets/model-editor/shapes/zone.tsx b/src/renderer/applets/model-editor/shapes/zone.tsx new file mode 100644 index 0000000..9da4f2c --- /dev/null +++ b/src/renderer/applets/model-editor/shapes/zone.tsx @@ -0,0 +1,84 @@ +import { Graph } from "@antv/x6"; + +const setZoneAttrs = (name: string, trustLevel: string) => { + return { + body: { + strokeWidth: 1, + stroke: 'black', + fill: 'rgba(255,255,255,0.0)', + strokeDasharray: '4', + }, + name: { + text: name, + refX: 0.5, + refY: 20, + textAnchor: 'middle', + textVerticalAnchor: 'bottom', + textSize: 12, + }, + trustLevel: { + ref: "name", + text: trustLevel, + fill: "black", + fontSize: 10, + textAnchor: "middle", + textVerticalAnchor: "middle", + pointerEvents: "none", + refY: 20 + }, + } +} + +const register = () => { + try { + Graph.registerNode( + 'zone', + { + inherit: 'rect', + resizing: true, + width: 80, + height: 40, + cursor: 'grab', //TODO + + data:{ + parent: true, + description: '' + }, + + markup: [ + { + tagName: 'rect', + selector: 'body' + }, + { + tagName: 'text', + selector: 'name', + }, + { + tagName: 'text', + selector: 'trustLevel', + }, + ], + }, + true, + ) + } catch(error) { + console.log(error) + } +} + +const create = (graph: Graph) => { + const node = graph.createNode({ + shape: 'zone', + }) + const attrs = setZoneAttrs('Zone', '') + node.setAttrs(attrs) + + return node; +} + +export default { + register, + create, + setZoneAttrs +}; \ No newline at end of file diff --git a/src/renderer/applets/model-editor/tools.tsx b/src/renderer/applets/model-editor/tools.tsx new file mode 100644 index 0000000..13d46ac --- /dev/null +++ b/src/renderer/applets/model-editor/tools.tsx @@ -0,0 +1,75 @@ +import { Graph, Registry } from "@antv/x6"; + +const registerEdgeSourceHandle = () => { + if (!Registry.EdgeTool.registry.data['edge-source-handle']) { + Graph.registerEdgeTool('edge-source-handle', { + inherit: 'source-arrowhead', + tagName: 'circle', + attrs: { + r: 5, + fill: 'black', + cursor: 'move', + } + }) + } +} + +const registerEdgeTargetHandle = () => { + if (!Registry.EdgeTool.registry.data['edge-target-handle']) { + Graph.registerEdgeTool('edge-target-handle', { + inherit: 'target-arrowhead', + tagName: 'circle', + attrs: { + r: 5, + fill: 'black', + cursor: 'move', + }, + }) + } +} + +const registerEdgeVertices = () => { + if (!Registry.EdgeTool.registry.data['edge-vertices']) { + Graph.registerEdgeTool('edge-vertices', { + inherit: 'vertices', + stopPropagation: false, + attrs: { + r: 5, + fill: 'black', + }, + }) + } +} + +const register = () => { + registerEdgeVertices() + registerEdgeSourceHandle() + registerEdgeTargetHandle() +}; + +// const toggleTextMode = (cells: Cell[], isTextMode: boolean) => { +// cells.forEach((cell: Cell) => { +// cell.removeTools() +// if (cell.isEdge()) { +// // if in text mode, show labels and remove vertices +// if (isTextMode) { +// cell.addTools([ +// { name: 'edge-editor-active'}, +// ]) + +// // if in edit mode, show vertices and remove labels +// } else { +// cell.addTools([ +// { name: 'edge-vertices'}, +// { name: 'edge-source-handle' }, +// { name: 'edge-target-handle' }, +// ]) +// } +// } +// }); +// } + +export default { + register, + // toggleTextMode +}; \ No newline at end of file diff --git a/src/renderer/components/Breadcrumbs.tsx b/src/renderer/components/Breadcrumbs.tsx new file mode 100644 index 0000000..d01d5e8 --- /dev/null +++ b/src/renderer/components/Breadcrumbs.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import { Breadcrumb } from 'semantic-ui-react'; + +const Breadcrumbs: React.FC = () => ( + + Projects + +); + +export default Breadcrumbs; diff --git a/src/renderer/components/Footer.tsx b/src/renderer/components/Footer.tsx new file mode 100644 index 0000000..9c84076 --- /dev/null +++ b/src/renderer/components/Footer.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { + Container, + Divider, + Grid, + Header, + Icon, + List, + Segment, +} from 'semantic-ui-react'; + +const textStyle = { + color: '#d3d3d3' +}; // Common text style + +const flexStyle = { + display: 'flex', + alignItems: 'center', + justifyContent: 'center' +} + +const Footer: React.FC = () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + nexTM v0.1.0 + + + © 2024. Daniel Krohmer + + + AGPL v3.0 + + + + +); + +export default Footer; diff --git a/src/renderer/components/SideBar.tsx b/src/renderer/components/SideBar.tsx new file mode 100644 index 0000000..adef85c --- /dev/null +++ b/src/renderer/components/SideBar.tsx @@ -0,0 +1,365 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { + Accordion, + Button, + Form, + Header, + Icon, + Input, + Popup, + Segment, + Sidebar, + Radio, + Checkbox, + Container +} from 'semantic-ui-react'; +import { useSelector, useDispatch } from 'react-redux'; +import { RootState, AppDispatch } from '../store'; +import { + showToast, + hideToast, + setSidebarVisible, + setGridVisible, + setDatabasePath, + setExplicitObjectSelection +} from '../store/SettingsStore'; // Adjust the import path as necessary +import { useNavigate } from 'react-router-dom'; + +const SideBar: React.FC = () => { + const { + sidebarVisible, + gridVisible, + explicitObjectSelection, + path + } = useSelector((state: RootState) => state.settings); + const dispatch = useDispatch(); + const navigate = useNavigate(); + + const [activeIndex, setActiveIndex] = useState(-1); + const [useDefaultDatabase, setUseDefaultDatabase] = useState(true); + const [selectedPath, setSelectedPath] = useState('default'); + const [inputPath, setInputPath] = useState('default'); + const [buttonLabel, setButtonLabel] = useState('Open'); + + const sidebarRef = useRef(null); + + useEffect(() => { + window.electron.getDefaultDbPath().then((defaultPath: string) => { + if (path === defaultPath) { + setUseDefaultDatabase(true); + setInputPath(defaultPath); + } else { + setUseDefaultDatabase(false); + setInputPath(path); + } + }); + }, [path]); + + const handleAccordionClick = (index: number) => { + setActiveIndex(activeIndex === index ? -1 : index); + }; + + const handleDatabaseTypeChange = async (_: React.FormEvent, { value }: any) => { + const isDefault = value === 'default'; + setUseDefaultDatabase(isDefault); + setButtonLabel('Open'); // Reset button label + + if (isDefault) { + const defaultPath = await window.electron.getDefaultDbPath(); + setInputPath(defaultPath); + } else { + setInputPath(''); + } + }; + + const handleOpenFilePicker = async () => { + try { + const filePath = await window.electron.openFilePicker(); + setInputPath(filePath); + setButtonLabel('Open'); + } catch (err) { + console.error('Error selecting file:', err); + } + }; + + const handleOpenDirectoryPicker = async () => { + try { + const directoryPath = await window.electron.openDirectoryPicker(); + setInputPath(directoryPath); + setButtonLabel('Create'); + } catch (err) { + console.error('Error selecting directory:', err); + } + }; + + const handlePathChange = (e: React.ChangeEvent) => { + setInputPath(e.target.value); + }; + + const handleFormSubmit = async () => { + try { + if (!inputPath) { + throw new Error('Please enter a valid path.'); + } + + let currentPath; + const promise = new Promise(async (resolve, reject) => { + let result; + try { + if (buttonLabel === 'Create') { + result = await window.electron.createDatabase(inputPath); + } else if (buttonLabel === 'Open') { + result = await window.electron.openDatabase(inputPath); + } + + if (result.success) { + window.electron.getCurrentDbPath().then((currentPath: string) => { + dispatch(setDatabasePath(currentPath)); + dispatch( + showToast({ + promise: Promise.resolve(), // Resolve immediately since there's no async operation + loadingMessage: '', // No loading message needed + successMessage: `Current database: ${currentPath}`, // Success message with grid type + errorMessage: '', // No error message needed + }) + ) + navigate('/'); + resolve(`Database set successfully:`) + }); + + } else { + reject('Operation failed on backend.'); + } + } catch (error) { + reject('Error processing form submission.'); + } + }); + } catch (error) { + console.error('Error processing form submission:', error); + } + }; + + const handleClickOutside = (event: MouseEvent) => { + if (sidebarRef.current && !sidebarRef.current.contains(event.target as Node)) { + dispatch(setSidebarVisible(false)); + } + }; + + const handleGridChange = (_: React.FormEvent, { value }: any) => { + window.electron.setGridType(value) + dispatch(setGridVisible(value)); + // Show toast notification for success + dispatch( + showToast({ + promise: Promise.resolve(), // Resolve immediately since there's no async operation + loadingMessage: '', // No loading message needed + successMessage: `Grid type changed to: ${value}`, // Success message with grid type + errorMessage: '', // No error message needed + }) + ); + }; + + const handleExplicitObjectSelectionChange = () => { + window.electron.setExplicitObjectSelection(!explicitObjectSelection) + dispatch(setExplicitObjectSelection(!explicitObjectSelection)) + dispatch( + showToast({ + promise: Promise.resolve(), // Resolve immediately since there's no async operation + loadingMessage: '', // No loading message needed + successMessage: `Explicit object selection ${!explicitObjectSelection ? 'active' : 'inactive'}`, // Success message with grid type + errorMessage: '', // No error message needed + }) + ); + } + + useEffect(() => { + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, []); + + const isSetDatabaseDisabled = !inputPath || inputPath === path; + + return ( + <> + +
+ Settings +
+ + + handleAccordionClick(0)} + > +

+ + General settings +

+
+ + +
+
+

+ +

+ } + content={`By default, the database is stored in the app's respective user data folder depending on your operating system. However, you may also specify a custom database directory of your choice.`} + /> +
+ + + + + + + { !useDefaultDatabase && + <> + + + + + + + } + content={`${inputPath || path}`} + /> + + + + } + +
+
+
+
+ + + handleAccordionClick(1)} + > +

+ + Model Editor Settings +

+
+ + +
+
+

+ +

+ } + content='Choose the type of grid for the model editor.' + /> +
+ + + + + + + + + +
+ + {/* + Require selection before context menu + */} +
+
+

+ +

+ } + content='If explicit object selection is active, you cannot context-click an object unless it has previously been selected with a left mouse click.' + /> +
+ + + +
+
+
+
+
+
+ + ); +}; + +export default SideBar; diff --git a/src/renderer/components/ToastManager.tsx b/src/renderer/components/ToastManager.tsx new file mode 100644 index 0000000..616b64d --- /dev/null +++ b/src/renderer/components/ToastManager.tsx @@ -0,0 +1,45 @@ +import React, { useEffect } from 'react'; +import toast, { Toaster } from 'react-hot-toast'; +import { useSelector, useDispatch } from 'react-redux'; +import { RootState, AppDispatch } from '../store'; +import { hideToast } from '../store/SettingsStore'; // Adjust the import path as necessary + +export const ToastManager: React.FC = () => { + const dispatch = useDispatch(); + const { + toastVisible, + toastPromise, + toastLoadingMessage, + toastSuccessMessage, + toastErrorMessage + } = useSelector((state: RootState) => state.settings); + + useEffect(() => { + if (toastVisible && toastPromise) { + // Dismiss any existing toasts before showing a new one + toast.dismiss(); + + toast.promise( + toastPromise, + { + loading: toastLoadingMessage, + success: toastSuccessMessage, + error: toastErrorMessage, + }, + { + style: { + background: '#1b1c1d', // Background color for inverted theme + color: '#ffffff', // Text color for inverted theme + boxShadow: '0 1px 3px rgba(0, 0, 0, 0.2)', // Shadow similar to Semantic UI + borderRadius: '0.28571429rem', // Border radius similar to Semantic UI + border: '0.5px white solid' + }, + } + ).finally(() => { + dispatch(hideToast()); + }); + } + }, [toastVisible, toastPromise, toastLoadingMessage, toastSuccessMessage, toastErrorMessage, dispatch]); + + return ; +}; diff --git a/src/renderer/components/TopBar.tsx b/src/renderer/components/TopBar.tsx new file mode 100644 index 0000000..5473139 --- /dev/null +++ b/src/renderer/components/TopBar.tsx @@ -0,0 +1,47 @@ +// src/renderer/components/TopBar.tsx +import React from 'react'; +import { Icon, Menu } from 'semantic-ui-react'; +import { useDispatch, useSelector } from 'react-redux'; +import { RootState, AppDispatch } from '../store'; +import { setSidebarVisible } from '../store/SettingsStore'; + +import logo from '/assets/logo.svg' +import { Navigate, useNavigate } from 'react-router-dom'; + +const TopBar: React.FC = () => { + const dispatch = useDispatch(); + const navigate = useNavigate() + + // global redux states + const { sidebarVisible } = useSelector((state: RootState) => state.settings); + + const toggleSidebar = () => { + dispatch(setSidebarVisible(!sidebarVisible)); + }; + + return ( + <> + + + Logo + + + {/* + + */} + + + + + + + {/* setSidebarVisible(false)} /> */} + + ); +}; + +export default TopBar; diff --git a/src/renderer/components/increments/Increment.tsx b/src/renderer/components/increments/Increment.tsx new file mode 100644 index 0000000..28667f8 --- /dev/null +++ b/src/renderer/components/increments/Increment.tsx @@ -0,0 +1,143 @@ +import React, { useState } from 'react'; +import { + Accordion, + Button, + Icon, + Popup +} from 'semantic-ui-react'; +import Models from '../models/Models' +import type { IIncrement } from '../../interfaces/IIncrement'; +import type { IProduct } from '../../interfaces/IProduct'; + +import { useDispatch } from 'react-redux'; +import { AppDispatch } from '../../store'; + +import { + setIncrementsModalOpen, + setCurrentIncrement, + setIncrementToDelete, + setIncrementsConfirmOpen, + setIncrementsIsCloning, + setIncrementsIsEditing, +} from '../../store/IncrementsStore'; + +interface IncrementProps { + increment: IIncrement; + product: IProduct; + index: number; + number: number; + isActive: boolean; + handleAccordionClick: (e: React.MouseEvent, titleProps: any) => void; +} + +const Increment: React.FC = ({ + increment, + product, + index, + number, + isActive, + handleAccordionClick +}) => { + + const dispatch = useDispatch(); + + + const [showThreatModels, ] = useState(true); // State to manage whether to show ThreatModel component + const [isHovering, setIsHovering] = useState(false); + + const handleMouseEnter = () => { + setIsHovering(true); + }; + + const handleMouseLeave = () => { + setIsHovering(false); + }; + + const handleEdit = (e: React.MouseEvent) => { + e.stopPropagation() + dispatch(setIncrementsIsEditing(true)); + dispatch(setCurrentIncrement(increment)); + dispatch(setIncrementsModalOpen(true)); + }; + + const handleClone = (e: React.MouseEvent) => { + e.stopPropagation() + + + dispatch(setIncrementsIsCloning(true)) + dispatch(setCurrentIncrement({...increment, name: `${increment.name} (Copy)`})); // Set the increment to clone + dispatch(setIncrementsModalOpen(true)); // Open the modal + }; + + const handleDelete = (incrementId: string) => { + dispatch(setIncrementToDelete(incrementId)); + dispatch(setIncrementsConfirmOpen(true)); + }; + + return ( + +
+ handleAccordionClick(e, { index })} + > +
+
+ + Increment #{number}: {increment.name} +
+ {/* {isHovering && ( */} +
+ + + + } + content={`Edit increment "#${number}: ${increment.name}"`} + /> + + + + + } + content={`Clone increment "#${number}: ${increment.name}"`} + /> + + { + e.stopPropagation(); + handleDelete(increment.id); + }}> + + + } + content={`Delete increment "#${number}: ${increment.name}"`} + /> +
+ {/* )} */} +
+
+ + {/* */} + {showThreatModels && + } + {/* */} + +
+ +
); +}; + +export default Increment; diff --git a/src/renderer/components/increments/Increments.tsx b/src/renderer/components/increments/Increments.tsx new file mode 100644 index 0000000..c53ebaf --- /dev/null +++ b/src/renderer/components/increments/Increments.tsx @@ -0,0 +1,191 @@ +import React, { useEffect } from 'react'; +import { useParams, useNavigate } from 'react-router-dom'; +import { useDispatch, useSelector } from 'react-redux'; +import { RootState, AppDispatch } from '../../store'; +import { + Accordion, + Button, + Confirm, + Dimmer, + Header, + Label, + Message, + Loader, + Segment +} from 'semantic-ui-react'; + +import Increment from './Increment'; +import IncrementsModal from './IncrementsModal'; + +import { + fetchIncrements, + setIncrementsActiveIndex, + setIncrementsModalOpen, + setIncrementsIsEditing, + setCurrentIncrement, + setIncrementsConfirmOpen, + deleteIncrement +} from '../../store/IncrementsStore'; +import { fetchProduct } from '../../store/ProductsStore'; + +const Increments: React.FC = () => { + const { productId, incrementId } = useParams<{ productId: string; incrementId?: string }>(); + const navigate = useNavigate(); + const dispatch = useDispatch(); + + const { + increments, + incrementsActiveIndex, + incrementsError, + incrementsIsLoading, + incrementsIsLoaded, + incrementsConfirmOpen, + incrementToDelete + } = useSelector((state: RootState) => state.increments); + + const { + product + } = useSelector((state: RootState) => state.products) + + //todo: direct access to increment via products/:id/increments/:id does not work yet + useEffect(() => { + if (productId) { + dispatch(setIncrementsActiveIndex(-1)); + dispatch(fetchProduct({ productId, isEagerLoading: false })); + dispatch(fetchIncrements({ productId })) + } + }, [productId, dispatch]); + + useEffect(() => { + if (incrementsIsLoaded && increments.length > 0) { + if (incrementId) { + const index = increments.findIndex(inc => inc.id === incrementId); + if (index !== -1) { + dispatch(setIncrementsActiveIndex(index)); + // navigate(`/products/${productId}/increments/${increments[index].id}`); + } + // } else { + // dispatch(setIncrementsActiveIndex(0)); + // } + } else { + dispatch(setIncrementsActiveIndex(-1)); + + // navigate(`/products/${productId}`); + } + } + + }, [incrementsIsLoaded, incrementId, increments, dispatch]); + + const handleAccordionClick = (index: number) => { + const increment = increments[index]; + + if (index === incrementsActiveIndex) { + dispatch(setIncrementsActiveIndex(-1)); + navigate(`/products/${productId}`); + } else { + navigate(`/products/${productId}/increments/${increment.id}`); + dispatch(setIncrementsActiveIndex(index)); + } + }; + + const openAddModal = () => { + dispatch(setIncrementsIsEditing(false)); + dispatch(setIncrementsModalOpen(true)); + dispatch(setCurrentIncrement({ + id: '', + name: '', + start: '', + end: '', + deadline: '', + state: '', + productId: '', + models: [] + })); + }; + + const confirmDelete = () => { + if (incrementToDelete) { + dispatch(deleteIncrement(incrementToDelete)); + navigate(`/products/${productId}/`); + dispatch(setIncrementsActiveIndex(-1)); + } + }; + + return ( +
+
+
+
+
Product Increments
+
+ +
+ + + + {/* Loader */} + + Loading Increments... + + + {/* Error handling */} + {incrementsError && ( + + + Error❗️ + +

+ {incrementsError} +

+
+ )} + + {/* Normal behavior */} + {!incrementsError && !incrementsIsLoading && increments && product && ( + // + + {increments.length > 0 ? ( + increments.map((increment, index) => ( + handleAccordionClick(index)} + /> + )) + ) : ( +
+

+ Increments, anyone? 👀 +

+
+ You are just one click away: +
+
+ )} +
+ //
+ + )} + +
+ + + + dispatch(setIncrementsConfirmOpen(false))} + onConfirm={confirmDelete} + content="Deleting an increment will permanently delete all models associated with it. Do you want to delete this increment?" + /> +
+
+ ); +} + +export default Increments; diff --git a/src/renderer/components/increments/IncrementsModal.tsx b/src/renderer/components/increments/IncrementsModal.tsx new file mode 100644 index 0000000..fb42bb6 --- /dev/null +++ b/src/renderer/components/increments/IncrementsModal.tsx @@ -0,0 +1,103 @@ +import React from 'react'; +import { useParams, useNavigate } from 'react-router-dom'; +import { RootState, AppDispatch } from '../../store'; + +import { useDispatch, useSelector } from 'react-redux'; +import { Modal, Form, InputOnChangeData } from 'semantic-ui-react'; +import { + setIncrementsModalOpen, + addOrUpdateIncrement, + setCurrentIncrement, + setIncrementsIsCloning, + setIncrementsIsEditing, + fetchIncrement +} from '../../store/IncrementsStore'; + +import { IIncrement } from '../../interfaces/IIncrement'; + +// const IncrementsModal: React.FC = ({ productId }) => { +const IncrementsModal: React.FC = () => { + + const { productId } = useParams<{ productId: string }>(); + + const dispatch = useDispatch(); + const navigate = useNavigate(); + + // global redux states + const { + incrementsModalOpen, + incrementsIsEditing, + incrementsIsCloning, + currentIncrement, + } = useSelector((state: RootState) => state.increments); + + // Updated to align with Semantic UI React's expected parameters for onChange + const handleInputChange = (_e: React.ChangeEvent, data: InputOnChangeData) => { + if (currentIncrement) { + dispatch(setCurrentIncrement({ ...currentIncrement, [data.name]: data.value })); + } + }; + + const handleSubmit = async () => { + if (currentIncrement && productId) { + let increment: IIncrement; + + if (incrementsIsCloning) { + const cloneResponse = await dispatch(fetchIncrement({ incrementId: currentIncrement.id, isEagerLoading: true })); + if (fetchIncrement.fulfilled.match(cloneResponse)) { + const eagerIncrement: IIncrement = cloneResponse.payload; + increment = { ...eagerIncrement, id: '', name: `${currentIncrement.name}` }; + } else { + // Handle the case where cloning fails + console.error("Cloning failed"); + return; + } + } else { + increment = currentIncrement; + } + + const response = await dispatch(addOrUpdateIncrement({ increment, productId })); + if (addOrUpdateIncrement.fulfilled.match(response)) { + const responseIncrement: IIncrement = response.payload; // This now should be IIncrement + navigate(`/products/${productId}/increments/${responseIncrement.id}`); + } + } + handleClose(); +}; + + const handleClose = () => { + dispatch(setIncrementsModalOpen(false)); + dispatch(setCurrentIncrement(null)); // Clear the increment to clone + dispatch(setIncrementsIsCloning(false)); // Clear the increment to clone + dispatch(setIncrementsIsEditing(false)); // Clear the increment to clone + }; + + const modalHeader = incrementsIsCloning ? 'Clone Increment' : incrementsIsEditing ? 'Edit Increment' : 'Add Increment'; + const submitButtonText = incrementsIsCloning ? 'Clone' : incrementsIsEditing ? 'Edit' : 'Add'; + + return ( + dispatch(setIncrementsModalOpen(false))} dimmer="blurring"> + {modalHeader} + +
+ + {/* Additional form inputs here */} + + {submitButtonText} + Cancel + + +
+
+ ); +}; + +export default IncrementsModal; diff --git a/src/renderer/components/models/Model.tsx b/src/renderer/components/models/Model.tsx new file mode 100644 index 0000000..e72a2a6 --- /dev/null +++ b/src/renderer/components/models/Model.tsx @@ -0,0 +1,198 @@ +// /src/renderer/components/models/Model.tsx +import React, { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { + Button, + Dimmer, + Icon, + Image, + List, + Loader, + Message, + Popup +} from 'semantic-ui-react'; + +import type { IModel } from '../../interfaces/IModel'; +import type { IIncrement } from '../../interfaces/IIncrement'; +import type { IProduct } from '../../interfaces/IProduct'; + +import { useDispatch, useSelector } from 'react-redux'; +import { AppDispatch, RootState } from '../../store'; + +import { + setModelsCurrentModel, + setModelsModalOpen, + setModelsConfirmOpen, + setModelToDelete, + setModelsIsEditing, + setModelsIsCloning, +} from '../../store/ModelsStore'; + +import thumbnail from '/assets/thumbnail.png' + +import { fetchLatestVersion } from '../../store/VersionsStore'; +import { version } from 'os'; + +interface ModelProps { + model: IModel; + increment: IIncrement; + product: IProduct; + number: number + // handleDelete: (id: string) => void; + // openEditModal: (model: IModel) => void; +} + +const Model: React.FC = ({ + model, + increment, + product, + // handleDelete, + // openEditModal, +}) => { + const dispatch = useDispatch(); + + // global redux states + // const { + // latestVersion, + // latestVersionError, + // latestVersionIsLoaded, + // latestVersionIsLoading + // } = useSelector((state: RootState) => state.versions); + + // local states + const [localVersion, setLocalVersion] = useState<{ thumbnail: string | null }>({ thumbnail: null }); + const [isVersionLoading, setIsVersionLoading] = useState(false); + const [versionError, setVersionError] = useState(null); + const [isHovering, setIsHovering] = useState(false); + + const navigate = useNavigate() + + const handleEdit = (e: React.MouseEvent, model: IModel) => { + e.stopPropagation() + dispatch(setModelsCurrentModel(model)); // Set current product for editing + dispatch(setModelsModalOpen(true)); + dispatch(setModelsIsEditing(true)) + }; + + const handleClone = (e: React.MouseEvent, model: IModel) => { + e.stopPropagation() + dispatch(setModelsIsCloning(true)) + dispatch(setModelsCurrentModel({...model, name: `${model.name} (Copy)`})); // Set the increment to clone + dispatch(setModelsModalOpen(true)); // Open the modal + }; + + const handleDelete = (e: React.MouseEvent, modelId: string) => { + e.stopPropagation(); + dispatch(setModelToDelete(modelId)); + dispatch(setModelsConfirmOpen(true)); + }; + + const handleMouseEnter = () => { + setIsHovering(true); + }; + + const handleMouseLeave = () => { + setIsHovering(false); + }; + + useEffect(() => { + const fetchVersion = async () => { + try { + setIsVersionLoading(true); + const version = await dispatch(fetchLatestVersion({ modelId: model.id })).unwrap(); + setLocalVersion({ thumbnail: version.thumbnail }); + setIsVersionLoading(false); + } catch (err) { + setVersionError('Failed to load version.'); + setIsVersionLoading(false); + } + }; + + fetchVersion(); + }, [model, dispatch]); + + return ( +
+ + Loading model... + + + {/* Error handling */} + {versionError && ( + + + Error❗️ + +

+ {versionError} +

+
+ )} + + {/* Normal behavior */} + {localVersion && !versionError && !isVersionLoading && product && ( + navigate(`/products/${product.id}/increments/${increment.id}/models/${model.id}`)} + > + + + navigate(`/products/${product.id}/increments/${increment.id}/models/${model.id}`)}> + {model.name} + + + Created at: {new Date(model.createdAt).toLocaleString()} + + + {isHovering && ( + + + { + handleEdit(e, model); + }}> + + + } + content={`Edit model "${model.name}"`} + /> + + { + handleClone(e, model); + }}> + + + } + content={`Clone model "${model.name}"`} + /> + + { + handleDelete(e, model.id); + }}> + + + } + content={`Delete model "${model.name}"`} + /> + + + + )} + + )} +
+ + ); +}; + +export default Model; \ No newline at end of file diff --git a/src/renderer/components/models/Models.tsx b/src/renderer/components/models/Models.tsx new file mode 100644 index 0000000..55d65c6 --- /dev/null +++ b/src/renderer/components/models/Models.tsx @@ -0,0 +1,147 @@ +import React, { useEffect } from 'react'; +import { useParams } from 'react-router-dom'; + +import { + Button, + Confirm, + Dimmer, + Label, + List, + Loader, + Message, + Segment +} from 'semantic-ui-react'; + +import { IModel } from '../../interfaces/IModel' +import { IProduct } from '../../interfaces/IProduct'; +import { IIncrement } from '../../interfaces/IIncrement'; + +import ModelsModal from './ModelsModal'; +import Model from './Model' + +import { useSelector, useDispatch } from 'react-redux'; +import { RootState, AppDispatch } from '../../store'; + +import { + fetchModels, + deleteModel, + setModelsCurrentModel, + setModelsModalOpen, + setModelsIsEditing, + setModelsConfirmOpen +} from '../../store/ModelsStore'; + +interface ThreatModelsProps { + product: IProduct, + increment: IIncrement, + number: number +} + +const ThreatModels: React.FC = ({ + product, + increment, + number +}) => { + const { incrementId } = useParams<{ incrementId: string }>(); + const dispatch = useDispatch(); + + // global redux states + const { + models, + modelsError, + modelsIsLoading, + modelsConfirmOpen, + modelToDelete + } = useSelector((state: RootState) => state.models); + + useEffect(() => { + if (incrementId) { + dispatch(fetchModels({ incrementId })); + } + }, [ + dispatch, + incrementId + ]); + + const openAddModal = () => { + dispatch(setModelsCurrentModel({ + id: '', + name: '', + createdAt: '', + incrementId: '', // Assuming you have this in your form state + })); + dispatch(setModelsModalOpen(true)); + dispatch(setModelsIsEditing(false)); + }; + + const confirmDelete = () => { + + if (modelToDelete) { + dispatch(deleteModel(modelToDelete)); + } + }; + + return ( +
+ + {/* Loader */} + + Loading models... + + + {/* Error handling */} + {modelsError && ( + + + Error❗️ + +

+ {modelsError} +

+
+ )} + + {/* No products available. */} + {!modelsError && !modelsIsLoading && models && models.length <= 0 && ( +
+

+ No threat models here yet 😔 +

+
+ Add one by clicking +
+
+ )} + + {/* Normal behavior */} + {!modelsError && !modelsIsLoading && models && models.length > 0 && ( + + {models.map((model: IModel) => ( + + ))} + + )} +
+ + + + + dispatch(setModelsConfirmOpen(false))} + onConfirm={confirmDelete} + content="Do you want to delete this model permanently?" + /> +
+ ); +}; + +export default ThreatModels; \ No newline at end of file diff --git a/src/renderer/components/models/ModelsModal.tsx b/src/renderer/components/models/ModelsModal.tsx new file mode 100644 index 0000000..2118d67 --- /dev/null +++ b/src/renderer/components/models/ModelsModal.tsx @@ -0,0 +1,131 @@ +import React from 'react'; +import { useParams } from 'react-router-dom'; +import { Modal, Form } from 'semantic-ui-react'; + +import { useSelector, useDispatch } from 'react-redux'; +import { RootState, AppDispatch } from '../../store'; + +import { IModel } from '../../interfaces/IModel'; +import { + fetchModel, + fetchModels, + addOrUpdateModel, + setModelsModalOpen, + setModelsIsEditing, + setModelsIsCloning, + setModelsCurrentModel, +} from '../../store/ModelsStore'; + + +const ModelsModal: React.FC = () => { + const { incrementId } = useParams<{ incrementId: string }>(); + + const dispatch = useDispatch(); + + // global redux states + const { + modelsIsEditing, + modelsModalOpen, + modelsCurrentModel, + modelsIsCloning + } = useSelector((state: RootState) => state.models); + + // const [newModel, setNewModel] = useState({ + // id: '', + // name: '', + // createdAt: '', + // incrementId: '', + // }); + + // useEffect(() => { + // if (incrementId && modelsModalOpen) { + // if (modelsIsEditing && modelsCurrentModel) { + // // Populate the form fields with currentModel data + // setNewModel(modelsCurrentModel); + // } else { + // setNewModel({ + // id: '', + // name: '', + // createdAt: '', + // incrementId: '', // Assuming you have this in your form state + // }); + // } + // } + // }, [modelsModalOpen, modelsIsEditing, modelsCurrentModel]); + + // const handleSubmit = async () => { + // if (incrementId) { + // await dispatch(addOrUpdateModel({ model: newModel, incrementId })); + // dispatch(fetchModels({ incrementId })); + // dispatch(setModelsModalOpen(false)); + // } + // }; + + const handleSubmit = async () => { + if (modelsCurrentModel && incrementId) { + let model: IModel; + + if (modelsIsCloning) { + const cloneResponse = await dispatch(fetchModel({ modelId: modelsCurrentModel.id, isEagerLoading: true })); + if (fetchModel.fulfilled.match(cloneResponse)) { + const eagerModel: IModel = cloneResponse.payload; + model = { ...eagerModel, id: '', name: `${modelsCurrentModel.name}` }; + } else { + // Handle the case where cloning fails + console.error("Cloning failed"); + return; + } + } else { + model = modelsCurrentModel; + } + await dispatch(addOrUpdateModel({ model, incrementId })); + dispatch(fetchModels({ incrementId })); + } + handleClose(); +}; + + const handleClose = () => { + dispatch(setModelsModalOpen(false)); + dispatch(setModelsCurrentModel(null)); // Clear the increment to clone + dispatch(setModelsIsEditing(false)) + dispatch(setModelsIsCloning(false)) + + }; + + const handleInputChange = (e: React.ChangeEvent, key: string) => { + if (modelsCurrentModel) { + dispatch(setModelsCurrentModel({ ...modelsCurrentModel, [key]: e.target.value })); + } + }; + + const modalHeader = modelsIsCloning ? 'Clone Model' : modelsIsEditing ? 'Edit Model' : 'Add Model'; + const submitButtonText = modelsIsCloning ? 'Clone' : modelsIsEditing ? 'Edit' : 'Add'; + + return ( + + + {modalHeader} + + +
+ handleInputChange(e, 'name')} + /> + {/* Add additional inputs for start, end, deadline, and state */} + + {submitButtonText} + Cancel + + +
+
+ ); +}; + +export default ModelsModal; \ No newline at end of file diff --git a/src/renderer/components/products/Product.tsx b/src/renderer/components/products/Product.tsx new file mode 100644 index 0000000..f1ba445 --- /dev/null +++ b/src/renderer/components/products/Product.tsx @@ -0,0 +1,123 @@ +import React, { useEffect } from 'react'; +import { useParams, useNavigate } from 'react-router-dom'; +import { Breadcrumb, Container, Dimmer, Grid, Icon, Label, Loader, Message, Segment } from 'semantic-ui-react'; +import { useSelector, useDispatch } from 'react-redux'; + +import { RootState, AppDispatch } from '../../store'; +import { fetchProduct } from '../../store/ProductsStore'; // Import the fetchProduct thunk + +import Increments from '../increments/Increments'; + +const Product: React.FC = () => { + const { productId } = useParams(); + const navigate = useNavigate(); + const dispatch = useDispatch(); + + // global redux states + const { + product, + productIsLoading, + productError + } = useSelector((state: RootState) => state.products); + + useEffect(() => { + if (productId) { + dispatch(fetchProduct({ productId, isEagerLoading: false })); + } + }, [productId, dispatch]); + + return ( + + + navigate(`/products`)}> + Products + + + {product ? product.name : 'Loading...'} + + + + + + Loading Product... + + + {/* Error handling */} + {productError && ( + + + Error❗️ + +

+ {productError} +

+
+ )} + + {/* Normal behavior */} + {!productError && !productIsLoading && product && ( + <> + + + + Description: + + + {product.description || 'n/a'} + + + + + Responsible(s): + + + {product.responsibles && product.responsibles.length > 0 + ? product.responsibles.map((resp, _index) => ( + + )) + : 'n/a' + } + + + + + Starts At: + + + {product.startsAt ? new Date(product.startsAt).toLocaleDateString() : 'n/a'} + + + + + Ends At: + + + {product.endsAt ? new Date(product.endsAt).toLocaleDateString() : 'n/a'} + + + + + Created At: + + + {product.createdAt ? new Date(product.createdAt).toLocaleString() : 'n/a'} + + + + + )} +
+
+ + {/* Load increments */} + {/* {product && } */} + + +
+ ); +}; + +export default Product; diff --git a/src/renderer/components/products/Products.tsx b/src/renderer/components/products/Products.tsx new file mode 100644 index 0000000..d4e8b5c --- /dev/null +++ b/src/renderer/components/products/Products.tsx @@ -0,0 +1,428 @@ +import React, { useState, useEffect } from 'react'; +import { + Button, + Container, + Breadcrumb, + Confirm, + Dimmer, + Dropdown, + DropdownProps, + Icon, + Loader, + Message, + Pagination, + PaginationProps, + Popup, + Segment, + Table, + Label +} from 'semantic-ui-react'; + +import { useNavigate } from 'react-router-dom'; // For React Router v6 + +import type { IProduct } from '../../interfaces/IProduct'; +import type { IResponsible } from '../../interfaces/IResponsible'; +import ProductsModal from './ProductsModal'; + +import { useSelector, useDispatch } from 'react-redux'; +import { RootState, AppDispatch } from '../../store'; +import { + fetchProducts, + deleteProduct, + setProductsIsCloning, + setProductsModalOpen, + setProductsCurrentProduct, + setProductsCurrentPage, + resetProductsCurrentPage, + setProductsItemsPerPage, + setProductsSortby, + toggleProductsSort, + setProductsIsEditing +} from '../../store/ProductsStore'; + +const itemsPerPageOptions = [ + { key: '5', text: '5 items', value: 5 }, + { key: '10', text: '10 items', value: 10 }, + { key: '25', text: '25 items', value: 25 }, + { key: '50', text: '50 items', value: 50 }, + { key: '100', text: '100 items', value: 100 } +]; + +const sortFields = [ + { key: 'createdAt', text: 'Created at', value: 'createdAt' }, + { key: 'name', text: 'Name', value: 'name' }, + { key: 'startsAt', text: 'Product start', value: 'startsAt' }, + { key: 'endsAt', text: 'Product end', value: 'endsAt' } +]; + +const validSortFields: string[] = sortFields.map(field => field.value); + +const Products: React.FC = () => { + const navigate = useNavigate(); + const dispatch = useDispatch(); + + const { + productsCurrentPage, + products, + productsError, + productsIsLoading, + productsCount, + productsSort, + productsSortby, + productsItemsPerPage + } = useSelector((state: RootState) => state.products); + + const [openConfirm, setOpenConfirm] = useState(false); + const [productToDelete, setProductToDelete] = useState(null); + const [hoveredProductId, setHoveredProductId] = useState(null); + + const openAddModal = () => { + dispatch(setProductsCurrentProduct({ + id: '', + name: '', + startsAt: '', + endsAt: '', + createdAt: '' + })); + dispatch(setProductsModalOpen(true)); + dispatch(setProductsIsEditing(false)); + }; + + const openEditModal = (product: IProduct) => { + dispatch(setProductsCurrentProduct(product)); + dispatch(setProductsModalOpen(true)); + dispatch(setProductsIsEditing(true)); + }; + + const handleDelete = (productId: string) => { + setProductToDelete(productId); + setOpenConfirm(true); + }; + + const handleClone = (e: React.MouseEvent, product: IProduct) => { + e.stopPropagation(); + dispatch(setProductsIsCloning(true)); + dispatch(setProductsCurrentProduct({...product, name: `${product.name} (Copy)`})); + dispatch(setProductsModalOpen(true)); + }; + + const handleConfirmDelete = () => { + if (productToDelete) { + let offset = ((productsCurrentPage as number) - 1) * productsItemsPerPage; + if (products.length === 1 && offset !== 0) { + offset = offset - productsItemsPerPage; + dispatch(setProductsCurrentPage(productsCurrentPage - 1)); + } + + dispatch(deleteProduct({ + productId: productToDelete, + limit: productsItemsPerPage, + offset: offset, + sort: productsSort, + sortby: productsSortby + })); + setProductToDelete(null); + } + setOpenConfirm(false); + }; + + const handleCancelDelete = () => { + setOpenConfirm(false); + }; + + const handlePaginationChange = (_e: React.MouseEvent, { activePage }: PaginationProps) => { + dispatch(setProductsCurrentPage(activePage as number)); + const offset = ((activePage as number) - 1) * productsItemsPerPage; + dispatch(fetchProducts({ + limit: productsItemsPerPage, + offset: offset, + sort: productsSort, + sortby: productsSortby + })); + }; + + const handleItemsPerPageChange = (_event: React.SyntheticEvent, data: DropdownProps) => { + dispatch(setProductsItemsPerPage(data.value as number)); + dispatch(resetProductsCurrentPage()); + dispatch(fetchProducts({ + limit: data.value as number, + offset: 0, + sort: productsSort, + sortby: productsSortby + })); + }; + + const handleSortFieldChange = ( + _event: React.SyntheticEvent, + data: DropdownProps + ) => { + if (typeof data.value === 'string' && validSortFields.includes(data.value)) { + dispatch(setProductsSortby({sortby: data.value})); + } else { + console.error('Invalid sort field'); + } + }; + + const toggleSortDirection = () => { + dispatch(toggleProductsSort()); + }; + + const formatResponsibles = (responsibles: IResponsible[]) => { + return responsibles.map((responsible, index) => { + return ( + <> + + {index < responsibles.length - 1 && , } + + ); + }) + }; + + const handleMouseEnter = (productId: string) => { + setHoveredProductId(productId); + }; + + const handleMouseLeave = () => { + setHoveredProductId(null); + }; + + const navigateToProduct = (product: IProduct) => { + const latestIncrement = product.latestIncrementId ? `/increments/${product.latestIncrementId}` : ''; + navigate(`/products/${product.id}${latestIncrement}`); + }; + + useEffect(() => { + dispatch(fetchProducts({ + limit: productsItemsPerPage, + offset: (productsCurrentPage - 1) * productsItemsPerPage, + sort: productsSort, + sortby: productsSortby + })); + }, [ + dispatch, + productsItemsPerPage, + productsCurrentPage, + productsSort, + productsSortby, + ]); + + // tsx + return ( + <> + + {/* Breadcrumbs */} + + Products + + +
+ {/* Filter buttons */} +
+ + + +
+ + {/* Add product */} +
+ +
+
+ + + {/* Loader */} + + Loading Products... + + + + + + Name + Description + Responsible(s) + Deadline + Created at + Actions + + + + + {/* Error handling */} + {productsError && ( + + + + + Error❗️ + +

+ {productsError} +

+
+
+
+ )} + {/* No products available. */} + {!productsError && !productsIsLoading && products.length <= 0 && ( + + +

+ It's quiet here 💤 +

+
+ Let's get productive by clicking +
+
+
+ )} + + {/* Normal behavior */} + {!productsError && !productsIsLoading && products.length > 0 && ( + products.slice(0, productsItemsPerPage).map((product) => ( + handleMouseEnter(product.id)} + onMouseLeave={handleMouseLeave} + > + + + + +
+ {product.description || 'n/a'} +
+ + } + content={`${product.description || 'n/a'}`} + /> + +
+ {product.responsibles && product.responsibles.length > 0 ? formatResponsibles(product.responsibles) : 'n/a'} +
+
+ + {product.endsAt ? new Date(product.endsAt).toLocaleDateString() : 'n/a'} + + + {new Date(product.createdAt).toLocaleString()} + + +
+ { + e.stopPropagation(); + openEditModal(product); + }}> + + + } + content={`Edit product "${product.name}"`} + /> + { + handleClone(e, product); + }}> + + + } + content={`Clone product "${product.name}"`} + /> + { + e.stopPropagation(); + handleDelete(product.id); + }}> + + + } + content={`Delete product "${product.name}"`} + /> +
+
+
+ )) + )} +
+
+
+ + {/* Pagination */} +
+
+ +
+ + {/* Items per page */} +
+ +
+
+ + {/* Confirmation handler */} + + + {/* Products modal */} + + +
+ + ); +}; + +export default Products; diff --git a/src/renderer/components/products/ProductsModal.tsx b/src/renderer/components/products/ProductsModal.tsx new file mode 100644 index 0000000..b0f4439 --- /dev/null +++ b/src/renderer/components/products/ProductsModal.tsx @@ -0,0 +1,229 @@ +// src/components/products/ProductsModal.tsx +import React from 'react'; +import { Button, Modal, Form } from 'semantic-ui-react'; +import { useSelector, useDispatch } from 'react-redux'; + +import { IProduct } from '../../interfaces/IProduct'; +import { IResponsible } from '../../interfaces/IResponsible'; +import { AppDispatch, RootState } from '../../store'; +import { + fetchProducts, + fetchProduct, + addOrUpdateProduct, + setProductsModalOpen, + setProductsIsCloning, + setProductsIsEditing, + resetProductsCurrentPage, + setProductsSort, + setProductsSortby, + setProductsCurrentProduct, +} from '../../store/ProductsStore'; + +const ProductsModal: React.FC = () => { + + const dispatch = useDispatch(); // Use the AppDispatch type here + + // global redux states + const { + productsIsCloning, + productsModalOpen, + productsCurrentProduct, + productsIsEditing + } = useSelector((state: RootState) => state.products); + + // local states + // const [newResponsibles, setNewResponsibles] = useState([{ + // id: '', + // firstName: '', + // lastName: '', + // role: '', + // }]); + + // const handleResponsibleChange = (index: number, field: keyof IResponsible, value: string) => { + // const updatedResponsibles = newResponsibles.map((resp, i) => i === index ? { ...resp, [field]: value } : resp); + // setNewResponsibles(updatedResponsibles); + // }; + + // Updated to align with Semantic UI React's expected parameters for onChange + const handleInputChange = (e: React.ChangeEvent, key: string) => { + if (productsCurrentProduct) { + dispatch(setProductsCurrentProduct({ ...productsCurrentProduct, [key]: e.target.value } )); + } + }; + + const handleSubmit = async () => { + if (productsCurrentProduct) { + let product: IProduct; + + if (productsIsCloning) { + const cloneResponse = await dispatch(fetchProduct({ productId: productsCurrentProduct.id, isEagerLoading: true })); + if (fetchProduct.fulfilled.match(cloneResponse)) { + const eagerProduct: IProduct = cloneResponse.payload; + // product = { ...eagerProduct, id: '', name: `${productsCurrentProduct.name}` }; + product = { + ...eagerProduct, + name: productsCurrentProduct.name, + description: productsCurrentProduct.description, + responsibles: productsCurrentProduct.responsibles, + startsAt: productsCurrentProduct.startsAt, + endsAt: productsCurrentProduct.endsAt, + id: '' }; + } else { + // Handle the case where cloning fails + console.error("Cloning failed"); + return; + } + } else { + product = productsCurrentProduct; + } + // product = { ...product, responsibles: newResponsibles } + await dispatch(addOrUpdateProduct({ product })); + } + handleClose(); + }; + + const handleClose = () => { + dispatch(resetProductsCurrentPage()); // Reset to the first page + dispatch(setProductsSort({sort: 'desc'})); // Resets sorting + dispatch(setProductsSortby({sortby: 'createdAt'})); // Resets sorting + dispatch(fetchProducts({limit: 10, offset: 0, sort: 'desc', sortby: 'createdAt'})); + dispatch(setProductsModalOpen(false)); + dispatch(setProductsIsCloning(false)); + dispatch(setProductsIsEditing(false)) + // setNewResponsibles([{ id: '', firstName: '', lastName: '', role: '' }]); + // setNewProduct({ id: '', name: '', createdAt: '', startsAt: '', endsAt: '' }); + }; + + // const addResponsible = (_e: React.MouseEvent) => { + // // setNewResponsibles([...newResponsibles, { id: '', firstName: '', lastName: '', role: '' }]); + // dispatch(setProductsCurrentProduct(...productsCurrentProduct, /* responsible here */)) + // }; + + const addResponsible = (_e: React.MouseEvent) => { + if (productsCurrentProduct) { + const updatedResponsibles = [ + ...(productsCurrentProduct.responsibles || []), + { id: '', firstName: '', lastName: '', role: '' } + ]; + dispatch(setProductsCurrentProduct({ ...productsCurrentProduct, responsibles: updatedResponsibles })); + } + }; + + // const removeResponsible = (index: number, _e: React.MouseEvent) => { + // if (newResponsibles.length === 1) { + // setNewResponsibles([{ id: '', firstName: '', lastName: '', role: '' }]); + // } else { + // setNewResponsibles(newResponsibles.filter((_, i) => i !== index)); + // } + // }; + + const removeResponsible = (index: number, _e: React.MouseEvent) => { + if (productsCurrentProduct) { + const updatedResponsibles = productsCurrentProduct.responsibles?.length === 1 + ? [{ id: '', firstName: '', lastName: '', role: '' }] + : productsCurrentProduct.responsibles?.filter((_, i) => i !== index) || []; + dispatch(setProductsCurrentProduct({ ...productsCurrentProduct, responsibles: updatedResponsibles })); + } + }; + + const handleResponsibleChange = (index: number, field: keyof IResponsible, value: string) => { + if (productsCurrentProduct) { + const updatedResponsibles = productsCurrentProduct.responsibles?.map((resp, i) => + i === index ? { ...resp, [field]: value } : resp + ) || []; + dispatch(setProductsCurrentProduct({ ...productsCurrentProduct, responsibles: updatedResponsibles })); + } + }; + + const formatDate = (dateString: string) => { + if (dateString) { + const date = new Date(dateString); + return new Date(date.getTime() - (date.getTimezoneOffset() * 60000)) + .toISOString() + .split("T")[0]; + } else { + return new Date() + } + }; + + const modalHeader = productsIsCloning ? 'Clone Product' : productsIsEditing ? 'Edit Product' : 'Add Product'; + const submitButtonText = productsIsCloning ? 'Clone' : productsIsEditing ? 'Edit' : 'Add'; + + // tsx + return ( + setProductsModalOpen(false)} dimmer="blurring"> + + {modalHeader} + + +
+ handleInputChange(e, 'name')} + /> + dispatch(setProductsCurrentProduct({ ...productsCurrentProduct!, description: data.value as string }))} + // onChange={(_e, data) => setNewProduct({ ...newProduct, description: data.value as string })} + /> +
+ + {/* {newResponsibles.map((responsible, index) => ( */} + {productsCurrentProduct?.responsibles?.map((responsible, index) => ( + + handleResponsibleChange(index, 'firstName', e.target.value as string)} + /> + handleResponsibleChange(index, 'lastName', e.target.value as string)} + /> + handleResponsibleChange(index, 'role', e.target.value as string)} + /> +
+ + + handleInputChange(e, 'startsAt')} + /> + handleInputChange(e, 'endsAt')} + min={formatDate(productsCurrentProduct?.startsAt || '')} // Enforce that endsAt date cannot be before startsAt + /> + + {submitButtonText} + Cancel + + +
+
+ ) +} + +export default ProductsModal; \ No newline at end of file diff --git a/src/renderer/index.css b/src/renderer/index.css new file mode 100644 index 0000000..d08b4ba --- /dev/null +++ b/src/renderer/index.css @@ -0,0 +1,178 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} + +.form-button-group { + display: flex; + justify-content: space-between; /* This pushes the first item to the left and the last item to the right */ +} + +.cancel-button { + margin-left: auto; /* This pushes the cancel button to the far right */ +} + +.ui.table th { + max-width: 180px; /* Ensure headers have the same width as cells */ +} + +/* used for hovering over table rows in /projects */ +.clickable-row:hover { + background-color: #f0f0f0; +} + +/* used for the link of "name" column in /projects */ +.clickable-row a { + cursor: pointer; + text-decoration: underline; +} + +/* shown when no projects exist in /projects */ +.empty-message-header { + text-align: center; + padding-top: 20px; + margin-bottom: 5px; + color: #999; +} + +/* shown when no projects exist in /projects */ +.empty-message-body { + text-align: center; + padding-bottom: 20px; + color: #999; +} + +/* Ellipsis for table cells in /projects */ +.ellipsis { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} + +.ui.grid > .row { + padding-top: 10px; + padding-bottom: 10px; +} + +.ui.grid > .row > .column { + display: flex; + align-items: center; +} + +.ui.table.no-border-table { + border-top: none !important; + border-bottom: none !important; +} + +.ui.item-group .item:hover { + background-color: #f4f4f5; /* Light grey background on hover */ + cursor: pointer; /* Changes the cursor to a pointer to indicate it's clickable */ +} + +html, body, #root { + height: 100%; + margin: 0; +} + +/* Ensure sidebar and pusher take up full height */ +.ui.sidebar { + height: 100%; +} + +.ui.sidebar + .pusher { + height: 100%; + overflow: hidden; + display: flex; + flex-direction: column; +} + +.content-wrapper { + flex: 1; + /* overflow: hidden; */ + overflow-y: auto; + display: flex; + flex-direction: column; +} + +.ui.fluid.input.inverted input { + background-color: #1b1c1d; + color: #ffffff; + border: 1px solid #333333; + padding: 10px; + border-radius: 0.28571429rem; +} + +.ui.fluid.input.inverted input::placeholder { + color: #777777; +} + +.sidebar-pusher { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; +} + +/* + * UI container + */ + .app-container { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; /* Ensure no scrollbars */ +} + +.graph-container { + flex: 1 1 auto; + overflow: hidden; +} + +.toolbar { + background-color: #282828; + position: absolute; + width: 100%; + z-index: 2; + border-top: 0.5px solid #404040; +} + +.topbar { + background-color: #f8f8f8; /* Example background color */ +} + +/* + * x6 overrides + */ + .x6-widget-stencil { + border: 0.5px solid; + border-radius: 5px; + +} + +.x6-widget-stencil-title { + background-color: #282828; + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + +.x6-toolbar-group::before { + background-color: #404040; +} + +.x6-toolbar.x6-toolbar-hover-effect { + color: #000; +} + +.x6-toolbar-item-icon { + color: #fff; +} \ No newline at end of file diff --git a/src/renderer/index.ejs b/src/renderer/index.ejs new file mode 100644 index 0000000..ce1e5d4 --- /dev/null +++ b/src/renderer/index.ejs @@ -0,0 +1,14 @@ + + + + + + nexTM + + +
+ + diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx new file mode 100644 index 0000000..a517757 --- /dev/null +++ b/src/renderer/index.tsx @@ -0,0 +1,16 @@ +import { createRoot } from 'react-dom/client'; +import App from './App'; + +import 'semantic-ui-css/semantic.min.css'; +import './index.css'; + +const container = document.getElementById('root') as HTMLElement; +const root = createRoot(container); +root.render(); + +// calling IPC exposed from preload script +// window.electron.ipcRenderer.once('ipc-example', (arg) => { +// // eslint-disable-next-line no-console +// console.log(arg); +// }); +// window.electron.ipcRenderer.sendMessage('ipc-example', ['ping']); \ No newline at end of file diff --git a/src/renderer/interfaces/IIncrement.tsx b/src/renderer/interfaces/IIncrement.tsx new file mode 100644 index 0000000..2475049 --- /dev/null +++ b/src/renderer/interfaces/IIncrement.tsx @@ -0,0 +1,20 @@ +import { IModel } from "./IModel" +import { IVersion } from "./IVersion" + +interface IIncrements { + increments: IIncrement[], + incrementsCount: number +} + +interface IIncrement { + id: string, + name: string, + start?: string, + end?: string, + deadline?: string, + state?: string, + productId: string, + // models: IModel [] +} + +export type { IIncrements, IIncrement } \ No newline at end of file diff --git a/src/renderer/interfaces/IModel.tsx b/src/renderer/interfaces/IModel.tsx new file mode 100644 index 0000000..0607fbf --- /dev/null +++ b/src/renderer/interfaces/IModel.tsx @@ -0,0 +1,16 @@ +import { IVersion } from "./IVersion" + +interface IModels { + models: IModel[], + modelsCount: number +} + +interface IModel { + id: string, + createdAt: string + name: string, + incrementId: string, + // versions?: IVersion[] +} + +export type { IModels, IModel } \ No newline at end of file diff --git a/src/renderer/interfaces/IProduct.tsx b/src/renderer/interfaces/IProduct.tsx new file mode 100644 index 0000000..d894188 --- /dev/null +++ b/src/renderer/interfaces/IProduct.tsx @@ -0,0 +1,23 @@ +import { IIncrement } from './IIncrement'; +import './IResponsible' + +import { IResponsible } from './IResponsible'; + +interface IProducts { + products: IProduct[], + productsCount: number +} + +interface IProduct { + id: string; + name: string; + createdAt: string; + description?: string; + startsAt?: string; + endsAt?: string; + responsibles?: IResponsible[], + // increments?: IIncrement[], + latestIncrementId?: string +} + +export type { IProducts, IProduct }; \ No newline at end of file diff --git a/src/renderer/interfaces/IResponsible.tsx b/src/renderer/interfaces/IResponsible.tsx new file mode 100644 index 0000000..e28493e --- /dev/null +++ b/src/renderer/interfaces/IResponsible.tsx @@ -0,0 +1,13 @@ +interface IResponsibles { + responsibles: IResponsible[], + responsiblesCount: number +} + +interface IResponsible { + id: string; + firstName: string; + lastName: string; + role: string; +} + +export type { IResponsibles, IResponsible } \ No newline at end of file diff --git a/src/renderer/interfaces/IVersion.tsx b/src/renderer/interfaces/IVersion.tsx new file mode 100644 index 0000000..f880dec --- /dev/null +++ b/src/renderer/interfaces/IVersion.tsx @@ -0,0 +1,17 @@ +interface IVersion { + id: string, + createdAt: string, + payload: Record // todo change this + thumbnail: string, + x: number, + y: number, + height: number, + width: number +} + +interface IVersions { + versions: IVersion[], + versionsCount: number +} + +export type { IVersion, IVersions } \ No newline at end of file diff --git a/src/renderer/store/IncrementsStore.tsx b/src/renderer/store/IncrementsStore.tsx new file mode 100644 index 0000000..385ca9b --- /dev/null +++ b/src/renderer/store/IncrementsStore.tsx @@ -0,0 +1,216 @@ +// src/store/IncrementsState.tsx +import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; +import type { IIncrement, IIncrements } from '../interfaces/IIncrement'; + +import { RootState } from './'; + +interface IncrementsState { + // states related to increments + increments: IIncrement[]; + incrementsIsLoading: boolean; + incrementsIsLoaded: boolean; + incrementsActiveIndex: number | undefined; + incrementsActiveIncrementId: string | null; + incrementsModalOpen: boolean; + incrementsIsEditing: boolean; + incrementsIsCloning: boolean; + incrementsError: string | null; + incrementsConfirmOpen: boolean; + // states related to increment + currentIncrement: IIncrement | null; + incrementToDelete: string | null; + increment: IIncrement | null; + incrementIsLoading: boolean; + incrementIsLoaded: boolean; + incrementError: string | null; +} + +const initialState: IncrementsState = { + // states related to increments + increments: [], + incrementsIsLoading: false, + incrementsIsLoaded: false, + incrementsActiveIndex: undefined, + incrementsActiveIncrementId: null, + incrementsModalOpen: false, + incrementsIsEditing: false, + incrementsIsCloning: false, + incrementsError: null, + incrementsConfirmOpen: false, + // states related to increment + currentIncrement: null, + incrementToDelete: null, + increment: null, + incrementIsLoading: false, + incrementIsLoaded: false, + incrementError: null, +}; + +// interfaces +interface FetchIncrementsArgs { + productId: string +} + +interface FetchIncrementArgs { + incrementId: string, + isEagerLoading: boolean +} + +// get all increments +export const fetchIncrements = createAsyncThunk( + 'increments/fetchIncrements', + async ({productId}: FetchIncrementsArgs, { rejectWithValue }) => { + try { + // const response = await axios.get(`/api/increments?productId=${productId}&sortBy=incrementIndex&sort=desc`); + // return response.data.increments; + const response = await window.electron.getAllIncrements({productId, sortby: 'incrementIndex', sort: 'desc'}) + return response + } catch (error) { + return rejectWithValue('Failed to load increments.'); + } +}); + +// get one increment +export const fetchIncrement = createAsyncThunk( + 'increments/fetchIncrement', + async ({incrementId, isEagerLoading}: FetchIncrementArgs, { rejectWithValue }) => { + try { + // const response = await axios.get(`/api/increments/${incrementId}?eager=${isEagerLoading ? 'true' : 'false'}`); + // return response.data; + const response = await window.electron.getIncrementById({incrementId, isEagerLoading}) + return response + } catch (error) { + return rejectWithValue('Failed to load increment.'); + } + } +); + +// Add or update an increment +export const addOrUpdateIncrement = createAsyncThunk( + 'increments/addOrUpdateIncrement', + async ({ increment, productId }: { increment: IIncrement; productId: string }, { rejectWithValue }) => { + try { + if (increment.id) { + const incrementId = increment.id + const response = await window.electron.updateIncrement({...increment, incrementId, productId }); + return response + } else { + const response = await window.electron.createIncrement({...increment, productId}); + return response; + } + } catch (error) { + return rejectWithValue(error); + } + } +); + +// delete an increment +export const deleteIncrement = createAsyncThunk('increments/deleteIncrement', async (incrementId: string, { rejectWithValue }) => { + try { + await window.electron.deleteIncrement({incrementId}) + // dispatch(fetchIncrements()); + return incrementId; + } catch (error) { + return rejectWithValue(error); + } +}); + +const incrementsSlice = createSlice({ + name: 'increments', + initialState, + reducers: { + setIncrementsActiveIndex(state, action) { + state.incrementsActiveIndex = action.payload; + }, + setIncrementsActiveIncrementId(state, action) { + state.incrementsActiveIncrementId = action.payload; + }, + setIncrementsModalOpen(state, action) { + state.incrementsModalOpen = action.payload; + }, + setIncrementsIsEditing(state, action) { + state.incrementsIsEditing = action.payload; + }, + setIncrementsIsCloning(state, action) { + state.incrementsIsCloning = action.payload; + }, + setIncrementsConfirmOpen(state, action) { + state.incrementsConfirmOpen = action.payload; + }, + setCurrentIncrement(state, action) { + state.currentIncrement = action.payload; + }, + setIncrementToDelete(state, action) { + state.incrementToDelete = action.payload; + }, + }, + extraReducers: (builder) => { + builder + // cases for fetching all increments + .addCase(fetchIncrements.pending, (state) => { + state.incrementsIsLoading = true; + state.incrementsIsLoaded = false; + + }) + .addCase(fetchIncrements.fulfilled, (state, action) => { + state.increments = action.payload.increments; + state.incrementsIsLoading = false; + state.incrementsIsLoaded = true; + }) + .addCase(fetchIncrements.rejected, (state, action) => { + state.incrementsIsLoading = false; + state.incrementsIsLoaded = false; + state.incrementsError = action.error.message || 'Failed to load increments'; + }) + // cases for fetching one increment + .addCase(fetchIncrement.pending, (state) => { + state.incrementIsLoading = true; + state.incrementError = null; + state.incrementIsLoaded = false; + + }) + .addCase(fetchIncrement.fulfilled, (state, action) => { + state.increment = action.payload; + state.incrementIsLoading = false; + state.incrementIsLoaded = true; + + }) + .addCase(fetchIncrement.rejected, (state, action) => { + state.incrementIsLoading = false; + state.incrementIsLoaded = false; + state.incrementError = action.payload as string; + }) + // cases for adding or updating one increment + .addCase(addOrUpdateIncrement.fulfilled, (state, action) => { + const index = state.increments.findIndex(inc => inc.id === action.payload.id); + if (index !== -1) { + state.increments[index] = action.payload; + } else { + state.increments.unshift(action.payload); + } + state.incrementsModalOpen = false; // Close modal on success + }) + // cases for deleting one increment + .addCase(deleteIncrement.fulfilled, (state, action) => { + state.increments = state.increments.filter(increment => increment.id !== action.payload); + state.incrementsConfirmOpen = false; + }) + .addCase(deleteIncrement.rejected, (state, action) => { + state.incrementsError = action.payload as string; + state.incrementsConfirmOpen = false; + }); + } +}); + +export const { + setIncrementsActiveIndex, + setIncrementsActiveIncrementId, + setIncrementsModalOpen, + setIncrementsIsEditing, + setIncrementsIsCloning, + setCurrentIncrement, + setIncrementsConfirmOpen, + setIncrementToDelete, +} = incrementsSlice.actions; + +export default incrementsSlice.reducer; diff --git a/src/renderer/store/ModelEditorStore.tsx b/src/renderer/store/ModelEditorStore.tsx new file mode 100644 index 0000000..289c877 --- /dev/null +++ b/src/renderer/store/ModelEditorStore.tsx @@ -0,0 +1,372 @@ +import { Graph } from '@antv/x6'; +import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'; + +interface DataflowStride { + spoofing: boolean; + tampering: boolean; + repudiation: boolean; + informationDisclosure: boolean; + denialOfService: boolean; + elevatePrivilege: boolean; +} + +interface ModelEditorState { + isSavePressed: boolean; + isExportPressed: boolean; + isImportPressed: boolean; + isFitViewPressed: boolean; + isZoomInPressed: boolean; + isZoomOutPressed: boolean; + isUndoPressed: boolean; + isRedoPressed: boolean; + isSelectAllPressed: boolean; + isCutPressed: boolean; + isCopyPressed: boolean; + isPastePressed: boolean; + isDeletePressed: boolean; + isExportModalOpen: boolean; + isImportModalOpen: boolean; + + selectedNodeId: string | null; + selectedEdgeId: string | null; + + actorModalOpen: boolean; + actorModalSelectedCell: string | null; + actorName: string; + actorDescription: string; + + systemModalOpen: boolean; + systemModalSelectedCell: string | null; + systemName: string; + systemStack: string + systemDescription: string; + + zoneModalOpen: boolean; + zoneModalSelectedCell: string | null; + zoneName: string; + zoneTrustLevel: string; + zoneDescription: string; + + dataflowModalOpen: boolean; + dataflowModalSelectedCell: string | null; + dataflowLabel: string; + dataflowProtocol: string; + dataflowStride: DataflowStride, + isTextMode: boolean, //deprecated + textModeInputValue: string, //deprecated + textModeSelectedCell: string; // deprecated +} + +const initialState: ModelEditorState = { + isSavePressed: false, + isExportPressed: false, + isImportPressed: false, + isFitViewPressed: false, + isZoomInPressed: false, + isZoomOutPressed: false, + isUndoPressed: false, + isRedoPressed: false, + isSelectAllPressed: false, + isCutPressed: false, + isCopyPressed: false, + isPastePressed: false, + isDeletePressed: false, + isExportModalOpen: false, + isImportModalOpen: false, + // events values + selectedNodeId: null, + selectedEdgeId: null, + // actor values + actorModalOpen: false, + actorModalSelectedCell: '', + actorName: '', + actorDescription: '', + // system values + systemModalOpen: false, + systemModalSelectedCell: '', + systemName: '', + systemStack: '', + systemDescription: '', + // zone values + zoneModalOpen: false, + zoneModalSelectedCell: '', + zoneName: '', + zoneTrustLevel: '', + zoneDescription: '', + // dataflow values + dataflowModalOpen: false, + dataflowModalSelectedCell: '', + dataflowLabel: '', + dataflowProtocol: '', + dataflowStride: { + spoofing: false, + tampering: false, + repudiation: false, + informationDisclosure: false, + denialOfService: false, + elevatePrivilege: false + }, + + + isTextMode: false, //deprecated + textModeInputValue: '', //deprecated + textModeSelectedCell: '' // deprecated +}; + +// interfaces +interface ExportGraphArgs { + format: string, + filename: string, + graph: Graph +} + +interface ImportGraphArgs { + graph: Graph, + jsonData: any +} + +interface ExportJsonArgs { + filename: string, + graph: Graph +} + +const exportJSON = ({filename, graph}: ExportJsonArgs) => { + const jsonString = JSON.stringify(graph, null, 2); + const blob = new Blob([jsonString], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = filename; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); +} + +// export graph +export const exportGraph = createAsyncThunk( + 'modelEditor/exportGraph', + async ({ format, filename, graph }: ExportGraphArgs, { rejectWithValue }) => { + switch (format) { + case 'json': + exportJSON({filename, graph}) + return true; + case 'png': + graph.exportPNG(filename, {padding: 50, quality: 1.0}) + return true; + case 'jpeg': + graph.exportJPEG(filename, {padding: 50, quality: 1.0}) + return true; + case 'svg': + graph.exportSVG(filename) + return true; + default: + return rejectWithValue('Invalid graph format.'); + } + } +); + +// import graph +export const importGraph = createAsyncThunk( + 'modelEditor/importGraph', + async ({ graph, jsonData }: ImportGraphArgs, { rejectWithValue }) => { + try { + if (graph) { + const fallback = graph.toJSON() + graph.fromJSON(jsonData); // Ensure graphInstance is defined + const cells = graph.getCells() + console.log("Result: ", cells) + + if (!cells || cells.length <= 0) { + graph.fromJSON(fallback) + return rejectWithValue('The graph payload is erroneous or empty.'); + } + + graph.zoomToFit({padding: {left: 200, right: 200}}) + } + } catch (error) { + return rejectWithValue(error); + } + } +); + +const modelEditorSlice = createSlice({ + name: 'modelEditor', + initialState, + reducers: { + setSavePressed(state, action: PayloadAction) { + state.isSavePressed = action.payload; + }, + setExportPressed(state, action: PayloadAction) { + state.isExportPressed = action.payload; + }, + setImportPressed(state, action: PayloadAction) { + state.isImportPressed = action.payload; + }, + setFitViewPressed(state, action: PayloadAction) { + state.isFitViewPressed = action.payload; + }, + setZoomInPressed(state, action: PayloadAction) { + state.isZoomInPressed = action.payload; + }, + setZoomOutPressed(state, action: PayloadAction) { + state.isZoomOutPressed = action.payload; + }, + setUndoPressed(state, action: PayloadAction) { + state.isUndoPressed = action.payload; + }, + setRedoPressed(state, action: PayloadAction) { + state.isRedoPressed = action.payload; + }, + setSelectAllPressed(state, action: PayloadAction) { + state.isSelectAllPressed = action.payload; + }, + setCutPressed(state, action: PayloadAction) { + state.isCutPressed = action.payload; + }, + setCopyPressed(state, action: PayloadAction) { + state.isCopyPressed = action.payload; + }, + setPastePressed(state, action: PayloadAction) { + state.isPastePressed = action.payload; + }, + setDeletePressed(state, action: PayloadAction) { + state.isDeletePressed = action.payload; + }, + setExportModalOpen(state, action: PayloadAction) { + state.isExportModalOpen = action.payload; + }, + setImportModalOpen(state, action: PayloadAction) { + state.isImportModalOpen = action.payload; + }, + // events values + setSelectedNodeId(state, action: PayloadAction) { + state.selectedNodeId = action.payload; + }, + setSelectedEdgeId(state, action: PayloadAction) { + state.selectedEdgeId = action.payload; + }, + // actor values + setActorModalOpen(state, action: PayloadAction) { + state.actorModalOpen = action.payload; + }, + setActorModalSelectedCell(state, action: PayloadAction) { + state.actorModalSelectedCell = action.payload; + }, + setActorName(state, action: PayloadAction) { + state.actorName = action.payload; + }, + setActorDescription(state, action: PayloadAction) { + state.actorDescription = action.payload; + }, + // system values + setSystemModalOpen(state, action: PayloadAction) { + state.systemModalOpen = action.payload; + }, + setSystemModalSelectedCell(state, action: PayloadAction) { + state.systemModalSelectedCell = action.payload; + }, + setSystemName(state, action: PayloadAction) { + state.systemName = action.payload; + }, + setSystemStack(state, action: PayloadAction) { + state.systemStack = action.payload; + }, + setSystemDescription(state, action: PayloadAction) { + state.systemDescription = action.payload; + }, + // zone values + setZoneModalOpen(state, action: PayloadAction) { + state.zoneModalOpen = action.payload; + }, + setZoneModalSelectedCell(state, action: PayloadAction) { + state.zoneModalSelectedCell = action.payload; + }, + setZoneName(state, action: PayloadAction) { + state.zoneName = action.payload; + }, + setZoneTrustLevel(state, action: PayloadAction) { + state.zoneTrustLevel = action.payload; + }, + setZoneDescription(state, action: PayloadAction) { + state.zoneDescription = action.payload; + }, + // dataflow values + setDataflowModalOpen(state, action: PayloadAction) { + state.dataflowModalOpen = action.payload; + }, + setDataflowModalSelectedCell(state, action: PayloadAction) { + state.dataflowModalSelectedCell = action.payload; + }, + setDataflowLabel(state, action: PayloadAction) { + state.dataflowLabel = action.payload; + }, + setDataflowProtocol(state, action: PayloadAction) { + state.dataflowProtocol = action.payload; + }, + setDataflowStride(state, action: PayloadAction) { + state.dataflowStride = action.payload; + }, + // deprecated + setTextMode(state, action: PayloadAction) { + state.isTextMode = action.payload; + }, + setTextModeInputValue (state, action: PayloadAction) { + state.textModeInputValue = action.payload; + }, + setTextModeSelectedCell (state, action: PayloadAction) { + state.textModeSelectedCell = action.payload; + }, + } +}); + +export const { + setSavePressed, + setExportPressed, + setImportPressed, + setFitViewPressed, + setZoomInPressed, + setZoomOutPressed, + setUndoPressed, + setRedoPressed, + setSelectAllPressed, + setCutPressed, + setCopyPressed, + setPastePressed, + setDeletePressed, + setExportModalOpen, + setImportModalOpen, + // event values + setSelectedNodeId, + setSelectedEdgeId, + // actor values + setActorModalOpen, + setActorModalSelectedCell, + setActorName, + setActorDescription, + // system values + setSystemModalOpen, + setSystemModalSelectedCell, + setSystemName, + setSystemStack, + setSystemDescription, + // zone values + setZoneModalOpen, + setZoneModalSelectedCell, + setZoneName, + setZoneTrustLevel, + setZoneDescription, + // dataflow values + setDataflowModalOpen, + setDataflowModalSelectedCell, + setDataflowLabel, + setDataflowProtocol, + setDataflowStride, + + setTextMode, // deprecated + setTextModeInputValue, // deprecated + setTextModeSelectedCell, // deprecated +} = modelEditorSlice.actions; + +export type { DataflowStride }; + +export default modelEditorSlice.reducer; \ No newline at end of file diff --git a/src/renderer/store/ModelsStore.tsx b/src/renderer/store/ModelsStore.tsx new file mode 100644 index 0000000..6416cbb --- /dev/null +++ b/src/renderer/store/ModelsStore.tsx @@ -0,0 +1,200 @@ +// modelsSlice.ts +import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit'; +import axios from 'axios'; + +import { IModel, IModels } from '../interfaces/IModel'; + +interface ModelsState { + // states related to models + models: IModel[]; + modelsCount: number; + modelsIsLoading: boolean; + modelsError: string | null; + modelsModalOpen: boolean; + modelsIsCloning: boolean; + modelsIsEditing: boolean; + modelsCurrentModel: IModel | null; + modelsConfirmOpen: boolean; + modelToDelete: string | null; + // states related to model + model: IModel | null; + modelIsLoading: boolean; + modelIsLoaded: boolean; + modelError: string | null; +} + +const initialState: ModelsState = { + // models initializers + models: [], + modelsCount: 0, + modelsIsLoading: false, + modelsError: null, + modelsModalOpen: false, + modelsIsCloning: false, + modelsIsEditing: false, + modelsCurrentModel: null, + modelsConfirmOpen: false, + modelToDelete: null, + // model initializers + model: null, + modelIsLoading: false, + modelIsLoaded: false, + modelError: null, +}; + +// interfaces +interface FetchModelsArgs { + incrementId: string +} + +interface FetchModelArgs { + modelId: string, + isEagerLoading: boolean +} + +interface AddOrUpdateModelArgs { + model: IModel, + incrementId: string +} + +// get all models +export const fetchModels = createAsyncThunk( + 'models/fetchModels', + async ({ incrementId }: FetchModelsArgs, { rejectWithValue }) => { + try { + // const response = await fetch(`/api/models?incrementId=${incrementId}`); + // const data = await response.json(); + const response = await window.electron.getAllModels({ incrementId }) + return response; + } catch (error) { + return rejectWithValue(error); + } + } +); + +// get one model +export const fetchModel = createAsyncThunk( + 'models/fetchModel', + async ({modelId, isEagerLoading}: FetchModelArgs, { rejectWithValue }) => { + try { + // const response = await axios.get(`/api/models/${modelId}?eager=${isEagerLoading ? 'true' : 'false'}`); + // return response.data; + const response = await window.electron.getModelById({ modelId, isEagerLoading }) + return response + } catch (error) { + return rejectWithValue(error); + } + } +); + +// Add or update a product +export const addOrUpdateModel = createAsyncThunk( + 'models/addOrUpdateModel', + async ({ model, incrementId }: AddOrUpdateModelArgs, { rejectWithValue }) => { + try { + if (model.id) { + // const response = await axios.put(`/api/models/${model.id}`, modelData); + // return response.data; + const response = await window.electron.updateModel({ ...model, incrementId }) + return response + } else { + // const response = await axios.post('/api/models', modelData); + // return response.data; + const response = await window.electron.createModel({ ...model, incrementId }) + return response + } + } catch (error) { + return rejectWithValue('Failed to save product.'); + } + } +); + +// delete a model +export const deleteModel = createAsyncThunk('models/deleteModel', async (modelId: string, { rejectWithValue }) => { + try { + // await axios.delete(`/api/models/${modelId}`); + // return modelId; + await window.electron.deleteModel({ modelId }) + return modelId + } catch (error) { + return rejectWithValue(error); + } +}); + +const modelsSlice = createSlice({ + name: 'models', + initialState, + reducers: { + setModelsIsEditing(state, action: PayloadAction) { + state.modelsIsEditing = action.payload; + }, + setModelsIsCloning(state, action: PayloadAction) { + state.modelsIsCloning = action.payload; + }, + setModelsModalOpen(state, action: PayloadAction) { + state.modelsModalOpen = action.payload; + }, + setModelsCurrentModel(state, action: PayloadAction) { + state.modelsCurrentModel = action.payload; + // state.modelsIsEditing = !!action.payload; + }, + setModelsConfirmOpen(state, action) { + state.modelsConfirmOpen = action.payload; + }, + setModelToDelete(state, action) { + state.modelToDelete = action.payload; + } + }, + extraReducers: (builder) => { + builder + // cases for fetching all models + .addCase(fetchModels.pending, (state) => { + state.modelsIsLoading = true; + }) + .addCase(fetchModels.fulfilled, (state, action) => { + state.models = action.payload.models; + state.modelsCount = action.payload.modelsCount; + state.modelsIsLoading = false; + }) + .addCase(fetchModels.rejected, (state, action) => { + state.modelsIsLoading = false; + state.modelsError = action.payload as string; + }) + // cases for fetching one model + .addCase(fetchModel.pending, (state) => { + state.modelIsLoading = true; + state.modelIsLoaded = false; + state.modelError = null; + }) + .addCase(fetchModel.fulfilled, (state, action) => { + state.model = action.payload; + state.modelIsLoading = false; + state.modelIsLoaded = true; + }) + .addCase(fetchModel.rejected, (state, action) => { + state.modelIsLoading = false; + state.modelIsLoaded = false; + state.modelError = action.payload as string; + }) + // cases for deleting a model + .addCase(deleteModel.fulfilled, (state, action) => { + state.models = state.models.filter(model => model.id !== action.payload); + state.modelsConfirmOpen = false; + }) + .addCase(deleteModel.rejected, (state, action) => { + state.modelsError = action.payload as string; + state.modelsConfirmOpen = false; + }); + }, +}); + +export const { + setModelsModalOpen, + setModelsCurrentModel, + setModelsIsCloning, + setModelsIsEditing, + setModelsConfirmOpen, + setModelToDelete +} = modelsSlice.actions; + +export default modelsSlice.reducer; diff --git a/src/renderer/store/ProductsStore.tsx b/src/renderer/store/ProductsStore.tsx new file mode 100644 index 0000000..af879b2 --- /dev/null +++ b/src/renderer/store/ProductsStore.tsx @@ -0,0 +1,258 @@ +// src/store/ProductStore.tsx +import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'; +import axios from 'axios'; +import type { IProduct, IProducts } from '../interfaces/IProduct'; +import { IResponsible } from '../interfaces/IResponsible'; + +interface ProductsState { + // states related to products + products: IProduct[]; + productsCount: number; + productsIsLoading: boolean; + productsError: string | null; + productsIsCloning: boolean; + productsModalOpen: boolean; + productsCurrentProduct: IProduct | null; + productsCurrentResponsibles: IResponsible[] | null; + productsIsEditing: boolean; + productsCurrentPage: number; + productsSortby: string; + productsSort: string; + productsItemsPerPage: number; + // states related to product + product: IProduct | null; + productIsLoading: boolean; + productIsLoaded: boolean; + productError: string | null; +} + +const initialProductsState: ProductsState = { + //products + products: [], + productsCount: 0, + productsIsLoading: false, + productsError: null, + productsIsCloning: false, + productsModalOpen: false, + productsCurrentProduct: null, + productsCurrentResponsibles: null, + productsIsEditing: false, + productsCurrentPage: 1, + productsSortby: 'createdAt', + productsSort: 'desc', + productsItemsPerPage: 5, + //product + product: null, + productIsLoading: false, + productIsLoaded: false, + productError: null, +}; + +// interfaces +interface AddOrUpdateProductArgs { + product: IProduct; + // responsibles: IResponsible[]; +} + +interface FetchProductsArgs { + limit: number, + offset: number, + sort: string, + sortby: string, +} + +interface FetchProductArgs { + productId: string, + isEagerLoading: boolean +} + +interface DeleteProductArgs { + productId: string, + limit: number, + offset: number, + sort: string, + sortby: string, +} + +// get all products +export const fetchProducts = createAsyncThunk( + 'products/fetchProducts', + async ({ limit, offset, sort, sortby }: FetchProductsArgs, { rejectWithValue }) => { + try { + // Construct the URL based on limit and offset + const params = new URLSearchParams(); + + if (limit !== undefined) params.append('limit', String(limit)); + if (offset !== undefined) params.append('offset', String(offset)); + if (sort !== undefined) params.append('sort', String(sort)); + if (sortby !== undefined) params.append('sortby', String(sortby)); + + // const response = await axios.get(`/api/products?${params.toString()}`); + const response = await window.electron.getAllProducts({limit, offset, sort, sortby}); + + // return response.data + return response + } catch (error) { + return rejectWithValue('Failed to load products.'); + } + } +); + +// get one product +export const fetchProduct = createAsyncThunk( + 'products/fetchProduct', + async ({productId, isEagerLoading}: FetchProductArgs, { rejectWithValue }) => { + try { + // const response = await axios.get(`/api/products/${productId}?eager=${isEagerLoading ? 'true' : 'false'}`); + // return response.data; + const response = await window.electron.getProductById({productId, isEagerLoading}); + return response; + } catch (error) { + return rejectWithValue('Failed to load product.'); + } + } +); + + +// Add or update a product +export const addOrUpdateProduct = createAsyncThunk( + 'products/addOrUpdateProduct', + async ({ product }: AddOrUpdateProductArgs, { rejectWithValue }) => { + try { + // const productData = { + // ...product, + // responsibles: responsibles.map(({ firstName, lastName, role }) => ({ + // firstName, + // lastName, + // role, + // })), + // }; + + if (product.id) { + // const response = await axios.put(`/api/products/${product.id}`, product); + // return response.data; + const productId = product.id + const response = await window.electron.updateProduct({productId, product}); + return response; + } else { + // const response = await axios.post('/api/products', product); + // return response.data; + const response = await window.electron.createProduct(product); + console.log("New product") + console.log(response) + return response; + } + } catch (error) { + return rejectWithValue('Failed to save product.'); + } + } +); + +// delete a product +export const deleteProduct = createAsyncThunk('products/deleteProduct', + async ({productId, limit, offset, sort, sortby}: DeleteProductArgs, { dispatch }) => { + // await axios.delete(`/api/products/${productId}`); + await window.electron.deleteProduct({productId}) + dispatch(fetchProducts({limit, offset, sort, sortby})); + return productId + } +); + +// products slices +const productsSlice = createSlice({ + name: 'products', + initialState: initialProductsState, + reducers: { + setProductsIsCloning(state, action: PayloadAction) { + state.productsIsCloning = action.payload; + }, + setProductsModalOpen(state, action: PayloadAction) { + state.productsModalOpen = action.payload; + }, + setProductsIsEditing(state, action: PayloadAction) { + state.productsIsEditing = action.payload; + }, + setProductsCurrentProduct(state, action: PayloadAction) { + state.productsCurrentProduct = action.payload; + // state.productsIsEditing = !!action.payload; + }, + setProductsCurrentResponsibles(state, action: PayloadAction) { + state.productsCurrentResponsibles = action.payload; + }, + setProductsCurrentPage: (state, action: PayloadAction) => { + state.productsCurrentPage = action.payload; + }, + resetProductsCurrentPage: (state) => { + state.productsCurrentPage = 1; + }, + setProductsSort: (state, action: PayloadAction<{ sort: string }>) => { + state.productsSort = action.payload.sort; + }, + setProductsSortby: (state, action: PayloadAction<{ sortby: string }>) => { + state.productsSortby = action.payload.sortby; + }, + toggleProductsSort: (state) => { + state.productsSort = state.productsSort === 'asc' ? 'desc' : 'asc'; + }, + setProductsItemsPerPage: (state, action: PayloadAction) => { + state.productsItemsPerPage = action.payload; + }, + }, + extraReducers: (builder) => { + builder + // cases for fetching ALL products + .addCase(fetchProducts.pending, (state) => { + state.productsIsLoading = true; + }) + .addCase(fetchProducts.fulfilled, (state, action) => { + state.products = action.payload.products; + state.productsCount = action.payload.productsCount; + state.productsIsLoading = false; + }) + .addCase(fetchProducts.rejected, (state, action) => { + state.productsIsLoading = false; + state.productsError = action.payload as string; + }) + // cases for fetching ONE product + .addCase(fetchProduct.pending, (state) => { + state.productIsLoaded = false; + state.productIsLoading = true; + state.productError = null; + }) + .addCase(fetchProduct.fulfilled, (state, action) => { + state.product = action.payload; + state.productIsLoading = false; + state.productIsLoaded = true; + }) + .addCase(fetchProduct.rejected, (state, action) => { + state.productIsLoaded = false; + state.productIsLoading = false; + state.productError = action.payload as string; + }) + // cases for deleting one product + // .addCase(deleteProduct.fulfilled, (state, action) => { + // state.products = state.products.filter(product => product.id !== action.payload); + // state.productsConfirmOpen = false; + // }) + // .addCase(deleteIncrement.rejected, (state, action) => { + // state.productsError = action.payload as string; + // state.productsConfirmOpen = false; + // }) + ; + } +}); + +export const { + setProductsIsCloning, + setProductsModalOpen, + setProductsIsEditing, + setProductsCurrentProduct, + setProductsCurrentPage, + resetProductsCurrentPage, + setProductsSort, + setProductsSortby, + toggleProductsSort, + setProductsItemsPerPage +} = productsSlice.actions; + +export default productsSlice.reducer; diff --git a/src/renderer/store/SettingsStore.tsx b/src/renderer/store/SettingsStore.tsx new file mode 100644 index 0000000..b6b95af --- /dev/null +++ b/src/renderer/store/SettingsStore.tsx @@ -0,0 +1,83 @@ +// src/store/ProductStore.tsx +import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'; + +interface SettingsState { + // General settings + sidebarVisible: boolean; + toastVisible: boolean; + toastPromise: Promise | null; + toastLoadingMessage: string; + toastSuccessMessage: string; + toastErrorMessage: string; + path: string; + pathIsLoading: boolean; + pathIsLoaded: boolean; + pathError: string | null; + // Model Editor settings + gridVisible: 'none' | 'dot' | 'mesh'; + explicitObjectSelection: boolean; +} + +const initialSettingsState: SettingsState = { + // General settings + sidebarVisible: false, + toastVisible: false, + toastPromise: null, + toastLoadingMessage: '', + toastSuccessMessage: '', + toastErrorMessage: '', + path: '', + pathIsLoading: false, + pathIsLoaded: false, + pathError: null, + // Model Editor settings + gridVisible: 'none', + explicitObjectSelection: false +}; + +// products slices +const productsSlice = createSlice({ + name: 'settings', + initialState: initialSettingsState, + reducers: { + // General settings + setSidebarVisible(state, action: PayloadAction) { + state.sidebarVisible = action.payload; + }, + showToast: (state, action: PayloadAction<{ promise: Promise; loadingMessage: string; successMessage: string; errorMessage: string }>) => { + state.toastVisible = true; + state.toastPromise = action.payload.promise; + state.toastLoadingMessage = action.payload.loadingMessage; + state.toastSuccessMessage = action.payload.successMessage; + state.toastErrorMessage = action.payload.errorMessage; + }, + hideToast: (state) => { + state.toastVisible = false; + state.toastPromise = null; + state.toastLoadingMessage = ''; + state.toastSuccessMessage = ''; + state.toastErrorMessage = ''; + }, + // Model Editor settings + setGridVisible(state, action: PayloadAction<'none' | 'dot' | 'mesh'>) { + state.gridVisible = action.payload; + }, + setDatabasePath(state, action: PayloadAction) { + state.path = action.payload; + }, + setExplicitObjectSelection(state, action: PayloadAction) { + state.explicitObjectSelection = action.payload; + }, + }, +}); + +export const { + setSidebarVisible, + showToast, + hideToast, + setGridVisible, + setDatabasePath, + setExplicitObjectSelection +} = productsSlice.actions; + +export default productsSlice.reducer; diff --git a/src/renderer/store/VersionsStore.tsx b/src/renderer/store/VersionsStore.tsx new file mode 100644 index 0000000..23ad21d --- /dev/null +++ b/src/renderer/store/VersionsStore.tsx @@ -0,0 +1,160 @@ +// src/store/IncrementsState.tsx +import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; +import axios from 'axios'; +import type { IVersion } from '../interfaces/IVersion'; + +import { RootState } from './'; +import { DataUri, Graph } from '@antv/x6'; +import { showToast } from './SettingsStore'; +import { Console } from 'console'; + + +interface IncrementsState { + // states related to latestVersion + latestVersion: IVersion | null; + latestVersionIsLoading: boolean; + latestVersionIsLoaded: boolean; + latestVersionError: string | null; +} + +const initialState: IncrementsState = { + // states related to latestVersion + latestVersion: null, + latestVersionIsLoading: false, + latestVersionIsLoaded: false, + latestVersionError: null, +}; + +// interfaces +interface FetchLatestVersionArgs { + modelId: string +} + +interface AddLatestVersionArgs { + modelId: string, + graph: Graph, + x: number, + y: number, + height: number, + width: number +} + +interface FetchLatestVersionThumbnailArgs { + modelId: string; +} + + +// get latest version +export const fetchLatestVersion = createAsyncThunk( + 'versions/fetchLatestVersion', + async ({modelId}: FetchLatestVersionArgs, { rejectWithValue }) => { + try { + // const response = await axios.get(`/api/versions/latest?modelId=${modelId}`); + // return response.data; + const response = await window.electron.getLatestVersion({ modelId }) + return response + } catch (error) { + return rejectWithValue('Failed to load increment.'); + } + } +); + +// Promisify the graph.toPNG function +const toPNGP = (graph: Graph): Promise => { + return new Promise((resolve, reject) => { + try { + graph.toPNG((dataUri: string) => { + if (dataUri) { + resolve(dataUri); + } else { + console.error("Failed to generate PNG data URI."); + reject(new Error("Failed to generate PNG data URI")); } + }, { + padding: { + left: 25, + right: 25, + top: 25, + bottom: 25 + }, + quality: 1, + width: 150, + height: 125 + }); + } catch (error) { + reject(error); + } + }); +}; + +// Add latest version +export const addLatestVersion = createAsyncThunk( + 'versions/addLatestVersion', + async ({ modelId, graph, x, y, height, width }: AddLatestVersionArgs, { rejectWithValue }) => { + try { + const dataUri = await toPNGP(graph); + + const response = window.electron.createVersion({ + modelId: modelId, + payload: { graph: graph.toJSON() }, + thumbnail: dataUri, + x, + y, + height, + width + }); + + return response; + } catch (error) { + return rejectWithValue(error); + } + } +); + +const incrementsSlice = createSlice({ + name: 'versions', + initialState, + reducers: { + // to do + }, + extraReducers: (builder) => { + builder + // cases for fetching latest version + .addCase(fetchLatestVersion.pending, (state) => { + state.latestVersionIsLoading = true; + state.latestVersionIsLoaded = false; + state.latestVersionError = null; + }) + .addCase(fetchLatestVersion.fulfilled, (state, action) => { + state.latestVersion = action.payload; + state.latestVersionIsLoading = false; + state.latestVersionIsLoaded = true; + }) + .addCase(fetchLatestVersion.rejected, (state, action) => { + state.latestVersionIsLoading = false; + state.latestVersionIsLoaded = false; + state.latestVersionError = action.payload as string; + }) + // cases for adding latest version + .addCase(addLatestVersion.pending, (state) => { + state.latestVersionIsLoading = true; + state.latestVersionIsLoaded = false; + state.latestVersionError = null; + }) + .addCase(addLatestVersion.fulfilled, (state, action) => { + state.latestVersion = action.payload; + state.latestVersionIsLoading = false; + state.latestVersionIsLoaded = true; + }) + .addCase(addLatestVersion.rejected, (state, action) => { + state.latestVersionIsLoading = false; + state.latestVersionIsLoaded = false; + state.latestVersionError = action.payload as string; + }); + } +}); + +export const { + +} = incrementsSlice.actions; + +export default incrementsSlice.reducer; diff --git a/src/renderer/store/index.tsx b/src/renderer/store/index.tsx new file mode 100644 index 0000000..da77e1a --- /dev/null +++ b/src/renderer/store/index.tsx @@ -0,0 +1,33 @@ +// store/index.ts +import { configureStore } from '@reduxjs/toolkit'; + +import productsReducer from './ProductsStore'; +import incrementsReducer from './IncrementsStore'; +import modelsReducer from './ModelsStore'; +import versionsReducer from './VersionsStore' +import modelEditorReducer from './ModelEditorStore'; +import settingsReducer from './SettingsStore'; + +const store = configureStore({ + reducer: { + products: productsReducer, + increments: incrementsReducer, + models: modelsReducer, + versions: versionsReducer, + modelEditor: modelEditorReducer, + settings: settingsReducer + }, + // ignore non-serializable data for toasts... + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + serializableCheck: { + ignoredActions: ['settings/showToast', 'settings/hideToast'], + ignoredPaths: ['settings.toastPromise'], + }, + }), +}); + +export type RootState = ReturnType; +export type AppDispatch = typeof store.dispatch; + +export default store; diff --git a/src/renderer/utils.tsx b/src/renderer/utils.tsx new file mode 100644 index 0000000..847afe7 --- /dev/null +++ b/src/renderer/utils.tsx @@ -0,0 +1,16 @@ +import { Graph } from '@antv/x6'; +import crypto from 'crypto-js'; + +const computeHash = (jsonData: any): string => { + const stringData = JSON.stringify(jsonData); + return crypto.SHA256(stringData).toString(); +}; + +export const compareHashes = (oldGraph: any, newGraph: any): boolean => { + // Compute the current hash + const oldGraphHash = computeHash(oldGraph); + const newGraphHash = computeHash(newGraph) + + // Compare the current hash with the latest hash + return oldGraphHash === newGraphHash; +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1e6a3d4 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "incremental": true, + "target": "es2022", + "module": "commonjs", + "lib": ["dom", "es2022"], + "jsx": "react-jsx", + "strict": true, + "sourceMap": true, + "moduleResolution": "node", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "allowJs": true, + "outDir": ".erb/dll", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + }, + "exclude": ["test", "release/build", "release/app/dist", ".erb/dll"] +}

+nexTM is a threat modeling tool tailored towards agile software development. It provides a clean and easy to use model editor which is loosely inspired by OWASP Threat Dragon (as it also makes use of the antvis X6 library). Besides the model editor, nexTM allows you to structure your threat modeling projects into products, product increments, and models to conveniently keep track of any changes throughout application development. In the near future, it is planned to implement a "diff view" feature to highlight model changes between different increments. More coming soon... + +This project uses the Electron React Boilerplate. +