From 858f83a45cb9ac7c7ea65890bb7e70a05fcbc20c Mon Sep 17 00:00:00 2001 From: IndieKKY Date: Wed, 17 May 2023 16:37:56 +0800 Subject: [PATCH] init --- .editorconfig | 17 + .env.development | 1 + .env.production_chrome | 3 + .eslintignore | 6 + .eslintrc.cjs | 40 + .gitignore | 27 + .npmrc | 1 + LICENSE | 21 + README.md | 63 + fixChrome.cjs | 11 + index.html | 16 + manifest.json | 33 + package.json | 77 + pnpm-lock.yaml | 4354 ++++++++++++++++++++++++++++ postcss.config.cjs | 6 + public/favicon-128x128.png | Bin 0 -> 1227 bytes public/favicon-16x16.png | Bin 0 -> 278 bytes public/favicon-32x32.png | Bin 0 -> 363 bytes public/favicon-48x48.png | Bin 0 -> 400 bytes public/favicon.ico | Bin 0 -> 447 bytes public/popup.html | 11 + public/shot.jpg | Bin 0 -> 51088 bytes public/subtitle.svg | 3 + src/App.tsx | 73 + src/Router.tsx | 26 + src/biz/Body.tsx | 168 ++ src/biz/CompactSegmentItem.tsx | 33 + src/biz/Header.tsx | 99 + src/biz/MoreBtn.tsx | 278 ++ src/biz/NormalSegmentItem.tsx | 35 + src/biz/SegmentCard.tsx | 239 ++ src/biz/SegmentItem.tsx | 70 + src/biz/Settings.tsx | 277 ++ src/chrome/background.ts | 72 + src/chrome/content-script.cjs | 238 ++ src/chrome/openaiService.ts | 20 + src/chrome/taskService.ts | 51 + src/components/Popover.module.less | 32 + src/components/Popover.tsx | 40 + src/const.tsx | 76 + src/data/data.json | 864 ++++++ src/data/keyPoints.json | 22 + src/hooks/redux.ts | 6 + src/hooks/useSubtitle.ts | 20 + src/hooks/useSubtitleService.ts | 219 ++ src/hooks/useTranslate.ts | 310 ++ src/hooks/useTranslateService.ts | 55 + src/index.less | 28 + src/main.tsx | 22 + src/redux/envReducer.ts | 246 ++ src/store.ts | 14 + src/typings.d.ts | 106 + src/util/biz_util.ts | 277 ++ src/util/util.ts | 43 + src/vite-env.d.ts | 8 + tailwind.config.cjs | 35 + tsconfig.json | 24 + tsconfig.node.json | 10 + vite.config.ts | 29 + 59 files changed, 8855 insertions(+) create mode 100644 .editorconfig create mode 100644 .env.development create mode 100644 .env.production_chrome create mode 100644 .eslintignore create mode 100644 .eslintrc.cjs create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 LICENSE create mode 100644 README.md create mode 100644 fixChrome.cjs create mode 100644 index.html create mode 100644 manifest.json create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 postcss.config.cjs create mode 100644 public/favicon-128x128.png create mode 100644 public/favicon-16x16.png create mode 100644 public/favicon-32x32.png create mode 100644 public/favicon-48x48.png create mode 100644 public/favicon.ico create mode 100644 public/popup.html create mode 100644 public/shot.jpg create mode 100644 public/subtitle.svg create mode 100644 src/App.tsx create mode 100644 src/Router.tsx create mode 100644 src/biz/Body.tsx create mode 100644 src/biz/CompactSegmentItem.tsx create mode 100644 src/biz/Header.tsx create mode 100644 src/biz/MoreBtn.tsx create mode 100644 src/biz/NormalSegmentItem.tsx create mode 100644 src/biz/SegmentCard.tsx create mode 100644 src/biz/SegmentItem.tsx create mode 100644 src/biz/Settings.tsx create mode 100644 src/chrome/background.ts create mode 100644 src/chrome/content-script.cjs create mode 100644 src/chrome/openaiService.ts create mode 100644 src/chrome/taskService.ts create mode 100644 src/components/Popover.module.less create mode 100644 src/components/Popover.tsx create mode 100644 src/const.tsx create mode 100644 src/data/data.json create mode 100644 src/data/keyPoints.json create mode 100644 src/hooks/redux.ts create mode 100644 src/hooks/useSubtitle.ts create mode 100644 src/hooks/useSubtitleService.ts create mode 100644 src/hooks/useTranslate.ts create mode 100644 src/hooks/useTranslateService.ts create mode 100644 src/index.less create mode 100644 src/main.tsx create mode 100644 src/redux/envReducer.ts create mode 100644 src/store.ts create mode 100644 src/typings.d.ts create mode 100644 src/util/biz_util.ts create mode 100644 src/util/util.ts create mode 100644 src/vite-env.d.ts create mode 100644 tailwind.config.cjs create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..dbdf761 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# http://editorconfig.org +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 +indent_size = 3 + +[Makefile] +indent_style = tab diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..97e15b6 --- /dev/null +++ b/.env.development @@ -0,0 +1 @@ +VITE_ENV=web-dev diff --git a/.env.production_chrome b/.env.production_chrome new file mode 100644 index 0000000..0cb6bbe --- /dev/null +++ b/.env.production_chrome @@ -0,0 +1,3 @@ +NODE_ENV=production + +VITE_ENV=chrome diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..7b310a6 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +public/ +dist/ +node_modules/ +postcss.config.cjs +vite.config.ts +vite-env.d.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..b3b3375 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,40 @@ +module.exports = { + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "standard-with-typescript", + ], + "overrides": [], + "parserOptions": { + "project": "tsconfig.json", + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": [ + "react" + ], + "rules": { + "react-hooks/exhaustive-deps": "error", + "@typescript-eslint/explicit-function-return-type": "off", + "react/react-in-jsx-scope": "off", + "@typescript-eslint/restrict-plus-operands": "off", + "@typescript-eslint/no-empty-interface": "warn", + "@typescript-eslint/no-unused-vars": "warn", + "@typescript-eslint/strict-boolean-expressions": "warn", + "@typescript-eslint/object-curly-spacing": "off", + "@typescript-eslint/no-misused-promises": "off", + "@typescript-eslint/space-infix-ops": "off", + "operator-linebreak": "off", + "@typescript-eslint/space-before-function-paren": "off", + "@typescript-eslint/comma-dangle": "off" + }, + "settings": { + "react": { + "version": "detect" + } + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2c46cb6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local +.pnpm-store + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +stats.html diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..5e4086a --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +registry=https://registry.npmmirror.com/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6bc3d63 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright 2023 IndieKKY + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d92f7a2 --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ +## 简介 + +哔哩哔哩字幕列表是一个浏览器扩展,旨在提供更高效和可控的视频信息获取方式。 + +该扩展会显示视频的字幕列表,让用户能够快速浏览字幕内容,并通过点击跳转到相应的视频位置。同时,用户还可以方便地下载字幕文件。 + +除此之外,该扩展还提供了视频字幕总结功能,帮助用户快速掌握视频的要点。 + +该扩展主要面向知识学习类的视频,帮助用户更好地理解和总结视频内容。 + +## 功能特点 + +- 显示视频的字幕列表 +- 点击字幕跳转视频对应位置 +- 多种格式复制与下载字幕 +- 多种方式总结字幕 +- 翻译字幕 + +## 下载扩展 + +[chrome商店](https://chrome.google.com/webstore/detail/bciglihaegkdhoogebcdblfhppoilclp) + +## 使用说明 + +安装扩展后,在哔哩哔哩网站观看视频时,视频右侧会显示字幕列表面板。 + +## 交流联系 + +QQ群:194536885 + +微信公众号:IndieKKY + +twitter:[https://twitter.com/IndieKky](https://twitter.com/IndieKky) + +github: [IndieKKY](https://github.com/IndieKKY) + +## 问题反馈 + +如果您在使用过程中遇到任何问题,或者有任何改进建议,请在项目的 **Issue 页面** 中提出。我们欢迎您的反馈,并会尽快回复和处理相关问题。 + +## 开发指南 +注意!此项目当前代码结构与代码质量不是非常高。 + +node版本:18.15.0 +包管理器:pnpm + +本地开发时,`pnpm run dev`可以开启本地调试,但只能调试部分功能; +`pnpm run build_chrome`可以构建项目,然后浏览器扩展中加载`dist`目录即可,此方式可以调试完整功能,但不是很方便,从改代码到构建完看到效果耗时比较长(取决于你的电脑性能)。 + +## 贡献指南 + +欢迎贡献代码或提出改进建议!如果您希望为该项目做出贡献,请遵循以下步骤: + +1. Fork该仓库到您自己的账号。 +2. 创建您的分支并进行修改。 +3. 提交修改前,请确保您的代码通过了所有的测试,并保持良好的代码风格。 +4. 提交 Pull Request,描述清楚您的修改内容和目的。 +5. 我们将仔细审查您的贡献,并与您进行讨论和反馈。 +6. 一旦您的贡献被接受并合并到主分支,您的修改将成为项目的一部分。 + +## 许可证 + +该项目采用 **MIT 许可证**,详情请参阅许可证文件。 diff --git a/fixChrome.cjs b/fixChrome.cjs new file mode 100644 index 0000000..e68be20 --- /dev/null +++ b/fixChrome.cjs @@ -0,0 +1,11 @@ +console.log('fixChrome.js loaded'); + +const fs = require('fs') + +const manifest = require('./dist/manifest.json') +manifest.web_accessible_resources[0].resources.push('index.html') +manifest.action.default_popup = 'popup.html' +//写回文件 +fs.writeFileSync('./dist/manifest.json', JSON.stringify(manifest, null, 2)) + +console.log('fixChrome.js done'); diff --git a/index.html b/index.html new file mode 100644 index 0000000..6ef8103 --- /dev/null +++ b/index.html @@ -0,0 +1,16 @@ + + + + bilibili-subtitle - 哔哩哔哩字幕 + + + + + + + + + + + + diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..a4cdba2 --- /dev/null +++ b/manifest.json @@ -0,0 +1,33 @@ +{ + "name": "哔哩哔哩字幕列表", + "description": "显示B站视频的字幕列表,可点击跳转与下载字幕,并支持翻译和总结字幕!", + "version": "1.6.5", + "manifest_version": 3, + "permissions": [ + "storage" + ], + "background": { + "service_worker": "src/chrome/background.ts" + }, + "content_scripts": [ + { + "matches": ["https://www.bilibili.com/video/*"], + "js": ["src/chrome/content-script.cjs"] + } + ], + "icons": { + "16": "favicon-16x16.png", + "32": "favicon-32x32.png", + "48": "favicon-48x48.png", + "128": "favicon-128x128.png" + }, + "action": { + "default_popup": "index.html", + "default_icon": { + "16": "favicon-16x16.png", + "32": "favicon-32x32.png", + "48": "favicon-48x48.png", + "128": "favicon-128x128.png" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..831cae8 --- /dev/null +++ b/package.json @@ -0,0 +1,77 @@ +{ + "private": true, + "name": "bilibili-subtitle", + "version": "1.6.5", + "type": "module", + "description": "哔哩哔哩字幕列表", + "main": "index.js", + "scripts": { + "dev": "vite", + "build_chrome": "tsc && vite build -m production_chrome && pnpm run fixChrome", + "fix": "eslint --fix --quiet .", + "fixChrome": "node fixChrome.cjs" + }, + "author": "IndieKKY", + "license": "MIT", + "dependencies": { + "@crxjs/vite-plugin": "^1.0.14", + "@kky002/kky-hooks": "^1.2.1", + "@kky002/kky-ui": "^1.0.9", + "@kky002/kky-util": "^1.4.2", + "@logto/react": "1.0.0-beta.13", + "@popperjs/core": "^2.11.6", + "@reduxjs/toolkit": "^1.8.5", + "@tippyjs/react": "^4.2.6", + "ahooks": "^3.7.1", + "classnames": "^2.3.2", + "daisyui": "^2.42.1", + "js-search": "^2.0.0", + "less": "^4.1.3", + "lodash-es": "^4.17.21", + "pako": "^2.1.0", + "qs": "^6.11.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-hot-toast": "^2.4.0", + "react-icons": "^4.4.0", + "react-markdown": "^8.0.3", + "react-popper": "^2.3.0", + "react-redux": "^8.0.2", + "react-slider": "^2.0.4", + "remark-gfm": "^3.0.1", + "tailwind-scrollbar-hide": "^1.1.7", + "tiny-pinyin": "^1.3.2", + "tippy.js": "^6.3.7", + "uuid": "^9.0.0" + }, + "devDependencies": { + "@tailwindcss/line-clamp": "^0.4.2", + "@tailwindcss/typography": "^0.5.8", + "@types/chrome": "^0.0.203", + "@types/js-search": "^1.4.0", + "@types/lodash-es": "^4.17.6", + "@types/pako": "^2.0.0", + "@types/qs": "^6.9.7", + "@types/react": "^18.0.20", + "@types/react-dom": "^18.0.6", + "@types/react-slider": "^1.3.1", + "@types/uuid": "^8.3.4", + "@typescript-eslint/eslint-plugin": "^5.37.0", + "@typescript-eslint/parser": "^5.37.0", + "@vitejs/plugin-react": "^2.1.0", + "autoprefixer": "^10.4.13", + "eslint": "8.22.0", + "eslint-config-standard": "^17.0.0", + "eslint-config-standard-with-typescript": "^23.0.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.2.5", + "eslint-plugin-promise": "^6.0.1", + "eslint-plugin-react": "^7.31.8", + "eslint-plugin-react-hooks": "^4.6.0", + "postcss": "^8.4.19", + "rollup-plugin-visualizer": "^5.8.3", + "tailwindcss": "^3.2.4", + "typescript": "^4.8.3", + "vite": "^3.1.1" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..384fe58 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,4354 @@ +lockfileVersion: '6.0' + +dependencies: + '@crxjs/vite-plugin': + specifier: ^1.0.14 + version: 1.0.14(vite@3.1.1) + '@kky002/kky-hooks': + specifier: ^1.2.1 + version: 1.2.1 + '@kky002/kky-ui': + specifier: ^1.0.9 + version: 1.0.9 + '@kky002/kky-util': + specifier: ^1.4.2 + version: 1.4.2 + '@logto/react': + specifier: 1.0.0-beta.13 + version: 1.0.0-beta.13(react@18.2.0) + '@popperjs/core': + specifier: ^2.11.6 + version: 2.11.6 + '@reduxjs/toolkit': + specifier: ^1.8.5 + version: 1.8.5(react-redux@8.0.2)(react@18.2.0) + '@tippyjs/react': + specifier: ^4.2.6 + version: 4.2.6(react-dom@18.2.0)(react@18.2.0) + ahooks: + specifier: ^3.7.1 + version: 3.7.1(react@18.2.0) + classnames: + specifier: ^2.3.2 + version: 2.3.2 + daisyui: + specifier: ^2.42.1 + version: 2.42.1(autoprefixer@10.4.13)(postcss@8.4.19) + js-search: + specifier: ^2.0.0 + version: 2.0.0 + less: + specifier: ^4.1.3 + version: 4.1.3 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + pako: + specifier: ^2.1.0 + version: 2.1.0 + qs: + specifier: ^6.11.0 + version: 6.11.0 + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + react-hot-toast: + specifier: ^2.4.0 + version: 2.4.0(csstype@3.1.1)(react-dom@18.2.0)(react@18.2.0) + react-icons: + specifier: ^4.4.0 + version: 4.4.0(react@18.2.0) + react-markdown: + specifier: ^8.0.3 + version: 8.0.3(@types/react@18.0.20)(react@18.2.0) + react-popper: + specifier: ^2.3.0 + version: 2.3.0(@popperjs/core@2.11.6)(react-dom@18.2.0)(react@18.2.0) + react-redux: + specifier: ^8.0.2 + version: 8.0.2(@types/react-dom@18.0.6)(@types/react@18.0.20)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.0) + react-slider: + specifier: ^2.0.4 + version: 2.0.4(react@18.2.0) + remark-gfm: + specifier: ^3.0.1 + version: 3.0.1 + tailwind-scrollbar-hide: + specifier: ^1.1.7 + version: 1.1.7 + tiny-pinyin: + specifier: ^1.3.2 + version: 1.3.2 + tippy.js: + specifier: ^6.3.7 + version: 6.3.7 + uuid: + specifier: ^9.0.0 + version: 9.0.0 + +devDependencies: + '@tailwindcss/line-clamp': + specifier: ^0.4.2 + version: 0.4.2(tailwindcss@3.2.4) + '@tailwindcss/typography': + specifier: ^0.5.8 + version: 0.5.8(tailwindcss@3.2.4) + '@types/chrome': + specifier: ^0.0.203 + version: 0.0.203 + '@types/js-search': + specifier: ^1.4.0 + version: 1.4.0 + '@types/lodash-es': + specifier: ^4.17.6 + version: 4.17.6 + '@types/pako': + specifier: ^2.0.0 + version: 2.0.0 + '@types/qs': + specifier: ^6.9.7 + version: 6.9.7 + '@types/react': + specifier: ^18.0.20 + version: 18.0.20 + '@types/react-dom': + specifier: ^18.0.6 + version: 18.0.6 + '@types/react-slider': + specifier: ^1.3.1 + version: 1.3.1 + '@types/uuid': + specifier: ^8.3.4 + version: 8.3.4 + '@typescript-eslint/eslint-plugin': + specifier: ^5.37.0 + version: 5.37.0(@typescript-eslint/parser@5.37.0)(eslint@8.22.0)(typescript@4.8.3) + '@typescript-eslint/parser': + specifier: ^5.37.0 + version: 5.37.0(eslint@8.22.0)(typescript@4.8.3) + '@vitejs/plugin-react': + specifier: ^2.1.0 + version: 2.1.0(vite@3.1.1) + autoprefixer: + specifier: ^10.4.13 + version: 10.4.13(postcss@8.4.19) + eslint: + specifier: 8.22.0 + version: 8.22.0 + eslint-config-standard: + specifier: ^17.0.0 + version: 17.0.0(eslint-plugin-import@2.26.0)(eslint-plugin-n@15.2.5)(eslint-plugin-promise@6.0.1)(eslint@8.22.0) + eslint-config-standard-with-typescript: + specifier: ^23.0.0 + version: 23.0.0(@typescript-eslint/eslint-plugin@5.37.0)(eslint-plugin-import@2.26.0)(eslint-plugin-n@15.2.5)(eslint-plugin-promise@6.0.1)(eslint@8.22.0)(typescript@4.8.3) + eslint-plugin-import: + specifier: ^2.26.0 + version: 2.26.0(@typescript-eslint/parser@5.37.0)(eslint@8.22.0) + eslint-plugin-n: + specifier: ^15.2.5 + version: 15.2.5(eslint@8.22.0) + eslint-plugin-promise: + specifier: ^6.0.1 + version: 6.0.1(eslint@8.22.0) + eslint-plugin-react: + specifier: ^7.31.8 + version: 7.31.8(eslint@8.22.0) + eslint-plugin-react-hooks: + specifier: ^4.6.0 + version: 4.6.0(eslint@8.22.0) + postcss: + specifier: ^8.4.19 + version: 8.4.19 + rollup-plugin-visualizer: + specifier: ^5.8.3 + version: 5.8.3 + tailwindcss: + specifier: ^3.2.4 + version: 3.2.4(postcss@8.4.19) + typescript: + specifier: ^4.8.3 + version: 4.8.3 + vite: + specifier: ^3.1.1 + version: 3.1.1(less@4.1.3) + +packages: + + /@ampproject/remapping@2.2.0: + resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.1.1 + '@jridgewell/trace-mapping': 0.3.15 + + /@babel/code-frame@7.18.6: + resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.18.6 + + /@babel/compat-data@7.19.1: + resolution: {integrity: sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==} + engines: {node: '>=6.9.0'} + + /@babel/core@7.19.1: + resolution: {integrity: sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.0 + '@babel/code-frame': 7.18.6 + '@babel/generator': 7.19.0 + '@babel/helper-compilation-targets': 7.19.1(@babel/core@7.19.1) + '@babel/helper-module-transforms': 7.19.0 + '@babel/helpers': 7.19.0 + '@babel/parser': 7.19.1 + '@babel/template': 7.18.10 + '@babel/traverse': 7.19.1 + '@babel/types': 7.19.0 + convert-source-map: 1.8.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.1 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + + /@babel/generator@7.19.0: + resolution: {integrity: sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.19.0 + '@jridgewell/gen-mapping': 0.3.2 + jsesc: 2.5.2 + + /@babel/helper-annotate-as-pure@7.18.6: + resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.19.0 + + /@babel/helper-compilation-targets@7.19.1(@babel/core@7.19.1): + resolution: {integrity: sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/compat-data': 7.19.1 + '@babel/core': 7.19.1 + '@babel/helper-validator-option': 7.18.6 + browserslist: 4.21.3 + semver: 6.3.0 + + /@babel/helper-environment-visitor@7.18.9: + resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} + engines: {node: '>=6.9.0'} + + /@babel/helper-function-name@7.19.0: + resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.18.10 + '@babel/types': 7.19.0 + + /@babel/helper-hoist-variables@7.18.6: + resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.19.0 + + /@babel/helper-module-imports@7.18.6: + resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.19.0 + + /@babel/helper-module-transforms@7.19.0: + resolution: {integrity: sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-module-imports': 7.18.6 + '@babel/helper-simple-access': 7.18.6 + '@babel/helper-split-export-declaration': 7.18.6 + '@babel/helper-validator-identifier': 7.19.1 + '@babel/template': 7.18.10 + '@babel/traverse': 7.19.1 + '@babel/types': 7.19.0 + transitivePeerDependencies: + - supports-color + + /@babel/helper-plugin-utils@7.19.0: + resolution: {integrity: sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==} + engines: {node: '>=6.9.0'} + + /@babel/helper-simple-access@7.18.6: + resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.19.0 + + /@babel/helper-split-export-declaration@7.18.6: + resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.19.0 + + /@babel/helper-string-parser@7.18.10: + resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier@7.19.1: + resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-option@7.18.6: + resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} + engines: {node: '>=6.9.0'} + + /@babel/helpers@7.19.0: + resolution: {integrity: sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.18.10 + '@babel/traverse': 7.19.1 + '@babel/types': 7.19.0 + transitivePeerDependencies: + - supports-color + + /@babel/highlight@7.18.6: + resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.19.1 + chalk: 2.4.2 + js-tokens: 4.0.0 + + /@babel/parser@7.19.1: + resolution: {integrity: sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.19.0 + + /@babel/plugin-syntax-jsx@7.18.6(@babel/core@7.19.1): + resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.19.1 + '@babel/helper-plugin-utils': 7.19.0 + + /@babel/plugin-transform-react-jsx-development@7.18.6(@babel/core@7.19.1): + resolution: {integrity: sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.19.1 + '@babel/plugin-transform-react-jsx': 7.19.0(@babel/core@7.19.1) + + /@babel/plugin-transform-react-jsx-self@7.18.6(@babel/core@7.19.1): + resolution: {integrity: sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.19.1 + '@babel/helper-plugin-utils': 7.19.0 + + /@babel/plugin-transform-react-jsx-source@7.18.6(@babel/core@7.19.1): + resolution: {integrity: sha512-utZmlASneDfdaMh0m/WausbjUjEdGrQJz0vFK93d7wD3xf5wBtX219+q6IlCNZeguIcxS2f/CvLZrlLSvSHQXw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.19.1 + '@babel/helper-plugin-utils': 7.19.0 + + /@babel/plugin-transform-react-jsx@7.19.0(@babel/core@7.19.1): + resolution: {integrity: sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.19.1 + '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/helper-module-imports': 7.18.6 + '@babel/helper-plugin-utils': 7.19.0 + '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.19.1) + '@babel/types': 7.19.0 + + /@babel/runtime@7.19.0: + resolution: {integrity: sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.13.9 + dev: false + + /@babel/template@7.18.10: + resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.18.6 + '@babel/parser': 7.19.1 + '@babel/types': 7.19.0 + + /@babel/traverse@7.19.1: + resolution: {integrity: sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.18.6 + '@babel/generator': 7.19.0 + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-function-name': 7.19.0 + '@babel/helper-hoist-variables': 7.18.6 + '@babel/helper-split-export-declaration': 7.18.6 + '@babel/parser': 7.19.1 + '@babel/types': 7.19.0 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + /@babel/types@7.19.0: + resolution: {integrity: sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.18.10 + '@babel/helper-validator-identifier': 7.19.1 + to-fast-properties: 2.0.0 + + /@crxjs/vite-plugin@1.0.14(vite@3.1.1): + resolution: {integrity: sha512-emOueVCqFRFmpcfT80Xsm4mfuFw9VSp5GY4eh5qeLDeiP81g0hddlobVQCo0pE2ZvNnWbyhLrXEYAaMAXjNL6A==} + engines: {node: '>=14'} + peerDependencies: + vite: ^2.9.0 + dependencies: + '@rollup/pluginutils': 4.2.1 + '@webcomponents/custom-elements': 1.5.1 + acorn-walk: 8.2.0 + cheerio: 1.0.0-rc.12 + connect-injector: 0.4.4 + debug: 4.3.4 + es-module-lexer: 0.10.5 + fast-glob: 3.2.12 + fs-extra: 10.1.0 + jsesc: 3.0.2 + magic-string: 0.26.3 + picocolors: 1.0.0 + react-refresh: 0.13.0 + rollup: 2.78.1 + vite: 3.1.1(less@4.1.3) + optionalDependencies: + '@vitejs/plugin-react': 2.1.0(vite@3.1.1) + transitivePeerDependencies: + - supports-color + dev: false + + /@esbuild/linux-loong64@0.15.7: + resolution: {integrity: sha512-IKznSJOsVUuyt7cDzzSZyqBEcZe+7WlBqTVXiF1OXP/4Nm387ToaXZ0fyLwI1iBlI/bzpxVq411QE2/Bt2XWWw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + optional: true + + /@eslint/eslintrc@1.3.2: + resolution: {integrity: sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.4.0 + globals: 13.17.0 + ignore: 5.2.0 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/config-array@0.10.4: + resolution: {integrity: sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/gitignore-to-minimatch@1.0.2: + resolution: {integrity: sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==} + dev: true + + /@humanwhocodes/object-schema@1.2.1: + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + dev: true + + /@jridgewell/gen-mapping@0.1.1: + resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.14 + + /@jridgewell/gen-mapping@0.3.2: + resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/trace-mapping': 0.3.15 + + /@jridgewell/resolve-uri@3.1.0: + resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} + engines: {node: '>=6.0.0'} + + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + + /@jridgewell/sourcemap-codec@1.4.14: + resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + + /@jridgewell/trace-mapping@0.3.15: + resolution: {integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==} + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + + /@kky002/kky-hooks@1.2.1: + resolution: {integrity: sha512-AJM2gm75TtkZqOPd/WX0+4h/dfjSb8HlDQLwAJsYIHRNw8MQUKu32Ih6OxhKL2l9pdPsuj+S9/lBc4Cwu4tP+Q==} + dependencies: + '@kky002/kky-util': 1.4.2 + ahooks: 3.7.5(react@18.2.0) + lodash-es: 4.17.21 + react: 18.2.0 + dev: false + + /@kky002/kky-ui@1.0.9: + resolution: {integrity: sha512-pepfRcLfC1eIQ1lsSJLWNr4PgdLqFLuvQMlitJy7W668yZ7qu8yAHSjg8A20R7HB4mFkJ+B96WETalOar1e/kA==} + dependencies: + react: 18.2.0 + dev: false + + /@kky002/kky-util@1.4.2: + resolution: {integrity: sha512-gpZHWuCBBgYV1rnZ07FhriCR7x2228LOnf6PI6nyfWXxYYy1RQ8MZcdegbBsi/HRmh7EsW1yPqq85pwNLX0B9w==} + dependencies: + lodash-es: 4.17.21 + qs: 6.11.0 + dev: false + + /@logto/browser@1.0.0-beta.13: + resolution: {integrity: sha512-ddAVggFcbS9yfG8Gvn2xknE2NZd6+lGxOQ6UbjIJKsYBAsJG95u1ITYaP7tNSDdxqZPmSBGXp4rfsQB+u0JPJQ==} + dependencies: + '@logto/client': 1.0.0-beta.13 + '@silverhand/essentials': 1.3.0 + js-base64: 3.7.2 + dev: false + + /@logto/client@1.0.0-beta.13: + resolution: {integrity: sha512-ddHILkcBW92p4x/TfUGqT3WXZzX14xgLd6lZZsoCgNZ9QWS7Jw+NsT/knJs96cd2A/jv9RZIGzh1g6+zlox7bw==} + dependencies: + '@logto/core-kit': 1.0.0-beta.20 + '@logto/js': 1.0.0-beta.13 + '@silverhand/essentials': 1.3.0 + camelcase-keys: 7.0.2 + jose: 4.10.4 + lodash.get: 4.4.2 + lodash.once: 4.1.1 + dev: false + + /@logto/core-kit@1.0.0-beta.20: + resolution: {integrity: sha512-seYvL/aGYRfO4d0FYfKIW/Cu9PnFMRpRM5/oRXwXbcbv+LY1a3TcAX0itrVXeBygIrxiAmWd9DL7CGIWzb48Qg==} + engines: {node: ^16.0.0} + dependencies: + '@logto/language-kit': 1.0.0-beta.20 + color: 4.2.3 + nanoid: 3.3.4 + zod: 3.19.1 + dev: false + + /@logto/js@1.0.0-beta.13: + resolution: {integrity: sha512-a3dhoJre/VOXgGxFNon/xY5E4fVs0CiFW5Ci0gt2W7v2zD/1VmzIvcJnECTLocxyz9W2UTkfYzm7q/iXF48WXw==} + dependencies: + '@logto/core-kit': 1.0.0-beta.20 + '@silverhand/essentials': 1.3.0 + camelcase-keys: 7.0.2 + jose: 4.10.4 + lodash.get: 4.4.2 + dev: false + + /@logto/language-kit@1.0.0-beta.20: + resolution: {integrity: sha512-nBqWQo2xGAlVcD9O/txpCzRyy7eKXNXBAHm8J1y/u5Fp3BMObMmJv+v4Zk+UhckdFpsnFJF0wYIX45ta2+IipA==} + engines: {node: ^16.0.0} + dependencies: + zod: 3.19.1 + dev: false + + /@logto/react@1.0.0-beta.13(react@18.2.0): + resolution: {integrity: sha512-jG7rXm5aW/aJ+RN9Rw8tEo4c/12LzO99qt8eZ39xFWfMB+g06/rmxPZGMMkkqaNexhE2KLr4cASYeOafTR8wwQ==} + peerDependencies: + react: '>=16.8.0' + dependencies: + '@logto/browser': 1.0.0-beta.13 + '@silverhand/essentials': 1.3.0 + react: 18.2.0 + dev: false + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.13.0 + + /@popperjs/core@2.11.6: + resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==} + dev: false + + /@reduxjs/toolkit@1.8.5(react-redux@8.0.2)(react@18.2.0): + resolution: {integrity: sha512-f4D5EXO7A7Xq35T0zRbWq5kJQyXzzscnHKmjnu2+37B3rwHU6mX9PYlbfXdnxcY6P/7zfmjhgan0Z+yuOfeBmA==} + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 + react-redux: ^7.2.1 || ^8.0.2 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + dependencies: + immer: 9.0.16 + react: 18.2.0 + react-redux: 8.0.2(@types/react-dom@18.0.6)(@types/react@18.0.20)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.0) + redux: 4.2.0 + redux-thunk: 2.4.1(redux@4.2.0) + reselect: 4.1.6 + dev: false + + /@rollup/pluginutils@4.2.1: + resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} + engines: {node: '>= 8.0.0'} + dependencies: + estree-walker: 2.0.2 + picomatch: 2.3.1 + dev: false + + /@silverhand/essentials@1.3.0: + resolution: {integrity: sha512-o3cAqwLkKxmv+HCEQfNMpyxrdmv+9Tz69WXB/P2LdzS2ggU6tcOXbxkCMv8K6b0UnGN/PckQSykM7pHnDZZN6w==} + engines: {node: '>=14.15.0', pnpm: '>=6'} + dependencies: + lodash.orderby: 4.6.0 + lodash.pick: 4.4.0 + dev: false + + /@tailwindcss/line-clamp@0.4.2(tailwindcss@3.2.4): + resolution: {integrity: sha512-HFzAQuqYCjyy/SX9sLGB1lroPzmcnWv1FHkIpmypte10hptf4oPUfucryMKovZh2u0uiS9U5Ty3GghWfEJGwVw==} + peerDependencies: + tailwindcss: '>=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1' + dependencies: + tailwindcss: 3.2.4(postcss@8.4.19) + dev: true + + /@tailwindcss/typography@0.5.8(tailwindcss@3.2.4): + resolution: {integrity: sha512-xGQEp8KXN8Sd8m6R4xYmwxghmswrd0cPnNI2Lc6fmrC3OojysTBJJGSIVwPV56q4t6THFUK3HJ0EaWwpglSxWw==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + postcss-selector-parser: 6.0.10 + tailwindcss: 3.2.4(postcss@8.4.19) + dev: true + + /@tippyjs/react@4.2.6(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-91RicDR+H7oDSyPycI13q3b7o4O60wa2oRbjlz2fyRLmHImc4vyDwuUP8NtZaN0VARJY5hybvDYrFzhY9+Lbyw==} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tippy.js: 6.3.7 + dev: false + + /@types/chrome@0.0.203: + resolution: {integrity: sha512-JlQNebwpBETVc8U1Rr2inDFuOTtn0lahRAhnddx1dd0S5RrLAFJEEsyIu7AXI14mkCgSunksnuLGioH8kvBqRA==} + dependencies: + '@types/filesystem': 0.0.32 + '@types/har-format': 1.2.8 + dev: true + + /@types/debug@4.1.7: + resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} + dependencies: + '@types/ms': 0.7.31 + dev: false + + /@types/filesystem@0.0.32: + resolution: {integrity: sha512-Yuf4jR5YYMR2DVgwuCiP11s0xuVRyPKmz8vo6HBY3CGdeMj8af93CFZX+T82+VD1+UqHOxTq31lO7MI7lepBtQ==} + dependencies: + '@types/filewriter': 0.0.29 + dev: true + + /@types/filewriter@0.0.29: + resolution: {integrity: sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ==} + dev: true + + /@types/har-format@1.2.8: + resolution: {integrity: sha512-OP6L9VuZNdskgNN3zFQQ54ceYD8OLq5IbqO4VK91ORLfOm7WdT/CiT/pHEBSQEqCInJ2y3O6iCm/zGtPElpgJQ==} + dev: true + + /@types/hast@2.3.4: + resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==} + dependencies: + '@types/unist': 2.0.6 + dev: false + + /@types/hoist-non-react-statics@3.3.1: + resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==} + dependencies: + '@types/react': 18.0.20 + hoist-non-react-statics: 3.3.2 + dev: false + + /@types/js-cookie@2.2.7: + resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==} + dev: false + + /@types/js-search@1.4.0: + resolution: {integrity: sha512-OMDWvQP2AmxpQI9vFh7U/TzExNGB9Sj9WQCoxUR8VXZEv6jM4cyNzLODkh1gkBHJ9Er7kdasChzEpba4FxLGaA==} + dev: true + + /@types/json-schema@7.0.11: + resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + dev: true + + /@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + dev: true + + /@types/lodash-es@4.17.6: + resolution: {integrity: sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==} + dependencies: + '@types/lodash': 4.14.185 + dev: true + + /@types/lodash@4.14.185: + resolution: {integrity: sha512-evMDG1bC4rgQg4ku9tKpuMh5iBNEwNa3tf9zRHdP1qlv+1WUg44xat4IxCE14gIpZRGUUWAx2VhItCZc25NfMA==} + dev: true + + /@types/mdast@3.0.10: + resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==} + dependencies: + '@types/unist': 2.0.6 + dev: false + + /@types/ms@0.7.31: + resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} + dev: false + + /@types/pako@2.0.0: + resolution: {integrity: sha512-10+iaz93qR5WYxTo+PMifD5TSxiOtdRaxBf7INGGXMQgTCu8Z/7GYWYFUOS3q/G0nE5boj1r4FEB+WSy7s5gbA==} + dev: true + + /@types/prop-types@15.7.5: + resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} + + /@types/qs@6.9.7: + resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} + dev: true + + /@types/react-dom@18.0.6: + resolution: {integrity: sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==} + dependencies: + '@types/react': 18.0.20 + + /@types/react-slider@1.3.1: + resolution: {integrity: sha512-4X2yK7RyCIy643YCFL+bc6XNmcnBtt8n88uuyihvcn5G7Lut23eNQU3q3KmwF7MWIfKfsW5NxCjw0SeDZRtgaA==} + dependencies: + '@types/react': 18.0.20 + dev: true + + /@types/react@18.0.20: + resolution: {integrity: sha512-MWul1teSPxujEHVwZl4a5HxQ9vVNsjTchVA+xRqv/VYGCuKGAU6UhfrTdF5aBefwD1BHUD8i/zq+O/vyCm/FrA==} + dependencies: + '@types/prop-types': 15.7.5 + '@types/scheduler': 0.16.2 + csstype: 3.1.1 + + /@types/scheduler@0.16.2: + resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} + + /@types/unist@2.0.6: + resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} + dev: false + + /@types/use-sync-external-store@0.0.3: + resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==} + dev: false + + /@types/uuid@8.3.4: + resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} + dev: true + + /@typescript-eslint/eslint-plugin@5.37.0(@typescript-eslint/parser@5.37.0)(eslint@8.22.0)(typescript@4.8.3): + resolution: {integrity: sha512-Fde6W0IafXktz1UlnhGkrrmnnGpAo1kyX7dnyHHVrmwJOn72Oqm3eYtddrpOwwel2W8PAK9F3pIL5S+lfoM0og==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/parser': 5.37.0(eslint@8.22.0)(typescript@4.8.3) + '@typescript-eslint/scope-manager': 5.37.0 + '@typescript-eslint/type-utils': 5.37.0(eslint@8.22.0)(typescript@4.8.3) + '@typescript-eslint/utils': 5.37.0(eslint@8.22.0)(typescript@4.8.3) + debug: 4.3.4 + eslint: 8.22.0 + functional-red-black-tree: 1.0.1 + ignore: 5.2.0 + regexpp: 3.2.0 + semver: 7.3.7 + tsutils: 3.21.0(typescript@4.8.3) + typescript: 4.8.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@5.37.0(eslint@8.22.0)(typescript@4.8.3): + resolution: {integrity: sha512-01VzI/ipYKuaG5PkE5+qyJ6m02fVALmMPY3Qq5BHflDx3y4VobbLdHQkSMg9VPRS4KdNt4oYTMaomFoHonBGAw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.37.0 + '@typescript-eslint/types': 5.37.0 + '@typescript-eslint/typescript-estree': 5.37.0(typescript@4.8.3) + debug: 4.3.4 + eslint: 8.22.0 + typescript: 4.8.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@5.37.0: + resolution: {integrity: sha512-F67MqrmSXGd/eZnujjtkPgBQzgespu/iCZ+54Ok9X5tALb9L2v3G+QBSoWkXG0p3lcTJsL+iXz5eLUEdSiJU9Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.37.0 + '@typescript-eslint/visitor-keys': 5.37.0 + dev: true + + /@typescript-eslint/type-utils@5.37.0(eslint@8.22.0)(typescript@4.8.3): + resolution: {integrity: sha512-BSx/O0Z0SXOF5tY0bNTBcDEKz2Ec20GVYvq/H/XNKiUorUFilH7NPbFUuiiyzWaSdN3PA8JV0OvYx0gH/5aFAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 5.37.0(typescript@4.8.3) + '@typescript-eslint/utils': 5.37.0(eslint@8.22.0)(typescript@4.8.3) + debug: 4.3.4 + eslint: 8.22.0 + tsutils: 3.21.0(typescript@4.8.3) + typescript: 4.8.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@5.37.0: + resolution: {integrity: sha512-3frIJiTa5+tCb2iqR/bf7XwU20lnU05r/sgPJnRpwvfZaqCJBrl8Q/mw9vr3NrNdB/XtVyMA0eppRMMBqdJ1bA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@typescript-eslint/typescript-estree@5.37.0(typescript@4.8.3): + resolution: {integrity: sha512-JkFoFIt/cx59iqEDSgIGnQpCTRv96MQnXCYvJi7QhBC24uyuzbD8wVbajMB1b9x4I0octYFJ3OwjAwNqk1AjDA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.37.0 + '@typescript-eslint/visitor-keys': 5.37.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.7 + tsutils: 3.21.0(typescript@4.8.3) + typescript: 4.8.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@5.37.0(eslint@8.22.0)(typescript@4.8.3): + resolution: {integrity: sha512-jUEJoQrWbZhmikbcWSMDuUSxEE7ID2W/QCV/uz10WtQqfOuKZUqFGjqLJ+qhDd17rjgp+QJPqTdPIBWwoob2NQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@types/json-schema': 7.0.11 + '@typescript-eslint/scope-manager': 5.37.0 + '@typescript-eslint/types': 5.37.0 + '@typescript-eslint/typescript-estree': 5.37.0(typescript@4.8.3) + eslint: 8.22.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0(eslint@8.22.0) + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@5.37.0: + resolution: {integrity: sha512-Hp7rT4cENBPIzMwrlehLW/28EVCOcE9U1Z1BQTc8EA8v5qpr7GRGuG+U58V5tTY48zvUOA3KHvw3rA8tY9fbdA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.37.0 + eslint-visitor-keys: 3.3.0 + dev: true + + /@vitejs/plugin-react@2.1.0(vite@3.1.1): + resolution: {integrity: sha512-am6rPyyU3LzUYne3Gd9oj9c4Rzbq5hQnuGXSMT6Gujq45Il/+bunwq3lrB7wghLkiF45ygMwft37vgJ/NE8IAA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^3.0.0 + dependencies: + '@babel/core': 7.19.1 + '@babel/plugin-transform-react-jsx': 7.19.0(@babel/core@7.19.1) + '@babel/plugin-transform-react-jsx-development': 7.18.6(@babel/core@7.19.1) + '@babel/plugin-transform-react-jsx-self': 7.18.6(@babel/core@7.19.1) + '@babel/plugin-transform-react-jsx-source': 7.18.6(@babel/core@7.19.1) + magic-string: 0.26.3 + react-refresh: 0.14.0 + vite: 3.1.1(less@4.1.3) + transitivePeerDependencies: + - supports-color + + /@webcomponents/custom-elements@1.5.1: + resolution: {integrity: sha512-6T/XT3S1UHDlRWFSxRXdeSoYWczEl78sygNPS7jDyHVrfZcF/pUtWGYgxF4uviH59iPVw1eOWbhubm8CqO0MpA==} + dev: false + + /acorn-jsx@5.3.2(acorn@8.8.0): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.8.0 + dev: true + + /acorn-node@1.8.2: + resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==} + dependencies: + acorn: 7.4.1 + acorn-walk: 7.2.0 + xtend: 4.0.2 + + /acorn-walk@7.2.0: + resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} + engines: {node: '>=0.4.0'} + + /acorn-walk@8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + dev: false + + /acorn@7.4.1: + resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} + engines: {node: '>=0.4.0'} + hasBin: true + + /acorn@8.8.0: + resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /ahooks-v3-count@1.0.0: + resolution: {integrity: sha512-V7uUvAwnimu6eh/PED4mCDjE7tokeZQLKlxg9lCTMPhN+NjsSbtdacByVlR1oluXQzD3MOw55wylDmQo4+S9ZQ==} + dev: false + + /ahooks@3.7.1(react@18.2.0): + resolution: {integrity: sha512-9fooKjhScNyJaIPnlWd13LkY1gQYqv3BqwSA9ynHg1ZUtDqAICuCRoedV97ylrEL6QqI4zeq3bO3lQxkfWVNcg==} + engines: {node: '>=8.0.0'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@types/js-cookie': 2.2.7 + ahooks-v3-count: 1.0.0 + dayjs: 1.11.5 + intersection-observer: 0.12.2 + js-cookie: 2.2.1 + lodash: 4.17.21 + react: 18.2.0 + resize-observer-polyfill: 1.5.1 + screenfull: 5.2.0 + dev: false + + /ahooks@3.7.5(react@18.2.0): + resolution: {integrity: sha512-RWkJYK5xj9ZXROj9jABRDqdpTBimkY1tlyeJQ8Ci7MAl1sC5xzSzwO20ydk6BjtdbWt56DPCYZhq4lGu3O2Zwg==} + engines: {node: '>=8.0.0'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@types/js-cookie': 2.2.7 + ahooks-v3-count: 1.0.0 + dayjs: 1.11.5 + intersection-observer: 0.12.2 + js-cookie: 2.2.1 + lodash: 4.17.21 + react: 18.2.0 + resize-observer-polyfill: 1.5.1 + screenfull: 5.2.0 + tslib: 2.5.0 + dev: false + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /anymatch@3.1.2: + resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + /arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-includes@3.1.5: + resolution: {integrity: sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.2 + get-intrinsic: 1.1.3 + is-string: 1.0.7 + dev: true + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /array.prototype.flat@1.3.0: + resolution: {integrity: sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.2 + es-shim-unscopables: 1.0.0 + dev: true + + /array.prototype.flatmap@1.3.0: + resolution: {integrity: sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.2 + es-shim-unscopables: 1.0.0 + dev: true + + /autoprefixer@10.4.13(postcss@8.4.19): + resolution: {integrity: sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.21.4 + caniuse-lite: 1.0.30001431 + fraction.js: 4.2.0 + normalize-range: 0.1.2 + picocolors: 1.0.0 + postcss: 8.4.19 + postcss-value-parser: 4.2.0 + + /bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + dev: false + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + + /boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: false + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + + /browserslist@4.21.3: + resolution: {integrity: sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001400 + electron-to-chromium: 1.4.251 + node-releases: 2.0.6 + update-browserslist-db: 1.0.9(browserslist@4.21.3) + + /browserslist@4.21.4: + resolution: {integrity: sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001431 + electron-to-chromium: 1.4.251 + node-releases: 2.0.6 + update-browserslist-db: 1.0.9(browserslist@4.21.4) + + /builtins@5.0.1: + resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==} + dependencies: + semver: 7.3.7 + dev: true + + /call-bind@1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.1.3 + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + /camelcase-keys@7.0.2: + resolution: {integrity: sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==} + engines: {node: '>=12'} + dependencies: + camelcase: 6.3.0 + map-obj: 4.3.0 + quick-lru: 5.1.1 + type-fest: 1.4.0 + dev: false + + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: false + + /caniuse-lite@1.0.30001400: + resolution: {integrity: sha512-Mv659Hn65Z4LgZdJ7ge5JTVbE3rqbJaaXgW5LEI9/tOaXclfIZ8DW7D7FCWWWmWiiPS7AC48S8kf3DApSxQdgA==} + + /caniuse-lite@1.0.30001431: + resolution: {integrity: sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==} + + /ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + dev: false + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + dev: false + + /cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + dependencies: + boolbase: 1.0.0 + css-select: 5.1.0 + css-what: 6.1.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.0.1 + dev: false + + /cheerio@1.0.0-rc.12: + resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} + engines: {node: '>= 6'} + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.0.1 + htmlparser2: 8.0.1 + parse5: 7.1.2 + parse5-htmlparser2-tree-adapter: 7.0.0 + dev: false + + /chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.2 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.2 + + /classnames@2.3.2: + resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==} + dev: false + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + /color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + dev: false + + /color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + dev: false + + /comma-separated-tokens@2.0.2: + resolution: {integrity: sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==} + dev: false + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /connect-injector@0.4.4: + resolution: {integrity: sha512-hdBG8nXop42y2gWCqOV8y1O3uVk4cIU+SoxLCPyCUKRImyPiScoNiSulpHjoktRU1BdI0UzoUdxUa87thrcmHw==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 2.6.9 + q: 1.5.1 + stream-buffers: 0.2.6 + uberproto: 1.2.0 + transitivePeerDependencies: + - supports-color + dev: false + + /convert-source-map@1.8.0: + resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} + dependencies: + safe-buffer: 5.1.2 + + /copy-anything@2.0.6: + resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} + dependencies: + is-what: 3.14.1 + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.0.1 + nth-check: 2.1.1 + dev: false + + /css-selector-tokenizer@0.8.0: + resolution: {integrity: sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==} + dependencies: + cssesc: 3.0.0 + fastparse: 1.1.2 + dev: false + + /css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + dev: false + + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + /csstype@3.1.1: + resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} + + /daisyui@2.42.1(autoprefixer@10.4.13)(postcss@8.4.19): + resolution: {integrity: sha512-IVeEvP8gvOzHR47fMrOp2YocQJMRmYskhdt7OsuhKJNn+YzLRGOpVpY7AGXt/56pYeYy7h03THHXRTW5cVU9rQ==} + peerDependencies: + autoprefixer: ^10.0.2 + postcss: ^8.1.6 + dependencies: + autoprefixer: 10.4.13(postcss@8.4.19) + color: 4.2.3 + css-selector-tokenizer: 0.8.0 + postcss: 8.4.19 + postcss-js: 4.0.0(postcss@8.4.19) + tailwindcss: 3.2.4(postcss@8.4.19) + transitivePeerDependencies: + - ts-node + dev: false + + /dayjs@1.11.5: + resolution: {integrity: sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==} + dev: false + + /debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + + /decode-named-character-reference@1.0.2: + resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} + dependencies: + character-entities: 2.0.2 + dev: false + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + dev: true + + /define-properties@1.1.4: + resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} + engines: {node: '>= 0.4'} + dependencies: + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 + dev: true + + /defined@1.0.1: + resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==} + + /dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + dev: false + + /detective@5.2.1: + resolution: {integrity: sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==} + engines: {node: '>=0.8.0'} + hasBin: true + dependencies: + acorn-node: 1.8.2 + defined: 1.0.1 + minimist: 1.2.6 + + /didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + /diff@5.1.0: + resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} + engines: {node: '>=0.3.1'} + dev: false + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + /doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.4.0 + dev: false + + /domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: false + + /domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: false + + /domutils@3.0.1: + resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: false + + /electron-to-chromium@1.4.251: + resolution: {integrity: sha512-k4o4cFrWPv4SoJGGAydd07GmlRVzmeDIJ6MaEChTUjk4Dmomn189tCicSzil2oyvbPoGgg2suwPDNWq4gWRhoQ==} + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /entities@4.4.0: + resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} + engines: {node: '>=0.12'} + dev: false + + /errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + requiresBuild: true + dependencies: + prr: 1.0.1 + optional: true + + /es-abstract@1.20.2: + resolution: {integrity: sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + es-to-primitive: 1.2.1 + function-bind: 1.1.1 + function.prototype.name: 1.1.5 + get-intrinsic: 1.1.3 + get-symbol-description: 1.0.0 + has: 1.0.3 + has-property-descriptors: 1.0.0 + has-symbols: 1.0.3 + internal-slot: 1.0.3 + is-callable: 1.2.6 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-weakref: 1.0.2 + object-inspect: 1.12.2 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.4.3 + string.prototype.trimend: 1.0.5 + string.prototype.trimstart: 1.0.5 + unbox-primitive: 1.0.2 + dev: true + + /es-module-lexer@0.10.5: + resolution: {integrity: sha512-+7IwY/kiGAacQfY+YBhKMvEmyAJnw5grTUgjG85Pe7vcUI/6b7pZjZG8nQ7+48YhzEAEqrEgD2dCz/JIK+AYvw==} + dev: false + + /es-shim-unscopables@1.0.0: + resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} + dependencies: + has: 1.0.3 + dev: true + + /es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.6 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + dev: true + + /esbuild-android-64@0.15.7: + resolution: {integrity: sha512-p7rCvdsldhxQr3YHxptf1Jcd86dlhvc3EQmQJaZzzuAxefO9PvcI0GLOa5nCWem1AJ8iMRu9w0r5TG8pHmbi9w==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + optional: true + + /esbuild-android-arm64@0.15.7: + resolution: {integrity: sha512-L775l9ynJT7rVqRM5vo+9w5g2ysbOCfsdLV4CWanTZ1k/9Jb3IYlQ06VCI1edhcosTYJRECQFJa3eAvkx72eyQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + optional: true + + /esbuild-darwin-64@0.15.7: + resolution: {integrity: sha512-KGPt3r1c9ww009t2xLB6Vk0YyNOXh7hbjZ3EecHoVDxgtbUlYstMPDaReimKe6eOEfyY4hBEEeTvKwPsiH5WZg==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true + + /esbuild-darwin-arm64@0.15.7: + resolution: {integrity: sha512-kBIHvtVqbSGajN88lYMnR3aIleH3ABZLLFLxwL2stiuIGAjGlQW741NxVTpUHQXUmPzxi6POqc9npkXa8AcSZQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optional: true + + /esbuild-freebsd-64@0.15.7: + resolution: {integrity: sha512-hESZB91qDLV5MEwNxzMxPfbjAhOmtfsr9Wnuci7pY6TtEh4UDuevmGmkUIjX/b+e/k4tcNBMf7SRQ2mdNuK/HQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + optional: true + + /esbuild-freebsd-arm64@0.15.7: + resolution: {integrity: sha512-dLFR0ChH5t+b3J8w0fVKGvtwSLWCv7GYT2Y2jFGulF1L5HftQLzVGN+6pi1SivuiVSmTh28FwUhi9PwQicXI6Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + optional: true + + /esbuild-linux-32@0.15.7: + resolution: {integrity: sha512-v3gT/LsONGUZcjbt2swrMjwxo32NJzk+7sAgtxhGx1+ZmOFaTRXBAi1PPfgpeo/J//Un2jIKm/I+qqeo4caJvg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + optional: true + + /esbuild-linux-64@0.15.7: + resolution: {integrity: sha512-LxXEfLAKwOVmm1yecpMmWERBshl+Kv5YJ/1KnyAr6HRHFW8cxOEsEfisD3sVl/RvHyW//lhYUVSuy9jGEfIRAQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /esbuild-linux-arm64@0.15.7: + resolution: {integrity: sha512-P3cfhudpzWDkglutWgXcT2S7Ft7o2e3YDMrP1n0z2dlbUZghUkKCyaWw0zhp4KxEEzt/E7lmrtRu/pGWnwb9vw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /esbuild-linux-arm@0.15.7: + resolution: {integrity: sha512-JKgAHtMR5f75wJTeuNQbyznZZa+pjiUHV7sRZp42UNdyXC6TiUYMW/8z8yIBAr2Fpad8hM1royZKQisqPABPvQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + optional: true + + /esbuild-linux-mips64le@0.15.7: + resolution: {integrity: sha512-T7XKuxl0VpeFLCJXub6U+iybiqh0kM/bWOTb4qcPyDDwNVhLUiPcGdG2/0S7F93czUZOKP57YiLV8YQewgLHKw==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + optional: true + + /esbuild-linux-ppc64le@0.15.7: + resolution: {integrity: sha512-6mGuC19WpFN7NYbecMIJjeQgvDb5aMuvyk0PDYBJrqAEMkTwg3Z98kEKuCm6THHRnrgsdr7bp4SruSAxEM4eJw==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + optional: true + + /esbuild-linux-riscv64@0.15.7: + resolution: {integrity: sha512-uUJsezbswAYo/X7OU/P+PuL/EI9WzxsEQXDekfwpQ23uGiooxqoLFAPmXPcRAt941vjlY9jtITEEikWMBr+F/g==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + optional: true + + /esbuild-linux-s390x@0.15.7: + resolution: {integrity: sha512-+tO+xOyTNMc34rXlSxK7aCwJgvQyffqEM5MMdNDEeMU3ss0S6wKvbBOQfgd5jRPblfwJ6b+bKiz0g5nABpY0QQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + optional: true + + /esbuild-netbsd-64@0.15.7: + resolution: {integrity: sha512-yVc4Wz+Pu3cP5hzm5kIygNPrjar/v5WCSoRmIjCPWfBVJkZNb5brEGKUlf+0Y759D48BCWa0WHrWXaNy0DULTQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + optional: true + + /esbuild-openbsd-64@0.15.7: + resolution: {integrity: sha512-GsimbwC4FSR4lN3wf8XmTQ+r8/0YSQo21rWDL0XFFhLHKlzEA4SsT1Tl8bPYu00IU6UWSJ+b3fG/8SB69rcuEQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + optional: true + + /esbuild-sunos-64@0.15.7: + resolution: {integrity: sha512-8CDI1aL/ts0mDGbWzjEOGKXnU7p3rDzggHSBtVryQzkSOsjCHRVe0iFYUuhczlxU1R3LN/E7HgUO4NXzGGP/Ag==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + optional: true + + /esbuild-windows-32@0.15.7: + resolution: {integrity: sha512-cOnKXUEPS8EGCzRSFa1x6NQjGhGsFlVgjhqGEbLTPsA7x4RRYiy2RKoArNUU4iR2vHmzqS5Gr84MEumO/wxYKA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + optional: true + + /esbuild-windows-64@0.15.7: + resolution: {integrity: sha512-7MI08Ec2sTIDv+zH6StNBKO+2hGUYIT42GmFyW6MBBWWtJhTcQLinKS6ldIN1d52MXIbiJ6nXyCJ+LpL4jBm3Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + optional: true + + /esbuild-windows-arm64@0.15.7: + resolution: {integrity: sha512-R06nmqBlWjKHddhRJYlqDd3Fabx9LFdKcjoOy08YLimwmsswlFBJV4rXzZCxz/b7ZJXvrZgj8DDv1ewE9+StMw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + optional: true + + /esbuild@0.15.7: + resolution: {integrity: sha512-7V8tzllIbAQV1M4QoE52ImKu8hT/NLGlGXkiDsbEU5PS6K8Mn09ZnYoS+dcmHxOS9CRsV4IRAMdT3I67IyUNXw==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/linux-loong64': 0.15.7 + esbuild-android-64: 0.15.7 + esbuild-android-arm64: 0.15.7 + esbuild-darwin-64: 0.15.7 + esbuild-darwin-arm64: 0.15.7 + esbuild-freebsd-64: 0.15.7 + esbuild-freebsd-arm64: 0.15.7 + esbuild-linux-32: 0.15.7 + esbuild-linux-64: 0.15.7 + esbuild-linux-arm: 0.15.7 + esbuild-linux-arm64: 0.15.7 + esbuild-linux-mips64le: 0.15.7 + esbuild-linux-ppc64le: 0.15.7 + esbuild-linux-riscv64: 0.15.7 + esbuild-linux-s390x: 0.15.7 + esbuild-netbsd-64: 0.15.7 + esbuild-openbsd-64: 0.15.7 + esbuild-sunos-64: 0.15.7 + esbuild-windows-32: 0.15.7 + esbuild-windows-64: 0.15.7 + esbuild-windows-arm64: 0.15.7 + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + dev: false + + /eslint-config-standard-with-typescript@23.0.0(@typescript-eslint/eslint-plugin@5.37.0)(eslint-plugin-import@2.26.0)(eslint-plugin-n@15.2.5)(eslint-plugin-promise@6.0.1)(eslint@8.22.0)(typescript@4.8.3): + resolution: {integrity: sha512-iaaWifImn37Z1OXbNW1es7KI+S7D408F9ys0bpaQf2temeBWlvb0Nc5qHkOgYaRb5QxTZT32GGeN1gtswASOXA==} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^5.0.0 + eslint: ^8.0.1 + eslint-plugin-import: ^2.25.2 + eslint-plugin-n: ^15.0.0 + eslint-plugin-promise: ^6.0.0 + typescript: '*' + dependencies: + '@typescript-eslint/eslint-plugin': 5.37.0(@typescript-eslint/parser@5.37.0)(eslint@8.22.0)(typescript@4.8.3) + '@typescript-eslint/parser': 5.37.0(eslint@8.22.0)(typescript@4.8.3) + eslint: 8.22.0 + eslint-config-standard: 17.0.0(eslint-plugin-import@2.26.0)(eslint-plugin-n@15.2.5)(eslint-plugin-promise@6.0.1)(eslint@8.22.0) + eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.37.0)(eslint@8.22.0) + eslint-plugin-n: 15.2.5(eslint@8.22.0) + eslint-plugin-promise: 6.0.1(eslint@8.22.0) + typescript: 4.8.3 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-config-standard@17.0.0(eslint-plugin-import@2.26.0)(eslint-plugin-n@15.2.5)(eslint-plugin-promise@6.0.1)(eslint@8.22.0): + resolution: {integrity: sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==} + peerDependencies: + eslint: ^8.0.1 + eslint-plugin-import: ^2.25.2 + eslint-plugin-n: ^15.0.0 + eslint-plugin-promise: ^6.0.0 + dependencies: + eslint: 8.22.0 + eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.37.0)(eslint@8.22.0) + eslint-plugin-n: 15.2.5(eslint@8.22.0) + eslint-plugin-promise: 6.0.1(eslint@8.22.0) + dev: true + + /eslint-import-resolver-node@0.3.6: + resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==} + dependencies: + debug: 3.2.7 + resolve: 1.22.1 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-module-utils@2.7.4(@typescript-eslint/parser@5.37.0)(eslint-import-resolver-node@0.3.6)(eslint@8.22.0): + resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 5.37.0(eslint@8.22.0)(typescript@4.8.3) + debug: 3.2.7 + eslint: 8.22.0 + eslint-import-resolver-node: 0.3.6 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-es@4.1.0(eslint@8.22.0): + resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} + engines: {node: '>=8.10.0'} + peerDependencies: + eslint: '>=4.19.1' + dependencies: + eslint: 8.22.0 + eslint-utils: 2.1.0 + regexpp: 3.2.0 + dev: true + + /eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.37.0)(eslint@8.22.0): + resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 5.37.0(eslint@8.22.0)(typescript@4.8.3) + array-includes: 3.1.5 + array.prototype.flat: 1.3.0 + debug: 2.6.9 + doctrine: 2.1.0 + eslint: 8.22.0 + eslint-import-resolver-node: 0.3.6 + eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.37.0)(eslint-import-resolver-node@0.3.6)(eslint@8.22.0) + has: 1.0.3 + is-core-module: 2.10.0 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.values: 1.1.5 + resolve: 1.22.1 + tsconfig-paths: 3.14.1 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-plugin-n@15.2.5(eslint@8.22.0): + resolution: {integrity: sha512-8+BYsqiyZfpu6NXmdLOXVUfk8IocpCjpd8nMRRH0A9ulrcemhb2VI9RSJMEy5udx++A/YcVPD11zT8hpFq368g==} + engines: {node: '>=12.22.0'} + peerDependencies: + eslint: '>=7.0.0' + dependencies: + builtins: 5.0.1 + eslint: 8.22.0 + eslint-plugin-es: 4.1.0(eslint@8.22.0) + eslint-utils: 3.0.0(eslint@8.22.0) + ignore: 5.2.0 + is-core-module: 2.10.0 + minimatch: 3.1.2 + resolve: 1.22.1 + semver: 7.3.7 + dev: true + + /eslint-plugin-promise@6.0.1(eslint@8.22.0): + resolution: {integrity: sha512-uM4Tgo5u3UWQiroOyDEsYcVMOo7re3zmno0IZmB5auxoaQNIceAbXEkSt8RNrKtaYehARHG06pYK6K1JhtP0Zw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + eslint: 8.22.0 + dev: true + + /eslint-plugin-react-hooks@4.6.0(eslint@8.22.0): + resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + dependencies: + eslint: 8.22.0 + dev: true + + /eslint-plugin-react@7.31.8(eslint@8.22.0): + resolution: {integrity: sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + array-includes: 3.1.5 + array.prototype.flatmap: 1.3.0 + doctrine: 2.1.0 + eslint: 8.22.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.3 + minimatch: 3.1.2 + object.entries: 1.1.5 + object.fromentries: 2.0.5 + object.hasown: 1.1.1 + object.values: 1.1.5 + prop-types: 15.8.1 + resolve: 2.0.0-next.4 + semver: 6.3.0 + string.prototype.matchall: 4.0.7 + dev: true + + /eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + + /eslint-scope@7.1.1: + resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-utils@2.1.0: + resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} + engines: {node: '>=6'} + dependencies: + eslint-visitor-keys: 1.3.0 + dev: true + + /eslint-utils@3.0.0(eslint@8.22.0): + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + dependencies: + eslint: 8.22.0 + eslint-visitor-keys: 2.1.0 + dev: true + + /eslint-visitor-keys@1.3.0: + resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} + engines: {node: '>=4'} + dev: true + + /eslint-visitor-keys@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + dev: true + + /eslint-visitor-keys@3.3.0: + resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint@8.22.0: + resolution: {integrity: sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint/eslintrc': 1.3.2 + '@humanwhocodes/config-array': 0.10.4 + '@humanwhocodes/gitignore-to-minimatch': 1.0.2 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.1.1 + eslint-utils: 3.0.0(eslint@8.22.0) + eslint-visitor-keys: 3.3.0 + espree: 9.4.0 + esquery: 1.4.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + functional-red-black-tree: 1.0.1 + glob-parent: 6.0.2 + globals: 13.17.0 + globby: 11.1.0 + grapheme-splitter: 1.0.4 + ignore: 5.2.0 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.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.1 + regexpp: 3.2.0 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + v8-compile-cache: 2.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree@9.4.0: + resolution: {integrity: sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.8.0 + acorn-jsx: 5.3.2(acorn@8.8.0) + eslint-visitor-keys: 3.3.0 + dev: true + + /esquery@1.4.0: + resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: false + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + dev: false + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-glob@3.2.12: + resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true + + /fastparse@1.1.2: + resolution: {integrity: sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==} + dev: false + + /fastq@1.13.0: + resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} + dependencies: + reusify: 1.0.4 + + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.0.4 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat-cache@3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.7 + rimraf: 3.0.2 + dev: true + + /flatted@3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + dev: true + + /fraction.js@4.2.0: + resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} + + /fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.10 + jsonfile: 6.1.0 + universalify: 2.0.0 + dev: false + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + optional: true + + /function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + + /function.prototype.name@1.1.5: + resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.2 + functions-have-names: 1.2.3 + dev: true + + /functional-red-black-tree@1.0.1: + resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} + dev: true + + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true + + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + + /get-intrinsic@1.1.3: + resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.3 + + /get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.1.3 + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + /globals@13.17.0: + resolution: {integrity: sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.2.12 + ignore: 5.2.0 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /goober@2.1.12(csstype@3.1.1): + resolution: {integrity: sha512-yXHAvO08FU1JgTXX6Zn6sYCUFfB/OJSX8HHjDSgerZHZmFKAb08cykp5LBw5QnmyMcZyPRMqkdyHUSSzge788Q==} + peerDependencies: + csstype: ^3.0.10 + dependencies: + csstype: 3.1.1 + dev: false + + /graceful-fs@4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + requiresBuild: true + + /grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + dev: true + + /has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + dev: true + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /has-property-descriptors@1.0.0: + resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + dependencies: + get-intrinsic: 1.1.3 + dev: true + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + /has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + + /hast-util-whitespace@2.0.0: + resolution: {integrity: sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg==} + dev: false + + /hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + dependencies: + react-is: 16.13.1 + dev: false + + /htmlparser2@8.0.1: + resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.0.1 + entities: 4.4.0 + dev: false + + /iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + optional: true + + /ignore@5.2.0: + resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} + engines: {node: '>= 4'} + dev: true + + /image-size@0.5.5: + resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} + engines: {node: '>=0.10.0'} + hasBin: true + requiresBuild: true + optional: true + + /immer@9.0.16: + resolution: {integrity: sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==} + dev: false + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true + + /inline-style-parser@0.1.1: + resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==} + dev: false + + /internal-slot@1.0.3: + resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.1.3 + has: 1.0.3 + side-channel: 1.0.4 + dev: true + + /intersection-observer@0.12.2: + resolution: {integrity: sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==} + dev: false + + /is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + dev: false + + /is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + dependencies: + has-bigints: 1.0.2 + dev: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + + /is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + has-tostringtag: 1.0.0 + dev: true + + /is-buffer@2.0.5: + resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} + engines: {node: '>=4'} + dev: false + + /is-callable@1.2.6: + resolution: {integrity: sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==} + engines: {node: '>= 0.4'} + dev: true + + /is-core-module@2.10.0: + resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==} + dependencies: + has: 1.0.3 + + /is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + + /is-negative-zero@2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + engines: {node: '>= 0.4'} + dev: true + + /is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + /is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + dev: false + + /is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + has-tostringtag: 1.0.0 + dev: true + + /is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + dependencies: + call-bind: 1.0.2 + dev: true + + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.2 + dev: true + + /is-what@3.14.1: + resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + + /is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /jose@4.10.4: + resolution: {integrity: sha512-eBH77Xs9Yc/oTDvukhAEDVMijhekPuNktXJL4tUlB22jqKP1k48v5nmsUmc8feoJPsxB3HsfEt2LbVSoz+1mng==} + dev: false + + /js-base64@3.7.2: + resolution: {integrity: sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ==} + dev: false + + /js-cookie@2.2.1: + resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} + dev: false + + /js-search@2.0.0: + resolution: {integrity: sha512-lJ8KzjlwcelIWuAdKyzsXv45W6OIwRpayzc7XmU8mzgWadg5UVOKVmnq/tXudddEB9Ceic3tVaGu6QOK/eebhg==} + dev: false + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + /jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + dev: false + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /json5@1.0.1: + resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} + hasBin: true + dependencies: + minimist: 1.2.6 + dev: true + + /json5@2.2.1: + resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==} + engines: {node: '>=6'} + hasBin: true + + /jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.0 + optionalDependencies: + graceful-fs: 4.2.10 + dev: false + + /jsx-ast-utils@3.3.3: + resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==} + engines: {node: '>=4.0'} + dependencies: + array-includes: 3.1.5 + object.assign: 4.1.4 + dev: true + + /kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + dev: false + + /less@4.1.3: + resolution: {integrity: sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==} + engines: {node: '>=6'} + hasBin: true + dependencies: + copy-anything: 2.0.6 + parse-node-version: 1.0.1 + tslib: 2.4.0 + optionalDependencies: + errno: 0.1.8 + graceful-fs: 4.2.10 + image-size: 0.5.5 + make-dir: 2.1.0 + mime: 1.6.0 + needle: 3.2.0 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /lilconfig@2.0.6: + resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==} + engines: {node: '>=10'} + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + dev: false + + /lodash.castarray@4.4.0: + resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} + dev: true + + /lodash.get@4.4.2: + resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + dev: false + + /lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + dev: true + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + dev: false + + /lodash.orderby@4.6.0: + resolution: {integrity: sha512-T0rZxKmghOOf5YPnn8EY5iLYeWCpZq8G41FfqoVHH5QDTAFaghJRmAdLiadEDq+ztgM2q5PjA+Z1fOwGrLgmtg==} + dev: false + + /lodash.pick@4.4.0: + resolution: {integrity: sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==} + dev: false + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false + + /longest-streak@3.0.1: + resolution: {integrity: sha512-cHlYSUpL2s7Fb3394mYxwTYj8niTaNHUCLr0qdiCXQfSjfuA7CKofpX2uSwEfFDQ0EB7JcnMnm+GjbqqoinYYg==} + dev: false + + /loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + dependencies: + js-tokens: 4.0.0 + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /magic-string@0.26.3: + resolution: {integrity: sha512-u1Po0NDyFcwdg2nzHT88wSK0+Rih0N1M+Ph1Sp08k8yvFFU3KR72wryS7e1qMPJypt99WB7fIFVCA92mQrMjrg==} + engines: {node: '>=12'} + dependencies: + sourcemap-codec: 1.4.8 + + /make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + requiresBuild: true + dependencies: + pify: 4.0.1 + semver: 5.7.1 + optional: true + + /map-obj@4.3.0: + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} + dev: false + + /markdown-table@3.0.2: + resolution: {integrity: sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==} + dev: false + + /mdast-util-definitions@5.1.1: + resolution: {integrity: sha512-rQ+Gv7mHttxHOBx2dkF4HWTg+EE+UR78ptQWDylzPKaQuVGdG4HIoY3SrS/pCp80nZ04greFvXbVFHT+uf0JVQ==} + dependencies: + '@types/mdast': 3.0.10 + '@types/unist': 2.0.6 + unist-util-visit: 4.1.1 + dev: false + + /mdast-util-find-and-replace@2.2.1: + resolution: {integrity: sha512-SobxkQXFAdd4b5WmEakmkVoh18icjQRxGy5OWTCzgsLRm1Fu/KCtwD1HIQSsmq5ZRjVH0Ehwg6/Fn3xIUk+nKw==} + dependencies: + escape-string-regexp: 5.0.0 + unist-util-is: 5.1.1 + unist-util-visit-parents: 5.1.1 + dev: false + + /mdast-util-from-markdown@1.2.0: + resolution: {integrity: sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==} + dependencies: + '@types/mdast': 3.0.10 + '@types/unist': 2.0.6 + decode-named-character-reference: 1.0.2 + mdast-util-to-string: 3.1.0 + micromark: 3.0.10 + micromark-util-decode-numeric-character-reference: 1.0.0 + micromark-util-decode-string: 1.0.2 + micromark-util-normalize-identifier: 1.0.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + unist-util-stringify-position: 3.0.2 + uvu: 0.5.6 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-gfm-autolink-literal@1.0.2: + resolution: {integrity: sha512-FzopkOd4xTTBeGXhXSBU0OCDDh5lUj2rd+HQqG92Ld+jL4lpUfgX2AT2OHAVP9aEeDKp7G92fuooSZcYJA3cRg==} + dependencies: + '@types/mdast': 3.0.10 + ccount: 2.0.1 + mdast-util-find-and-replace: 2.2.1 + micromark-util-character: 1.1.0 + dev: false + + /mdast-util-gfm-footnote@1.0.1: + resolution: {integrity: sha512-p+PrYlkw9DeCRkTVw1duWqPRHX6Ywh2BNKJQcZbCwAuP/59B0Lk9kakuAd7KbQprVO4GzdW8eS5++A9PUSqIyw==} + dependencies: + '@types/mdast': 3.0.10 + mdast-util-to-markdown: 1.3.0 + micromark-util-normalize-identifier: 1.0.0 + dev: false + + /mdast-util-gfm-strikethrough@1.0.1: + resolution: {integrity: sha512-zKJbEPe+JP6EUv0mZ0tQUyLQOC+FADt0bARldONot/nefuISkaZFlmVK4tU6JgfyZGrky02m/I6PmehgAgZgqg==} + dependencies: + '@types/mdast': 3.0.10 + mdast-util-to-markdown: 1.3.0 + dev: false + + /mdast-util-gfm-table@1.0.6: + resolution: {integrity: sha512-uHR+fqFq3IvB3Rd4+kzXW8dmpxUhvgCQZep6KdjsLK4O6meK5dYZEayLtIxNus1XO3gfjfcIFe8a7L0HZRGgag==} + dependencies: + '@types/mdast': 3.0.10 + markdown-table: 3.0.2 + mdast-util-from-markdown: 1.2.0 + mdast-util-to-markdown: 1.3.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-gfm-task-list-item@1.0.1: + resolution: {integrity: sha512-KZ4KLmPdABXOsfnM6JHUIjxEvcx2ulk656Z/4Balw071/5qgnhz+H1uGtf2zIGnrnvDC8xR4Fj9uKbjAFGNIeA==} + dependencies: + '@types/mdast': 3.0.10 + mdast-util-to-markdown: 1.3.0 + dev: false + + /mdast-util-gfm@2.0.1: + resolution: {integrity: sha512-42yHBbfWIFisaAfV1eixlabbsa6q7vHeSPY+cg+BBjX51M8xhgMacqH9g6TftB/9+YkcI0ooV4ncfrJslzm/RQ==} + dependencies: + mdast-util-from-markdown: 1.2.0 + mdast-util-gfm-autolink-literal: 1.0.2 + mdast-util-gfm-footnote: 1.0.1 + mdast-util-gfm-strikethrough: 1.0.1 + mdast-util-gfm-table: 1.0.6 + mdast-util-gfm-task-list-item: 1.0.1 + mdast-util-to-markdown: 1.3.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-to-hast@12.2.4: + resolution: {integrity: sha512-a21xoxSef1l8VhHxS1Dnyioz6grrJkoaCUgGzMD/7dWHvboYX3VW53esRUfB5tgTyz4Yos1n25SPcj35dJqmAg==} + dependencies: + '@types/hast': 2.3.4 + '@types/mdast': 3.0.10 + mdast-util-definitions: 5.1.1 + micromark-util-sanitize-uri: 1.1.0 + trim-lines: 3.0.1 + unist-builder: 3.0.0 + unist-util-generated: 2.0.0 + unist-util-position: 4.0.3 + unist-util-visit: 4.1.1 + dev: false + + /mdast-util-to-markdown@1.3.0: + resolution: {integrity: sha512-6tUSs4r+KK4JGTTiQ7FfHmVOaDrLQJPmpjD6wPMlHGUVXoG9Vjc3jIeP+uyBWRf8clwB2blM+W7+KrlMYQnftA==} + dependencies: + '@types/mdast': 3.0.10 + '@types/unist': 2.0.6 + longest-streak: 3.0.1 + mdast-util-to-string: 3.1.0 + micromark-util-decode-string: 1.0.2 + unist-util-visit: 4.1.1 + zwitch: 2.0.2 + dev: false + + /mdast-util-to-string@3.1.0: + resolution: {integrity: sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==} + dev: false + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + /micromark-core-commonmark@1.0.6: + resolution: {integrity: sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==} + dependencies: + decode-named-character-reference: 1.0.2 + micromark-factory-destination: 1.0.0 + micromark-factory-label: 1.0.2 + micromark-factory-space: 1.0.0 + micromark-factory-title: 1.0.2 + micromark-factory-whitespace: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-chunked: 1.0.0 + micromark-util-classify-character: 1.0.0 + micromark-util-html-tag-name: 1.1.0 + micromark-util-normalize-identifier: 1.0.0 + micromark-util-resolve-all: 1.0.0 + micromark-util-subtokenize: 1.0.2 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: false + + /micromark-extension-gfm-autolink-literal@1.0.3: + resolution: {integrity: sha512-i3dmvU0htawfWED8aHMMAzAVp/F0Z+0bPh3YrbTPPL1v4YAlCZpy5rBO5p0LPYiZo0zFVkoYh7vDU7yQSiCMjg==} + dependencies: + micromark-util-character: 1.1.0 + micromark-util-sanitize-uri: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: false + + /micromark-extension-gfm-footnote@1.0.4: + resolution: {integrity: sha512-E/fmPmDqLiMUP8mLJ8NbJWJ4bTw6tS+FEQS8CcuDtZpILuOb2kjLqPEeAePF1djXROHXChM/wPJw0iS4kHCcIg==} + dependencies: + micromark-core-commonmark: 1.0.6 + micromark-factory-space: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-normalize-identifier: 1.0.0 + micromark-util-sanitize-uri: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: false + + /micromark-extension-gfm-strikethrough@1.0.4: + resolution: {integrity: sha512-/vjHU/lalmjZCT5xt7CcHVJGq8sYRm80z24qAKXzaHzem/xsDYb2yLL+NNVbYvmpLx3O7SYPuGL5pzusL9CLIQ==} + dependencies: + micromark-util-chunked: 1.0.0 + micromark-util-classify-character: 1.0.0 + micromark-util-resolve-all: 1.0.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: false + + /micromark-extension-gfm-table@1.0.5: + resolution: {integrity: sha512-xAZ8J1X9W9K3JTJTUL7G6wSKhp2ZYHrFk5qJgY/4B33scJzE2kpfRL6oiw/veJTbt7jiM/1rngLlOKPWr1G+vg==} + dependencies: + micromark-factory-space: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: false + + /micromark-extension-gfm-tagfilter@1.0.1: + resolution: {integrity: sha512-Ty6psLAcAjboRa/UKUbbUcwjVAv5plxmpUTy2XC/3nJFL37eHej8jrHrRzkqcpipJliuBH30DTs7+3wqNcQUVA==} + dependencies: + micromark-util-types: 1.0.2 + dev: false + + /micromark-extension-gfm-task-list-item@1.0.3: + resolution: {integrity: sha512-PpysK2S1Q/5VXi72IIapbi/jliaiOFzv7THH4amwXeYXLq3l1uo8/2Be0Ac1rEwK20MQEsGH2ltAZLNY2KI/0Q==} + dependencies: + micromark-factory-space: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: false + + /micromark-extension-gfm@2.0.1: + resolution: {integrity: sha512-p2sGjajLa0iYiGQdT0oelahRYtMWvLjy8J9LOCxzIQsllMCGLbsLW+Nc+N4vi02jcRJvedVJ68cjelKIO6bpDA==} + dependencies: + micromark-extension-gfm-autolink-literal: 1.0.3 + micromark-extension-gfm-footnote: 1.0.4 + micromark-extension-gfm-strikethrough: 1.0.4 + micromark-extension-gfm-table: 1.0.5 + micromark-extension-gfm-tagfilter: 1.0.1 + micromark-extension-gfm-task-list-item: 1.0.3 + micromark-util-combine-extensions: 1.0.0 + micromark-util-types: 1.0.2 + dev: false + + /micromark-factory-destination@1.0.0: + resolution: {integrity: sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==} + dependencies: + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + dev: false + + /micromark-factory-label@1.0.2: + resolution: {integrity: sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==} + dependencies: + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: false + + /micromark-factory-space@1.0.0: + resolution: {integrity: sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==} + dependencies: + micromark-util-character: 1.1.0 + micromark-util-types: 1.0.2 + dev: false + + /micromark-factory-title@1.0.2: + resolution: {integrity: sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==} + dependencies: + micromark-factory-space: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: false + + /micromark-factory-whitespace@1.0.0: + resolution: {integrity: sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==} + dependencies: + micromark-factory-space: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + dev: false + + /micromark-util-character@1.1.0: + resolution: {integrity: sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==} + dependencies: + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + dev: false + + /micromark-util-chunked@1.0.0: + resolution: {integrity: sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==} + dependencies: + micromark-util-symbol: 1.0.1 + dev: false + + /micromark-util-classify-character@1.0.0: + resolution: {integrity: sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==} + dependencies: + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + dev: false + + /micromark-util-combine-extensions@1.0.0: + resolution: {integrity: sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==} + dependencies: + micromark-util-chunked: 1.0.0 + micromark-util-types: 1.0.2 + dev: false + + /micromark-util-decode-numeric-character-reference@1.0.0: + resolution: {integrity: sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==} + dependencies: + micromark-util-symbol: 1.0.1 + dev: false + + /micromark-util-decode-string@1.0.2: + resolution: {integrity: sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==} + dependencies: + decode-named-character-reference: 1.0.2 + micromark-util-character: 1.1.0 + micromark-util-decode-numeric-character-reference: 1.0.0 + micromark-util-symbol: 1.0.1 + dev: false + + /micromark-util-encode@1.0.1: + resolution: {integrity: sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==} + dev: false + + /micromark-util-html-tag-name@1.1.0: + resolution: {integrity: sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==} + dev: false + + /micromark-util-normalize-identifier@1.0.0: + resolution: {integrity: sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==} + dependencies: + micromark-util-symbol: 1.0.1 + dev: false + + /micromark-util-resolve-all@1.0.0: + resolution: {integrity: sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==} + dependencies: + micromark-util-types: 1.0.2 + dev: false + + /micromark-util-sanitize-uri@1.1.0: + resolution: {integrity: sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==} + dependencies: + micromark-util-character: 1.1.0 + micromark-util-encode: 1.0.1 + micromark-util-symbol: 1.0.1 + dev: false + + /micromark-util-subtokenize@1.0.2: + resolution: {integrity: sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==} + dependencies: + micromark-util-chunked: 1.0.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: false + + /micromark-util-symbol@1.0.1: + resolution: {integrity: sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==} + dev: false + + /micromark-util-types@1.0.2: + resolution: {integrity: sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==} + dev: false + + /micromark@3.0.10: + resolution: {integrity: sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg==} + dependencies: + '@types/debug': 4.1.7 + debug: 4.3.4 + decode-named-character-reference: 1.0.2 + micromark-core-commonmark: 1.0.6 + micromark-factory-space: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-chunked: 1.0.0 + micromark-util-combine-extensions: 1.0.0 + micromark-util-decode-numeric-character-reference: 1.0.0 + micromark-util-encode: 1.0.1 + micromark-util-normalize-identifier: 1.0.0 + micromark-util-resolve-all: 1.0.0 + micromark-util-sanitize-uri: 1.1.0 + micromark-util-subtokenize: 1.0.2 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + transitivePeerDependencies: + - supports-color + dev: false + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + + /mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + requiresBuild: true + optional: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimist@1.2.6: + resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} + + /mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + dev: false + + /ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + /nanoid@3.3.4: + resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /needle@3.2.0: + resolution: {integrity: sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==} + engines: {node: '>= 4.4.x'} + hasBin: true + requiresBuild: true + dependencies: + debug: 3.2.7 + iconv-lite: 0.6.3 + sax: 1.2.4 + transitivePeerDependencies: + - supports-color + optional: true + + /node-releases@2.0.6: + resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + /normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + /nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: false + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + /object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + /object-inspect@1.12.2: + resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} + + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: true + + /object.assign@4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: true + + /object.entries@1.1.5: + resolution: {integrity: sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.2 + dev: true + + /object.fromentries@2.0.5: + resolution: {integrity: sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.2 + dev: true + + /object.hasown@1.1.1: + resolution: {integrity: sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==} + dependencies: + define-properties: 1.1.4 + es-abstract: 1.20.2 + dev: true + + /object.values@1.1.5: + resolution: {integrity: sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.2 + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /open@8.4.0: + resolution: {integrity: sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==} + engines: {node: '>=12'} + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + dev: true + + /optionator@0.9.1: + resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + engines: {node: '>= 0.8.0'} + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.3 + dev: true + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + dev: false + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /parse-node-version@1.0.1: + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} + + /parse5-htmlparser2-tree-adapter@7.0.0: + resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==} + dependencies: + domhandler: 5.0.3 + parse5: 7.1.2 + dev: false + + /parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + dependencies: + entities: 4.4.0 + dev: false + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + /pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + /pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + optional: true + + /postcss-import@14.1.0(postcss@8.4.19): + resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} + engines: {node: '>=10.0.0'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + postcss: 8.4.19 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.1 + + /postcss-js@4.0.0(postcss@8.4.19): + resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.3.3 + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.19 + + /postcss-load-config@3.1.4(postcss@8.4.19): + resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} + engines: {node: '>= 10'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 2.0.6 + postcss: 8.4.19 + yaml: 1.10.2 + + /postcss-nested@6.0.0(postcss@8.4.19): + resolution: {integrity: sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + dependencies: + postcss: 8.4.19 + postcss-selector-parser: 6.0.10 + + /postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + /postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + /postcss@8.4.19: + resolution: {integrity: sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.4 + picocolors: 1.0.0 + source-map-js: 1.0.2 + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + /property-information@6.1.1: + resolution: {integrity: sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==} + dev: false + + /prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + optional: true + + /punycode@2.1.1: + resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} + engines: {node: '>=6'} + dev: true + + /q@1.5.1: + resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + dev: false + + /qs@6.11.0: + resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: false + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + /quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + + /react-dom@18.2.0(react@18.2.0): + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + peerDependencies: + react: ^18.2.0 + dependencies: + loose-envify: 1.4.0 + react: 18.2.0 + scheduler: 0.23.0 + dev: false + + /react-fast-compare@3.2.0: + resolution: {integrity: sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==} + dev: false + + /react-hot-toast@2.4.0(csstype@3.1.1)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-qnnVbXropKuwUpriVVosgo8QrB+IaPJCpL8oBI6Ov84uvHZ5QQcTp2qg6ku2wNfgJl6rlQXJIQU5q+5lmPOutA==} + engines: {node: '>=10'} + peerDependencies: + react: '>=16' + react-dom: '>=16' + dependencies: + goober: 2.1.12(csstype@3.1.1) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + transitivePeerDependencies: + - csstype + dev: false + + /react-icons@4.4.0(react@18.2.0): + resolution: {integrity: sha512-fSbvHeVYo/B5/L4VhB7sBA1i2tS8MkT0Hb9t2H1AVPkwGfVHLJCqyr2Py9dKMxsyM63Eng1GkdZfbWj+Fmv8Rg==} + peerDependencies: + react: '*' + dependencies: + react: 18.2.0 + dev: false + + /react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + /react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + dev: false + + /react-markdown@8.0.3(@types/react@18.0.20)(react@18.2.0): + resolution: {integrity: sha512-We36SfqaKoVNpN1QqsZwWSv/OZt5J15LNgTLWynwAN5b265hrQrsjMtlRNwUvS+YyR3yDM8HpTNc4pK9H/Gc0A==} + peerDependencies: + '@types/react': '>=16' + react: '>=16' + dependencies: + '@types/hast': 2.3.4 + '@types/prop-types': 15.7.5 + '@types/react': 18.0.20 + '@types/unist': 2.0.6 + comma-separated-tokens: 2.0.2 + hast-util-whitespace: 2.0.0 + prop-types: 15.8.1 + property-information: 6.1.1 + react: 18.2.0 + react-is: 18.2.0 + remark-parse: 10.0.1 + remark-rehype: 10.1.0 + space-separated-tokens: 2.0.1 + style-to-object: 0.3.0 + unified: 10.1.2 + unist-util-visit: 4.1.1 + vfile: 5.3.5 + transitivePeerDependencies: + - supports-color + dev: false + + /react-popper@2.3.0(@popperjs/core@2.11.6)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==} + peerDependencies: + '@popperjs/core': ^2.0.0 + react: ^16.8.0 || ^17 || ^18 + react-dom: ^16.8.0 || ^17 || ^18 + dependencies: + '@popperjs/core': 2.11.6 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-fast-compare: 3.2.0 + warning: 4.0.3 + dev: false + + /react-redux@8.0.2(@types/react-dom@18.0.6)(@types/react@18.0.20)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.0): + resolution: {integrity: sha512-nBwiscMw3NoP59NFCXFf02f8xdo+vSHT/uZ1ldDwF7XaTpzm+Phk97VT4urYBl5TYAPNVaFm12UHAEyzkpNzRA==} + peerDependencies: + '@types/react': ^16.8 || ^17.0 || ^18.0 + '@types/react-dom': ^16.8 || ^17.0 || ^18.0 + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + react-native: '>=0.59' + redux: ^4 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + react-dom: + optional: true + react-native: + optional: true + redux: + optional: true + dependencies: + '@babel/runtime': 7.19.0 + '@types/hoist-non-react-statics': 3.3.1 + '@types/react': 18.0.20 + '@types/react-dom': 18.0.6 + '@types/use-sync-external-store': 0.0.3 + hoist-non-react-statics: 3.3.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-is: 18.2.0 + redux: 4.2.0 + use-sync-external-store: 1.2.0(react@18.2.0) + dev: false + + /react-refresh@0.13.0: + resolution: {integrity: sha512-XP8A9BT0CpRBD+NYLLeIhld/RqG9+gktUjW1FkE+Vm7OCinbG1SshcK5tb9ls4kzvjZr9mOQc7HYgBngEyPAXg==} + engines: {node: '>=0.10.0'} + dev: false + + /react-refresh@0.14.0: + resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} + engines: {node: '>=0.10.0'} + + /react-slider@2.0.4(react@18.2.0): + resolution: {integrity: sha512-sWwQD01n6v+MbeLCYthJGZPc0kzOyhQHyd0bSo0edg+IAxTVQmj3Oy4SBK65eX6gNwS9meUn6Z5sIBUVmwAd9g==} + peerDependencies: + react: ^16 || ^17 || ^18 + dependencies: + prop-types: 15.8.1 + react: 18.2.0 + dev: false + + /react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + dev: false + + /read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + dependencies: + pify: 2.3.0 + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + + /redux-thunk@2.4.1(redux@4.2.0): + resolution: {integrity: sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==} + peerDependencies: + redux: ^4 + dependencies: + redux: 4.2.0 + dev: false + + /redux@4.2.0: + resolution: {integrity: sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==} + dependencies: + '@babel/runtime': 7.19.0 + dev: false + + /regenerator-runtime@0.13.9: + resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} + dev: false + + /regexp.prototype.flags@1.4.3: + resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + functions-have-names: 1.2.3 + dev: true + + /regexpp@3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + dev: true + + /remark-gfm@3.0.1: + resolution: {integrity: sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==} + dependencies: + '@types/mdast': 3.0.10 + mdast-util-gfm: 2.0.1 + micromark-extension-gfm: 2.0.1 + unified: 10.1.2 + transitivePeerDependencies: + - supports-color + dev: false + + /remark-parse@10.0.1: + resolution: {integrity: sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==} + dependencies: + '@types/mdast': 3.0.10 + mdast-util-from-markdown: 1.2.0 + unified: 10.1.2 + transitivePeerDependencies: + - supports-color + dev: false + + /remark-rehype@10.1.0: + resolution: {integrity: sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==} + dependencies: + '@types/hast': 2.3.4 + '@types/mdast': 3.0.10 + mdast-util-to-hast: 12.2.4 + unified: 10.1.2 + dev: false + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /reselect@4.1.6: + resolution: {integrity: sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ==} + dev: false + + /resize-observer-polyfill@1.5.1: + resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} + dev: false + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve@1.22.1: + resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} + hasBin: true + dependencies: + is-core-module: 2.10.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + /resolve@2.0.0-next.4: + resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} + hasBin: true + dependencies: + is-core-module: 2.10.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /rollup-plugin-visualizer@5.8.3: + resolution: {integrity: sha512-QGJk4Bqe4AOat5AjipOh8esZH1nck5X2KFpf4VytUdSUuuuSwvIQZjMGgjcxe/zXexltqaXp5Vx1V3LmnQH15Q==} + engines: {node: '>=14'} + hasBin: true + peerDependencies: + rollup: 2.x || 3.x + peerDependenciesMeta: + rollup: + optional: true + dependencies: + open: 8.4.0 + source-map: 0.7.4 + yargs: 17.6.2 + dev: true + + /rollup@2.78.1: + resolution: {integrity: sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==} + engines: {node: '>=10.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + + /sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + dependencies: + mri: 1.2.0 + dev: false + + /safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + optional: true + + /sax@1.2.4: + resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} + optional: true + + /scheduler@0.23.0: + resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} + dependencies: + loose-envify: 1.4.0 + dev: false + + /screenfull@5.2.0: + resolution: {integrity: sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==} + engines: {node: '>=0.10.0'} + dev: false + + /semver@5.7.1: + resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true + optional: true + + /semver@6.3.0: + resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true + + /semver@7.3.7: + resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.1.3 + object-inspect: 1.12.2 + + /simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + dependencies: + is-arrayish: 0.3.2 + dev: false + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + requiresBuild: true + optional: true + + /source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + dev: true + + /sourcemap-codec@1.4.8: + resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} + + /space-separated-tokens@2.0.1: + resolution: {integrity: sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw==} + dev: false + + /stream-buffers@0.2.6: + resolution: {integrity: sha512-ZRpmWyuCdg0TtNKk8bEqvm13oQvXMmzXDsfD4cBgcx5LouborvU5pm3JMkdTP3HcszyUI08AM1dHMXA5r2g6Sg==} + engines: {node: '>= 0.3.0'} + dev: false + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string.prototype.matchall@4.0.7: + resolution: {integrity: sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.2 + get-intrinsic: 1.1.3 + has-symbols: 1.0.3 + internal-slot: 1.0.3 + regexp.prototype.flags: 1.4.3 + side-channel: 1.0.4 + dev: true + + /string.prototype.trimend@1.0.5: + resolution: {integrity: sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.2 + dev: true + + /string.prototype.trimstart@1.0.5: + resolution: {integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.2 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: true + + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /style-to-object@0.3.0: + resolution: {integrity: sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==} + dependencies: + inline-style-parser: 0.1.1 + dev: false + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + /tailwind-scrollbar-hide@1.1.7: + resolution: {integrity: sha512-X324n9OtpTmOMqEgDUEA/RgLrNfBF/jwJdctaPZDzB3mppxJk7TLIDmOreEDm1Bq4R9LSPu4Epf8VSdovNU+iA==} + dev: false + + /tailwindcss@3.2.4(postcss@8.4.19): + resolution: {integrity: sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==} + engines: {node: '>=12.13.0'} + hasBin: true + peerDependencies: + postcss: ^8.0.9 + dependencies: + arg: 5.0.2 + chokidar: 3.5.3 + color-name: 1.1.4 + detective: 5.2.1 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.2.12 + glob-parent: 6.0.2 + is-glob: 4.0.3 + lilconfig: 2.0.6 + micromatch: 4.0.5 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.0 + postcss: 8.4.19 + postcss-import: 14.1.0(postcss@8.4.19) + postcss-js: 4.0.0(postcss@8.4.19) + postcss-load-config: 3.1.4(postcss@8.4.19) + postcss-nested: 6.0.0(postcss@8.4.19) + postcss-selector-parser: 6.0.10 + postcss-value-parser: 4.2.0 + quick-lru: 5.1.1 + resolve: 1.22.1 + transitivePeerDependencies: + - ts-node + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /tiny-pinyin@1.3.2: + resolution: {integrity: sha512-uHNGu4evFt/8eNLldazeAM1M8JrMc1jshhJJfVRARTN3yT8HEEibofeQ7QETWQ5ISBjd6fKtTVBCC/+mGS6FpA==} + dev: false + + /tippy.js@6.3.7: + resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} + dependencies: + '@popperjs/core': 2.11.6 + dev: false + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + + /trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + dev: false + + /trough@2.1.0: + resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==} + dev: false + + /tsconfig-paths@3.14.1: + resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.1 + minimist: 1.2.6 + strip-bom: 3.0.0 + dev: true + + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true + + /tslib@2.4.0: + resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + + /tslib@2.5.0: + resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} + dev: false + + /tsutils@3.21.0(typescript@4.8.3): + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + 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' + dependencies: + tslib: 1.14.1 + typescript: 4.8.3 + dev: true + + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /type-fest@1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + dev: false + + /typescript@4.8.3: + resolution: {integrity: sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + + /uberproto@1.2.0: + resolution: {integrity: sha512-pGtPAQmLwh+R9w81WVHzui1FfedpQWQpiaIIfPCwhtsBez4q6DYbJFfyXPVHPUTNFnedAvNEnkoFiLuhXIR94w==} + dev: false + + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + dependencies: + call-bind: 1.0.2 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + dev: true + + /unified@10.1.2: + resolution: {integrity: sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==} + dependencies: + '@types/unist': 2.0.6 + bail: 2.0.2 + extend: 3.0.2 + is-buffer: 2.0.5 + is-plain-obj: 4.1.0 + trough: 2.1.0 + vfile: 5.3.5 + dev: false + + /unist-builder@3.0.0: + resolution: {integrity: sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ==} + dependencies: + '@types/unist': 2.0.6 + dev: false + + /unist-util-generated@2.0.0: + resolution: {integrity: sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw==} + dev: false + + /unist-util-is@5.1.1: + resolution: {integrity: sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==} + dev: false + + /unist-util-position@4.0.3: + resolution: {integrity: sha512-p/5EMGIa1qwbXjA+QgcBXaPWjSnZfQ2Sc3yBEEfgPwsEmJd8Qh+DSk3LGnmOM4S1bY2C0AjmMnB8RuEYxpPwXQ==} + dependencies: + '@types/unist': 2.0.6 + dev: false + + /unist-util-stringify-position@3.0.2: + resolution: {integrity: sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==} + dependencies: + '@types/unist': 2.0.6 + dev: false + + /unist-util-visit-parents@5.1.1: + resolution: {integrity: sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==} + dependencies: + '@types/unist': 2.0.6 + unist-util-is: 5.1.1 + dev: false + + /unist-util-visit@4.1.1: + resolution: {integrity: sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==} + dependencies: + '@types/unist': 2.0.6 + unist-util-is: 5.1.1 + unist-util-visit-parents: 5.1.1 + dev: false + + /universalify@2.0.0: + resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + engines: {node: '>= 10.0.0'} + dev: false + + /update-browserslist-db@1.0.9(browserslist@4.21.3): + resolution: {integrity: sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.21.3 + escalade: 3.1.1 + picocolors: 1.0.0 + + /update-browserslist-db@1.0.9(browserslist@4.21.4): + resolution: {integrity: sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.21.4 + escalade: 3.1.1 + picocolors: 1.0.0 + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.1.1 + dev: true + + /use-sync-external-store@1.2.0(react@18.2.0): + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + /uuid@9.0.0: + resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} + hasBin: true + dev: false + + /uvu@0.5.6: + resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==} + engines: {node: '>=8'} + hasBin: true + dependencies: + dequal: 2.0.3 + diff: 5.1.0 + kleur: 4.1.5 + sade: 1.8.1 + dev: false + + /v8-compile-cache@2.3.0: + resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} + dev: true + + /vfile-message@3.1.2: + resolution: {integrity: sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==} + dependencies: + '@types/unist': 2.0.6 + unist-util-stringify-position: 3.0.2 + dev: false + + /vfile@5.3.5: + resolution: {integrity: sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==} + dependencies: + '@types/unist': 2.0.6 + is-buffer: 2.0.5 + unist-util-stringify-position: 3.0.2 + vfile-message: 3.1.2 + dev: false + + /vite@3.1.1(less@4.1.3): + resolution: {integrity: sha512-hgxQWev/AL7nWYrqByYo8nfcH9n97v6oFsta9+JX8h6cEkni7nHKP2kJleNYV2kcGhE8jsbaY1aStwPZXzPbgA==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + less: '*' + sass: '*' + stylus: '*' + terser: ^5.4.0 + peerDependenciesMeta: + less: + optional: true + sass: + optional: true + stylus: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.15.7 + less: 4.1.3 + postcss: 8.4.19 + resolve: 1.22.1 + rollup: 2.78.1 + optionalDependencies: + fsevents: 2.3.2 + + /warning@4.0.3: + resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} + dependencies: + loose-envify: 1.4.0 + dev: false + + /which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /word-wrap@1.2.3: + resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} + engines: {node: '>=0.10.0'} + dev: true + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + + /yargs@17.6.2: + resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==} + engines: {node: '>=12'} + 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.8 + yargs-parser: 21.1.1 + dev: true + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true + + /zod@3.19.1: + resolution: {integrity: sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==} + dev: false + + /zwitch@2.0.2: + resolution: {integrity: sha512-JZxotl7SxAJH0j7dN4pxsTV6ZLXoLdGME+PsjkL/DaBrVryK9kTGq06GfKrwcSOqypP+fdXGoCHE36b99fWVoA==} + dev: false diff --git a/postcss.config.cjs b/postcss.config.cjs new file mode 100644 index 0000000..f1c8dac --- /dev/null +++ b/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + } +} diff --git a/public/favicon-128x128.png b/public/favicon-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..a7be2b709671e2faa2fafabd79f2822ced038252 GIT binary patch literal 1227 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&F%}28J2BoosZ$T+a29w(7Bet# z3xhBt!>l!Warx_+ZJv85ztVle6aQX@_B}z1=j6KbbQ5` z_s(wBfqiX44(reF&o5YzVDLcUga4glTY9c7jmi2}!*PyV;*r#?*{Y?RZj>yyWZuQV zz_iBG#WAE}&fD3U#g`2P+C-U7Uz`w^scF7+iZx>tA9E`c;5wqENgD(la~~H!|i^z zvOH9#_wVszhJP5<)Rg~UV(GI#5Tf~IzFpf>egosXY!-db`3ssh2Kv-DFj;qU7j(@% z#%gi++^5IIo6nWZn|*F0_s55OPM@kaEZciT?|6H73{%Wg#S;PtOs6v(z46t`wSj?y zK{{c&jz;*mDD%857lm?eos2{Y27Q;w-DZCn^SBv0TVM3a);H|#+WugkZUd_+!})3U zcfxxbOdA#{9bk@T;1}JTaB|ZB#mBoM4@_J8!@kmL2_MJQf|rq{>%aav>b;CFA^z|^ z)^`jSlpPpY8u%PCJs4ON;^kMYUDGsA?DhIxmrrZgJX~q_+LLjT^rW_B)l074Sfwd1 zC&kDYVEidRKG$Tgs{A#E6Vgl#_h!I-w*m zgK5j5o6YuXqINNyZ46$a*)i{X*8dN)lo-}C&r9Txx>#aAf$zK4PQD+1#TPDWaK9z~ zSz*F2e%+({z6tqwuQ5;kxq+>rRFHu&Al!%HzwH6(zh^Jq+ovJhu>7`hd5CyC_sdHc zPVC=q?JLT-dEMT%QAQ1)jxF`vej#vkbzg||^kWQHpK#n@7f_nOwIGR0VaxHA3_i23 zSw56``O2aG{^}R{(-uv+{XNdPe&?Qxm*-vjR$IpKLQKG68p8`~r7s)_jC*?f@9kuX z=#OPKJ0B@i7x;7D?79Sb#?aSqg!K-jKg(UfG)3Zf(@Xifh|gc8=lwtP-9XiB`G!CB zIc}amKa2PM{}B-*#uY8`FPe3s(cgRjHb4GguO@B%bH8PK>vT}kTH^Cs{{DXx_Y+Br Qrh&>FPgg&ebxsLQ0F`J$NB{r; literal 0 HcmV?d00001 diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..5a06200218493e1ed6239c7ea2c597d0ac8bc94a GIT binary patch literal 278 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6XVU3I`u#fXMsm#F#`j) zFbFd;%$g$s6toQR32_C|4C~&Ifi4_WFa_!rE(!7rW>BzyaQ?vk{{{OE0vhTQCO8OO zkesja8z>#_>EaktF(>zYBwvF9kLyLTgG$XjzvI{3l5#rw*)^|1k)dW`pn%zHwK8_2 z&$Z6wAC3!H95L~TP%|{PG4}HK46_w*A>k)%SFHEaI*T4~Bgh2Hw~o7*FdRqXqf RgS8;%d%F6$taD0e0ss*JVpRYD literal 0 HcmV?d00001 diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..c2b31a091efb5bac652aa6bfec52508d1dd37b91 GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jPK-BC>eK@{oCO|{#S9GG z!XV7ZFl&wkP|zd5C&U#Hq(g+)|o(uD%yOUzk33 z$@ZJ7znFLbb53hH&=XXjrJCC z$GR8GR<^#$JTZCc0evU?+NPL|9`iNs=HK|z#eT6%7e literal 0 HcmV?d00001 diff --git a/public/favicon-48x48.png b/public/favicon-48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..a871f5e91c6d500b69a14c844c453ca159ee5140 GIT binary patch literal 400 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sjKx9jPK-BC>eK@{oCO|{#S9GG z!XV7ZFl&wkP|zd5C&U#FSPp91FYgXWK;}$)dc{Mj@-~ZWsJ(0^oR-XKK=NxZb zjk?o*h6C}7Ou8;|DHwmUS#(n2{v`J^3mtUU2+TJXC{we|dwDosM<$5(OpBJ~`6{gy zOBSR>FG`c$-Mn#MoPw+~L$0`8h|ULF4GX^4nqohet^Qawcc!kT+WSBA^%ec)XI`pi zT{pSNHN*A$L&kkasv;#`&%I>x^+L7KI>#5yibve5H@vwb{_%bAW>xzuj(Q(o-7TDA c^|Zf;+3l6UpYppKuY&^4)78&qol`;+0G(Z@J^%m! literal 0 HcmV?d00001 diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a45002526a794f1dee648dbb013c2b8d8ae6f00c GIT binary patch literal 447 zcmZQzU<5(|0R|wcz_5~$fkBLcfuS?N&z+Y`iVMi(_4IHF0@6Sg3<4a?KvF}OKNv_c z76-XIG2T3>QxD{D7I;J!Gca%qgD@k*tT_@u!D#_LA+8MT-Vi`Ql?2sLTR}r~eiP7M zqmm%M;Q9al|84)?oYDVBhrzCRt=2YAW{%c_2lVIems|4wozMdBt v$0RlD#+eJ3t~oO8s^a-Ir^n;K0RaZJ4}44F?jB|Z+RWhT>gTe~DWM4f50k7C literal 0 HcmV?d00001 diff --git a/public/popup.html b/public/popup.html new file mode 100644 index 0000000..5ecbba6 --- /dev/null +++ b/public/popup.html @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/shot.jpg b/public/shot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..37f1ee451b1feaa45d9a027c36997a5b988957a9 GIT binary patch literal 51088 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 literal 0 HcmV?d00001 diff --git a/public/subtitle.svg b/public/subtitle.svg new file mode 100644 index 0000000..aae2592 --- /dev/null +++ b/public/subtitle.svg @@ -0,0 +1,3 @@ + + diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..45675f0 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,73 @@ +import React, {useCallback, useContext, useEffect, useMemo} from 'react' +import 'tippy.js/dist/tippy.css' +import {useAppDispatch, useAppSelector} from './hooks/redux' +import {setEnvData, setEnvReady, setFold, setPage} from './redux/envReducer' +import Header from './biz/Header' +import Body from './biz/Body' +import useSubtitleService from './hooks/useSubtitleService' +import {cloneDeep} from 'lodash-es' +import {EVENT_EXPAND, PAGE_MAIN, PAGE_SETTINGS, STORAGE_ENV} from './const' +import {EventBusContext} from './Router' +import useTranslateService from './hooks/useTranslateService' +import Settings from './biz/Settings' +import classNames from 'classnames' +import {handleJson} from '@kky002/kky-util' +import {useLocalStorage} from '@kky002/kky-hooks' +import {Toaster} from 'react-hot-toast' +import {setTheme} from './util/biz_util' + +function App() { + const dispatch = useAppDispatch() + const envData = useAppSelector(state => state.env.envData) + const fold = useAppSelector(state => state.env.fold) + const eventBus = useContext(EventBusContext) + const page = useAppSelector(state => state.env.page) + const totalHeight = useAppSelector(state => state.env.totalHeight) + + const foldCallback = useCallback(() => { + dispatch(setFold(!fold)) + dispatch(setPage(PAGE_MAIN)) + window.parent.postMessage({type: 'fold', fold: !fold}, '*') + }, [dispatch, fold]) + + // handle event + eventBus.useSubscription((event: any) => { + if (event.type === EVENT_EXPAND) { + if (fold) { + foldCallback() + } + } + }) + + // env数据 + const savedEnvData = useMemo(() => { + return handleJson(cloneDeep(envData)) as EnvData + }, [envData]) + const onLoadEnv = useCallback((data?: EnvData) => { + if (data != null) { + dispatch(setEnvData(data)) + } + dispatch(setEnvReady()) + }, [dispatch]) + useLocalStorage('chrome_client', STORAGE_ENV, savedEnvData, onLoadEnv) + + // theme改变时,设置主题 + useEffect(() => { + setTheme(envData.theme) + }, [envData.theme]) + + // services + useSubtitleService() + useTranslateService() + + return
+
+ {!fold && page === PAGE_MAIN && } + {!fold && page === PAGE_SETTINGS && } + +
+} + +export default App diff --git a/src/Router.tsx b/src/Router.tsx new file mode 100644 index 0000000..e04183c --- /dev/null +++ b/src/Router.tsx @@ -0,0 +1,26 @@ +import App from './App' +import {useEventEmitter} from 'ahooks' +import React from 'react' + +export const EventBusContext = React.createContext(null) + +const map: { [key: string]: string } = { + // '/close': 'close', +} + +const Router = () => { + const path = map[window.location.pathname] ?? 'app' + + if (path === 'close') { + window.close() + } + + // 事件总线 + const eventBus = useEventEmitter() + + return + {path === 'app' && } + +} + +export default Router diff --git a/src/biz/Body.tsx b/src/biz/Body.tsx new file mode 100644 index 0000000..33d9f66 --- /dev/null +++ b/src/biz/Body.tsx @@ -0,0 +1,168 @@ +import React, {useCallback, useEffect, useRef} from 'react' +import { + setAutoScroll, + setAutoTranslate, + setCheckAutoScroll, + setCompact, + setFoldAll, + setNeedScroll, + setPage, + setSegmentFold +} from '../redux/envReducer' +import {useAppDispatch, useAppSelector} from '../hooks/redux' +import {AiOutlineAim, FaRegArrowAltCircleDown, IoWarning, MdExpand, RiTranslate} from 'react-icons/all' +import classNames from 'classnames' +import toast from 'react-hot-toast' +import SegmentCard from './SegmentCard' +import {HEADER_HEIGHT, PAGE_SETTINGS, SUMMARIZE_ALL_THRESHOLD, TITLE_HEIGHT} from '../const' +import {FaClipboardList} from 'react-icons/fa' +import useTranslate from '../hooks/useTranslate' + +const Body = () => { + const dispatch = useAppDispatch() + const noVideo = useAppSelector(state => state.env.noVideo) + const autoTranslate = useAppSelector(state => state.env.autoTranslate) + const autoScroll = useAppSelector(state => state.env.autoScroll) + const segments = useAppSelector(state => state.env.segments) + const foldAll = useAppSelector(state => state.env.foldAll) + const envData = useAppSelector(state => state.env.envData) + const compact = useAppSelector(state => state.env.compact) + const apiKey = useAppSelector(state => state.env.envData.apiKey) + const floatKeyPointsSegIdx = useAppSelector(state => state.env.floatKeyPointsSegIdx) + const translateEnable = useAppSelector(state => state.env.envData.translateEnable) + const summarizeEnable = useAppSelector(state => state.env.envData.summarizeEnable) + const title = useAppSelector(state => state.env.title) + const {addSummarizeTask} = useTranslate() + const bodyRef = useRef() + const curOffsetTop = useAppSelector(state => state.env.curOffsetTop) + const checkAutoScroll = useAppSelector(state => state.env.checkAutoScroll) + const needScroll = useAppSelector(state => state.env.needScroll) + const totalHeight = useAppSelector(state => state.env.totalHeight) + const curSummaryType = useAppSelector(state => state.env.curSummaryType) + + const normalCallback = useCallback(() => { + dispatch(setCompact(false)) + }, [dispatch]) + + const compactCallback = useCallback(() => { + dispatch(setCompact(true)) + }, [dispatch]) + + const posCallback = useCallback(() => { + dispatch(setNeedScroll(true)) + }, [dispatch]) + + const onSummarizeAll = useCallback(() => { + if (!apiKey) { + dispatch(setPage(PAGE_SETTINGS)) + toast.error('需要先设置ApiKey!') + return + } + const segments_ = [] + for (const segment of segments ?? []) { + const summary = segment.summaries[curSummaryType] + if (!summary || summary.status === 'init' || (summary.status === 'done' && summary.error)) { + segments_.push(segment) + } + } + if (segments_.length === 0) { + toast.error('没有可总结的段落!') + return + } + if (segments_.length < SUMMARIZE_ALL_THRESHOLD || confirm(`确定总结${segments_.length}个段落?`)) { + for (const segment of segments_) { + addSummarizeTask(title, curSummaryType, segment).catch(console.error) + } + toast.success(`已添加${segments_.length}个总结任务!`) + } + }, [addSummarizeTask, apiKey, curSummaryType, dispatch, segments, title]) + + const onFoldAll = useCallback(() => { + dispatch(setFoldAll(!foldAll)) + for (const segment of segments ?? []) { + dispatch(setSegmentFold({ + segmentStartIdx: segment.startIdx, + fold: !foldAll + })) + } + }, [dispatch, foldAll, segments]) + + const toggleAutoTranslateCallback = useCallback(() => { + if (envData.apiKey) { + dispatch(setAutoTranslate(!autoTranslate)) + } else { + dispatch(setPage(PAGE_SETTINGS)) + toast.error('需要先设置ApiKey!') + } + }, [autoTranslate, dispatch, envData.apiKey]) + + const onEnableAutoScroll = useCallback(() => { + dispatch(setAutoScroll(true)) + dispatch(setNeedScroll(true)) + }, [dispatch]) + + const onWheel = useCallback(() => { + if (autoScroll) { + dispatch(setAutoScroll(false)) + } + }, [autoScroll, dispatch]) + + // 自动滚动 + useEffect(() => { + if (checkAutoScroll && curOffsetTop && autoScroll && !needScroll) { + if (bodyRef.current.scrollTop <= curOffsetTop - bodyRef.current.offsetTop - (totalHeight-120) + (floatKeyPointsSegIdx != null ? 100 : 0) || + bodyRef.current.scrollTop >= curOffsetTop - bodyRef.current.offsetTop - 40 - 10 + ) { + dispatch(setNeedScroll(true)) + dispatch(setCheckAutoScroll(false)) + console.debug('need scroll') + } + } + }, [autoScroll, checkAutoScroll, curOffsetTop, dispatch, floatKeyPointsSegIdx, needScroll, totalHeight]) + + return
+
+ + {segments != null && segments.length > 1 && + } +
+ +
+ {translateEnable &&
+ +
} + {summarizeEnable && +
+ +
} + {noVideo &&
+ +
} +
+ {!autoScroll &&
+ +
} +
+ {segments?.map((segment, segmentIdx) => )} +
+
+} + +export default Body diff --git a/src/biz/CompactSegmentItem.tsx b/src/biz/CompactSegmentItem.tsx new file mode 100644 index 0000000..b85d802 --- /dev/null +++ b/src/biz/CompactSegmentItem.tsx @@ -0,0 +1,33 @@ +import React, {useMemo} from 'react' +import {useAppSelector} from '../hooks/redux' +import {getDisplay, getTransText} from '../util/biz_util' +import classNames from 'classnames' + +const CompactSegmentItem = (props: { + item: { + from: number + to: number + content: string + } + idx: number + isIn: boolean + last: boolean + moveCallback: (event: any) => void +}) => { + const {item, idx, last, isIn, moveCallback} = props + const transResult = useAppSelector(state => state.env.transResults[idx]) + const envData = useAppSelector(state => state.env.envData) + const fontSize = useAppSelector(state => state.env.envData.fontSize) + const autoTranslate = useAppSelector(state => state.env.autoTranslate) + const transText = useMemo(() => getTransText(transResult, envData.hideOnDisableAutoTranslate, autoTranslate), [autoTranslate, envData.hideOnDisableAutoTranslate, transResult]) + const display = useMemo(() => getDisplay(envData.transDisplay, item.content, transText), [envData.transDisplay, item.content, transText]) + + return
+ + {display.main} + {display.sub && ({display.sub})} + {!last && ', '} +
+} + +export default CompactSegmentItem diff --git a/src/biz/Header.tsx b/src/biz/Header.tsx new file mode 100644 index 0000000..ff3d3f8 --- /dev/null +++ b/src/biz/Header.tsx @@ -0,0 +1,99 @@ +import {IoIosArrowUp} from 'react-icons/all' +import {useCallback} from 'react' +import {useAppDispatch, useAppSelector} from '../hooks/redux' +import {find, remove} from 'lodash-es' +import {setCurFetched, setCurInfo, setData, setInfos, setUploadedTranscript} from '../redux/envReducer' +import MoreBtn from './MoreBtn' +import classNames from 'classnames' +import {parseTranscript} from '../util/biz_util' + +const Header = (props: { + foldCallback: () => void +}) => { + const {foldCallback} = props + const dispatch = useAppDispatch() + const infos = useAppSelector(state => state.env.infos) + const curInfo = useAppSelector(state => state.env.curInfo) + const fold = useAppSelector(state => state.env.fold) + const uploadedTranscript = useAppSelector(state => state.env.uploadedTranscript) + + const upload = useCallback(() => { + const input = document.createElement('input') + input.type = 'file' + input.accept = '.vtt,.srt' + input.onchange = (e: any) => { + const file = e.target.files[0] + const reader = new FileReader() + reader.onload = (e) => { + const text = e.target?.result + if (text) { + const infos_ = [...(infos??[])] + // const blob = new Blob([text], {type: 'text/plain'}) + // const url = URL.createObjectURL(blob) + // remove old if exist + remove(infos_, {id: 'uploaded'}) + // add new + const tarInfo = {id: 'uploaded', subtitle_url: 'uploaded', lan_doc: '上传的字幕'} + infos_.push(tarInfo) + // set + const transcript = parseTranscript(file.name, text) + dispatch(setInfos(infos_)) + dispatch(setCurInfo(tarInfo)) + dispatch(setCurFetched(true)) + dispatch(setUploadedTranscript(transcript)) + dispatch(setData(transcript)) + } + } + reader.readAsText(file) + } + input.click() + }, [dispatch, infos]) + + const selectCallback = useCallback((e: any) => { + if (e.target.value === 'upload') { + upload() + return + } + + const tarInfo = find(infos, {subtitle_url: e.target.value}) + if (curInfo?.id !== tarInfo?.id) { + dispatch(setCurInfo(tarInfo)) + if (tarInfo && tarInfo.subtitle_url === 'uploaded') { + dispatch(setCurFetched(true)) + dispatch(setData(uploadedTranscript)) + } else { + dispatch(setCurFetched(false)) + } + } + }, [curInfo?.id, dispatch, infos, upload, uploadedTranscript]) + + const preventCallback = useCallback((e: any) => { + e.stopPropagation() + }, []) + + const onUpload = useCallback((e: any) => { + e.stopPropagation() + upload() + }, [upload]) + + return
+
+ 字幕列表 + +
+
+ {(infos == null) || infos.length <= 0 + ?
+ + (未找到字幕) +
+ :} + +
+
+} + +export default Header diff --git a/src/biz/MoreBtn.tsx b/src/biz/MoreBtn.tsx new file mode 100644 index 0000000..c259437 --- /dev/null +++ b/src/biz/MoreBtn.tsx @@ -0,0 +1,278 @@ +import React, {MouseEvent, useCallback, useContext, useRef, useState} from 'react' +import {useClickAway} from 'ahooks' +import { + AiFillWechat, + BsFillChatDotsFill, + FiMoreVertical, + ImDownload3, + IoMdSettings, + RiFileCopy2Line +} from 'react-icons/all' +import Popover from '../components/Popover' +import {Placement} from '@popperjs/core/lib/enums' +import {useAppDispatch, useAppSelector} from '../hooks/redux' +import {setDownloadType, setEnvData, setPage} from '../redux/envReducer' +import {EventBusContext} from '../Router' +import {EVENT_EXPAND, PAGE_SETTINGS} from '../const' +import {formatSrtTime, formatTime, formatVttTime} from '../util/util' +import {downloadText, openUrl} from '@kky002/kky-util' +import toast from 'react-hot-toast' +import {getSummarize} from '../util/biz_util' + +interface Props { + placement: Placement +} + +const DownloadTypes = [ + { + type: 'text', + name: '列表', + }, + { + type: 'textWithTime', + name: '列表(带时间)', + }, + { + type: 'article', + name: '文章', + }, + { + type: 'srt', + name: 'srt', + }, + { + type: 'vtt', + name: 'vtt', + }, + { + type: 'json', + name: '原始json', + }, + { + type: 'summarize', + name: '总结', + }, +] + +const MoreBtn = (props: Props) => { + const {placement} = props + const dispatch = useAppDispatch() + + const moreRef = useRef(null) + const data = useAppSelector(state => state.env.data) + const envReady = useAppSelector(state => state.env.envReady) + const envData = useAppSelector(state => state.env.envData) + const downloadType = useAppSelector(state => state.env.downloadType) + const [moreVisible, setMoreVisible] = useState(false) + const eventBus = useContext(EventBusContext) + const segments = useAppSelector(state => state.env.segments) + const title = useAppSelector(state => state.env.title) + const curSummaryType = useAppSelector(state => state.env.curSummaryType) + + const downloadCallback = useCallback((download: boolean) => { + if (data == null) { + return + } + + let s, fileName + if (!downloadType || downloadType === 'text') { + s = '' + for (const item of data.body) { + s += item.content + '\n' + } + fileName = 'download.txt' + } else if (downloadType === 'textWithTime') { + s = '' + for (const item of data.body) { + s += formatTime(item.from) + ' ' + item.content + '\n' + } + fileName = 'download.txt' + } else if (downloadType === 'article') { + s = '' + for (const item of data.body) { + s += item.content + ', ' + } + s = s.substring(0, s.length - 1) // remove last ',' + fileName = 'download.txt' + } else if (downloadType === 'srt') { + /** + * 1 + * 00:05:00,400 --> 00:05:15,300 + * This is an example of + * a subtitle. + * + * 2 + * 00:05:16,400 --> 00:05:25,300 + * This is an example of + * a subtitle - 2nd subtitle. + */ + s = '' + for (const item of data.body) { + const ss = (item.idx + 1) + '\n' + formatSrtTime(item.from) + ' --> ' + formatSrtTime(item.to) + '\n' + ((item.content?.trim()) ?? '') + '\n\n' + s += ss + } + s = s.substring(0, s.length - 1)// remove last '\n' + fileName = 'download.srt' + } else if (downloadType === 'vtt') { + /** + * WEBVTT title + * + * 1 + * 00:05:00.400 --> 00:05:15.300 + * This is an example of + * a subtitle. + * + * 2 + * 00:05:16.400 --> 00:05:25.300 + * This is an example of + * a subtitle - 2nd subtitle. + */ + s = `WEBVTT ${title ?? ''}\n\n` + for (const item of data.body) { + const ss = (item.idx + 1) + '\n' + formatVttTime(item.from) + ' --> ' + formatVttTime(item.to) + '\n' + ((item.content?.trim()) ?? '') + '\n\n' + s += ss + } + s = s.substring(0, s.length - 1)// remove last '\n' + fileName = 'download.vtt' + } else if (downloadType === 'json') { + s = JSON.stringify(data) + fileName = 'download.json' + } else if (downloadType === 'summarize') { + const [success, content] = getSummarize(title, segments, curSummaryType) + if (!success) return + s = content + fileName = '总结.txt' + } else { + return + } + if (download) { + downloadText(s, fileName) + } else { + navigator.clipboard.writeText(s).then(() => { + toast.success('复制成功') + }).catch(console.error) + } + setMoreVisible(false) + }, [curSummaryType, data, downloadType, segments, title]) + + const downloadAudioCallback = useCallback(() => { + window.parent.postMessage({ + type: 'downloadAudio', + }, '*') + }, []) + + const selectCallback = useCallback((e: any) => { + dispatch(setDownloadType(e.target.value)) + }, [dispatch]) + + const preventCallback = useCallback((e: any) => { + e.stopPropagation() + }, []) + + const moreCallback = useCallback((e: MouseEvent) => { + e.stopPropagation() + if (!envData.flagDot) { + dispatch(setEnvData({ + ...envData, + flagDot: true, + })) + } + setMoreVisible(!moreVisible) + // 显示菜单时自动展开,防止菜单显示不全 + if (!moreVisible) { + eventBus.emit({ + type: EVENT_EXPAND + }) + } + }, [dispatch, envData, eventBus, moreVisible]) + useClickAway(() => { + setMoreVisible(false) + }, moreRef) + + return <> +
+
+ {envReady && !envData.flagDot && } + +
+
+ {moreVisible && + + + } + +} + +export default MoreBtn diff --git a/src/biz/NormalSegmentItem.tsx b/src/biz/NormalSegmentItem.tsx new file mode 100644 index 0000000..e5a21a2 --- /dev/null +++ b/src/biz/NormalSegmentItem.tsx @@ -0,0 +1,35 @@ +import React, {useMemo} from 'react' +import {formatTime} from '../util/util' +import {useAppSelector} from '../hooks/redux' +import {getDisplay, getTransText} from '../util/biz_util' +import classNames from 'classnames' + +const NormalSegmentItem = (props: { + item: { + from: number + to: number + content: string + } + idx: number + isIn: boolean + moveCallback: (event: any) => void +}) => { + const {item, idx, isIn, moveCallback} = props + const transResult = useAppSelector(state => state.env.transResults[idx]) + const envData = useAppSelector(state => state.env.envData) + const fontSize = useAppSelector(state => state.env.envData.fontSize) + const autoTranslate = useAppSelector(state => state.env.autoTranslate) + const transText = useMemo(() => getTransText(transResult, envData.hideOnDisableAutoTranslate, autoTranslate), [autoTranslate, envData.hideOnDisableAutoTranslate, transResult]) + const display = useMemo(() => getDisplay(envData.transDisplay, item.content, transText), [envData.transDisplay, item.content, transText]) + + return
+
{formatTime(item.from)}
+
+
{display.main}
+ {display.sub &&
{display.sub}
} +
+
+} + +export default NormalSegmentItem diff --git a/src/biz/SegmentCard.tsx b/src/biz/SegmentCard.tsx new file mode 100644 index 0000000..1528c26 --- /dev/null +++ b/src/biz/SegmentCard.tsx @@ -0,0 +1,239 @@ +import React, {MutableRefObject, useCallback, useEffect, useMemo, useRef} from 'react' +import {useAppDispatch, useAppSelector} from '../hooks/redux' +import {setCurSummaryType, setFloatKeyPointsSegIdx, setPage, setSegmentFold} from '../redux/envReducer' +import classNames from 'classnames' +import {FaClipboardList} from 'react-icons/fa' +import {PAGE_MAIN, PAGE_SETTINGS, SUMMARIZE_THRESHOLD} from '../const' +import useTranslate from '../hooks/useTranslate' +import {BsDashSquare, BsPlusSquare, CgFileDocument, GrOverview, RiFileCopy2Line} from 'react-icons/all' +import toast from 'react-hot-toast' +import {getLastTime, getSummaryStr, isSummaryEmpty, parseStrTimeToSeconds} from '../util/biz_util' +import {useInViewport} from 'ahooks' +import SegmentItem from './SegmentItem' +import {stopPopFunc} from '../util/util' +import useSubtitle from '../hooks/useSubtitle' + +const SummarizeItemOverview = (props: { + segment: Segment + summary: OverviewSummary + segmentIdx: number + overviewItem: OverviewItem + idx: number +}) => { + const { segment, summary, segmentIdx, overviewItem, idx} = props + + const {move} = useSubtitle() + const time = parseStrTimeToSeconds(overviewItem.time) + const currentTime = useAppSelector(state => state.env.currentTime) + const isIn = useMemo(() => { + if (currentTime != null) { + // check in current segment + if (segment.items?.length > 0) { + const startTime = segment.items[0].from + const lastTime = segment.items[segment.items.length - 1].to + if (currentTime >= startTime && currentTime < lastTime) { + // check in current overview item + const nextOverviewItem = summary.content?.[idx + 1] + const nextTime = (nextOverviewItem != null)?parseStrTimeToSeconds(nextOverviewItem.time):null + return currentTime >= time && (nextTime == null || currentTime < nextTime) + } + } + } + return false + }, [currentTime, idx, segment.items, summary.content, time]) + + const moveCallback = useCallback((event: any) => { + if (event.altKey) { // 复制 + navigator.clipboard.writeText(overviewItem.key).catch(console.error) + } else { + move(time) + } + }, [overviewItem.key, move, time]) + + return
  • + {overviewItem.emoji} + {overviewItem.time} + {overviewItem.key} +
  • +} + +const Summarize = (props: { + segment: Segment + segmentIdx: number + summary?: Summary + float?: boolean +}) => { + const {segment, segmentIdx, summary, float} = props + + const dispatch = useAppDispatch() + const apiKey = useAppSelector(state => state.env.envData.apiKey) + const fontSize = useAppSelector(state => state.env.envData.fontSize) + const title = useAppSelector(state => state.env.title) + const curSummaryType = useAppSelector(state => state.env.curSummaryType) + const {addSummarizeTask} = useTranslate() + + const onGenerate = useCallback(() => { + if (apiKey) { + addSummarizeTask(title, curSummaryType, segment).catch(console.error) + } else { + dispatch(setPage(PAGE_SETTINGS)) + toast.error('需要先设置ApiKey!') + } + }, [addSummarizeTask, apiKey, curSummaryType, dispatch, segment, title]) + + const onCopy = useCallback(() => { + if (summary != null) { + navigator.clipboard.writeText(getSummaryStr(summary)).then(() => { + toast.success('已复制到剪贴板!') + }).catch(console.error) + } + }, [summary]) + + return
    + {(summary != null) && !isSummaryEmpty(summary) &&
    + +
    } +
    + {summary?.type === 'overview' && (summary.content != null) && +
      + {(summary.content).map((overviewItem: OverviewItem, idx: number) => + )} +
    } + {summary?.type === 'keypoint' && (summary.content != null) && +
      + {summary.content?.map((keyPoint: string, idx: number) =>
    • {keyPoint}
    • )} +
    } + {summary?.type === 'brief' && (summary.content != null) && +
    + {summary.content.summary} +
    } +
    +
    + {segment.text.length < SUMMARIZE_THRESHOLD &&
    文字过短,无法总结.
    } + {segment.text.length >= SUMMARIZE_THRESHOLD && ((summary == null) || summary.status !== 'done' || summary.error) && } + {summary?.error &&
    {summary?.error}
    } +
    + {!float &&
    } +
    +} + +const SegmentCard = (props: { + bodyRef: MutableRefObject + segment: Segment + segmentIdx: number +}) => { + const {bodyRef, segment, segmentIdx} = props + + const dispatch = useAppDispatch() + const summarizeRef = useRef(null) + const [inViewport] = useInViewport(summarizeRef, { + root: bodyRef.current, + }) + const segments = useAppSelector(state => state.env.segments) + const needScroll = useAppSelector(state => state.env.needScroll) + const curIdx = useAppSelector(state => state.env.curIdx) + const summarizeEnable = useAppSelector(state => state.env.envData.summarizeEnable) + const summarizeFloat = useAppSelector(state => state.env.envData.summarizeFloat) + const fold = useAppSelector(state => state.env.fold) + const page = useAppSelector(state => state.env.page) + const compact = useAppSelector(state => state.env.compact) + const floatKeyPointsSegIdx = useAppSelector(state => state.env.floatKeyPointsSegIdx) + const showCurrent = useMemo(() => curIdx != null && segment.startIdx <= curIdx && curIdx <= segment.endIdx, [curIdx, segment.endIdx, segment.startIdx]) + const curSummaryType = useAppSelector(state => state.env.curSummaryType) + const summary = useMemo(() => { + const result = segment.summaries[curSummaryType] + if (result) { + return result + } + return undefined + }, [curSummaryType, segment.summaries]) + + const onFold = useCallback(() => { + dispatch(setSegmentFold({ + segmentStartIdx: segment.startIdx, + fold: !segment.fold + })) + }, [dispatch, segment.fold, segment.startIdx]) + + // 检测设置floatKeyPointsSegIdx + useEffect(() => { + if (summarizeFloat) { // 已启用 + if (!fold && page === PAGE_MAIN && showCurrent) { // 当前Card有控制权 + if (!inViewport && (summary != null) && !isSummaryEmpty(summary)) { + dispatch(setFloatKeyPointsSegIdx(segment.startIdx)) + } else { + dispatch(setFloatKeyPointsSegIdx()) + } + } + } + }, [dispatch, fold, inViewport, page, segment.startIdx, showCurrent, summarizeFloat, summary]) + + const onSelBrief = useCallback(() => { + dispatch(setCurSummaryType('brief')) + }, [dispatch]) + + const onSelOverview = useCallback(() => { + dispatch(setCurSummaryType('overview')) + }, [dispatch]) + + const onSelKeypoint = useCallback(() => { + dispatch(setCurSummaryType('keypoint')) + }, [dispatch]) + + return
    +
    + {segments != null && segments.length > 1 && +
    + {segment.fold + ? : + } +
    } + {summarizeEnable &&
    + + 总结 + 概览 + 要点 + +
    } +
    {getLastTime(segment.items[segment.items.length - 1].to - segment.items[0].from)}
    +
    + {summarizeEnable &&
    + +
    } + {!segment.fold + ?
    + {!compact &&
    +
    时间
    +
    字幕内容
    +
    } + {segment.items.map((item: TranscriptItem, idx: number) => )} + {segments != null && segments.length > 1 && } +
    + : } + {floatKeyPointsSegIdx === segment.startIdx &&
    +
    + +
    +
    } +
    +} + +export default SegmentCard diff --git a/src/biz/SegmentItem.tsx b/src/biz/SegmentItem.tsx new file mode 100644 index 0000000..67fea73 --- /dev/null +++ b/src/biz/SegmentItem.tsx @@ -0,0 +1,70 @@ +import React, {useCallback, useEffect, useRef} from 'react' +import {useAppDispatch, useAppSelector} from '../hooks/redux' +import useSubtitle from '../hooks/useSubtitle' +import {setCheckAutoScroll, setCurOffsetTop, setNeedScroll} from '../redux/envReducer' +import NormalSegmentItem from './NormalSegmentItem' +import CompactSegmentItem from './CompactSegmentItem' + +const SegmentItem = (props: { + bodyRef: any + item: { + from: number + to: number + content: string + } + idx: number + isIn: boolean + needScroll?: boolean + last: boolean +}) => { + const dispatch = useAppDispatch() + const {bodyRef, item, idx, isIn, needScroll, last} = props + const ref = useRef() + const {move} = useSubtitle() + const compact = useAppSelector(state => state.env.compact) + + const moveCallback = useCallback((event: any) => { + if (event.altKey) { // 复制 + navigator.clipboard.writeText(item.content).catch(console.error) + } else { + move(item.from) + } + }, [item.content, item.from, move]) + + // 检测需要滚动进入视野 + useEffect(() => { + if (needScroll) { + bodyRef.current.scrollTop = ref.current.offsetTop - bodyRef.current.offsetTop - 40 + dispatch(setNeedScroll(false)) + } + }, [dispatch, needScroll, bodyRef]) + + // 进入时更新当前offsetTop + useEffect(() => { + if (isIn) { + dispatch(setCurOffsetTop(ref.current.offsetTop)) + dispatch(setCheckAutoScroll(true)) + } + }, [dispatch, isIn]) + + return + {compact + ? + : + + } + +} + +export default SegmentItem diff --git a/src/biz/Settings.tsx b/src/biz/Settings.tsx new file mode 100644 index 0000000..fe02548 --- /dev/null +++ b/src/biz/Settings.tsx @@ -0,0 +1,277 @@ +import React, {PropsWithChildren, useCallback, useMemo, useState} from 'react' +import {setEnvData, setPage} from '../redux/envReducer' +import {useAppDispatch, useAppSelector} from '../hooks/redux' +import { + HEADER_HEIGHT, + LANGUAGE_DEFAULT, + LANGUAGES, + PAGE_MAIN, + SERVER_URL_THIRD, + SUMMARIZE_LANGUAGE_DEFAULT, + TRANSLATE_FETCH_DEFAULT, + TRANSLATE_FETCH_MAX, + TRANSLATE_FETCH_MIN, + TRANSLATE_FETCH_STEP, + WORDS_DEFAULT, + WORDS_MAX, + WORDS_MIN, + WORDS_STEP +} from '../const' +import {IoWarning} from 'react-icons/all' +import classNames from 'classnames' +import toast from 'react-hot-toast' +import {useBoolean, useEventTarget} from 'ahooks' +import {useEventChecked} from '@kky002/kky-hooks' + +const Section = (props: { + title: ShowElement + htmlFor?: string +} & PropsWithChildren) => { + const {title, htmlFor, children} = props + return
    + +
    {children}
    +
    +} + +const FormItem = (props: { + title: ShowElement + tip?: string + htmlFor?: string +} & PropsWithChildren) => { + const {title, tip, htmlFor, children} = props + return
    +
    + +
    +
    + {children} +
    +
    +} + +const Settings = () => { + const dispatch = useAppDispatch() + const envData = useAppSelector(state => state.env.envData) + const {value: autoExpandValue, onChange: setAutoExpandValue} = useEventChecked(envData.autoExpand) + // const {value: autoScrollValue, onChange: setAutoScrollValue} = useEventChecked(envData.autoScroll) + const {value: translateEnableValue, onChange: setTranslateEnableValue} = useEventChecked(envData.translateEnable) + const {value: summarizeEnableValue, onChange: setSummarizeEnableValue} = useEventChecked(envData.summarizeEnable) + const {value: summarizeFloatValue, onChange: setSummarizeFloatValue} = useEventChecked(envData.summarizeFloat) + const [apiKeyValue, { onChange: onChangeApiKeyValue }] = useEventTarget({initialValue: envData.apiKey??''}) + const [serverUrlValue, setServerUrlValue] = useState(envData.serverUrl) + const [languageValue, { onChange: onChangeLanguageValue }] = useEventTarget({initialValue: envData.language??LANGUAGE_DEFAULT}) + const [summarizeLanguageValue, { onChange: onChangeSummarizeLanguageValue }] = useEventTarget({initialValue: envData.summarizeLanguage??SUMMARIZE_LANGUAGE_DEFAULT}) + const [hideOnDisableAutoTranslateValue, setHideOnDisableAutoTranslateValue] = useState(envData.hideOnDisableAutoTranslate) + const [themeValue, setThemeValue] = useState(envData.theme) + const [fontSizeValue, setFontSizeValue] = useState(envData.fontSize) + const [transDisplayValue, setTransDisplayValue] = useState(envData.transDisplay) + const [wordsValue, setWordsValue] = useState(envData.words??WORDS_DEFAULT) + const [fetchAmountValue, setFetchAmountValue] = useState(envData.fetchAmount??TRANSLATE_FETCH_DEFAULT) + const [moreFold, {toggle: toggleMoreFold}] = useBoolean(true) + const fold = useAppSelector(state => state.env.fold) + const totalHeight = useAppSelector(state => state.env.totalHeight) + const wordsList = useMemo(() => { + const list = [] + for (let i = WORDS_MIN; i <= WORDS_MAX; i += WORDS_STEP) { + list.push(i) + } + return list + }, []) + const transFetchAmountList = useMemo(() => { + const list = [] + for (let i = TRANSLATE_FETCH_MIN; i <= TRANSLATE_FETCH_MAX; i += TRANSLATE_FETCH_STEP) { + list.push(i) + } + return list + }, []) + + const onChangeHideOnDisableAutoTranslate = useCallback((e: any) => { + setHideOnDisableAutoTranslateValue(e.target.checked) + }, []) + + const onSave = useCallback(() => { + dispatch(setEnvData({ + autoExpand: autoExpandValue, + apiKey: apiKeyValue, + serverUrl: serverUrlValue, + translateEnable: translateEnableValue, + language: languageValue, + hideOnDisableAutoTranslate: hideOnDisableAutoTranslateValue, + theme: themeValue, + transDisplay: transDisplayValue, + summarizeEnable: summarizeEnableValue, + summarizeFloat: summarizeFloatValue, + summarizeLanguage: summarizeLanguageValue, + words: wordsValue, + fetchAmount: fetchAmountValue, + fontSize: fontSizeValue, + })) + dispatch(setPage(PAGE_MAIN)) + toast.success('保存成功') + }, [fontSizeValue, apiKeyValue, autoExpandValue, dispatch, fetchAmountValue, hideOnDisableAutoTranslateValue, languageValue, serverUrlValue, summarizeEnableValue, summarizeFloatValue, summarizeLanguageValue, themeValue, transDisplayValue, translateEnableValue, wordsValue]) + + const onCancel = useCallback(() => { + dispatch(setPage(PAGE_MAIN)) + }, [dispatch]) + + const onFetchAmountChange = useCallback((e: any) => { + setFetchAmountValue(parseInt(e.target.value)) + }, []) + + const onWordsChange = useCallback((e: any) => { + setWordsValue(parseInt(e.target.value)) + }, []) + + const onSel1 = useCallback(() => { + setTransDisplayValue('originPrimary') + }, []) + + const onSel2 = useCallback(() => { + setTransDisplayValue('targetPrimary') + }, []) + + const onSel3 = useCallback(() => { + setTransDisplayValue('target') + }, []) + + const onSelTheme1 = useCallback(() => { + setThemeValue('system') + }, []) + + const onSelTheme2 = useCallback(() => { + setThemeValue('light') + }, []) + + const onSelTheme3 = useCallback(() => { + setThemeValue('dark') + }, []) + + const onSelFontSize1 = useCallback(() => { + setFontSizeValue('normal') + }, []) + + const onSelFontSize2 = useCallback(() => { + setFontSizeValue('large') + }, []) + + return
    +
    +
    + + + + +
    + + + +
    +
    + +
    + + +
    +
    +
    +
    + + + + + setServerUrlValue(e.target.value)}/> + + + {!moreFold &&
    + +
    } +
    +
    + 翻译配置 + {!apiKeyValue &&
    + +
    } +
    }> + + + + + + + +
    + +
    + {transFetchAmountList.map(amount => {amount})} +
    +
    +
    + +
    + + + +
    +
    + + + + +
    + 总结配置 + {!apiKeyValue &&
    + +
    } +
    }> + + + + + + + + + + +
    + +
    + {wordsList.map(words => {words})} +
    +
    +
    + +
    + + +
    + + +} + +export default Settings diff --git a/src/chrome/background.ts b/src/chrome/background.ts new file mode 100644 index 0000000..005c9e5 --- /dev/null +++ b/src/chrome/background.ts @@ -0,0 +1,72 @@ +import {v4} from 'uuid' +import {handleTask, initTaskService, tasksMap} from './taskService' + +/** + * 消息处理入口 + * 注意:需要异步sendResponse时返回true + */ +chrome.runtime.onMessage.addListener((event, sender, sendResponse) => { + console.debug('收到请求: ', event) + if (event.type === 'p') { // 发出http请求 + const {url, options} = event + // 发出请求 + fetch('http://localhost:27081/oproxy/p', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + url, + options, + }), + }).then(async res => await res.json()).then(sendResponse).catch(console.error) + return true + } else if (event.type === 'syncGet') { // sync.get + chrome.storage.sync.get(event.keys, data => { + sendResponse(data) + }) + return true + } else if (event.type === 'syncSet') { // sync.set + chrome.storage.sync.set(event.items).catch(console.error) + } else if (event.type === 'syncRemove') { // sync.remove + chrome.storage.sync.remove(event.keys).catch(console.error) + } else if (event.type === 'addTask') { + // 新建任务 + const task: Task = { + id: v4(), + startTime: Date.now(), + status: 'pending', + def: event.taskDef, + } + tasksMap.set(task.id, task) + + // 立即触发任务 + handleTask(task).catch(console.error) + + // 返回任务信息 + sendResponse(task) + } else if (event.type === 'getTask') { + // 返回任务信息 + const taskId = event.taskId + const task = tasksMap.get(taskId) + if (task == null) { + sendResponse({ + code: 'not_found', + }) + return + } + + // 检测删除缓存 + if (task.status === 'done') { + tasksMap.delete(taskId) + } + + // 返回任务 + sendResponse({ + code: 'ok', + task, + }) + } +}) + +initTaskService() diff --git a/src/chrome/content-script.cjs b/src/chrome/content-script.cjs new file mode 100644 index 0000000..47d5840 --- /dev/null +++ b/src/chrome/content-script.cjs @@ -0,0 +1,238 @@ +const {TOTAL_HEIGHT_DEF, HEADER_HEIGHT, TOTAL_HEIGHT_MIN, TOTAL_HEIGHT_MAX} = require("../const"); +var totalHeight = TOTAL_HEIGHT_DEF + +const getVideoElement = () => { + const videoWrapper = document.getElementById('bilibili-player') + return videoWrapper.querySelector('video') +} + +var danmukuBoxLoaded = false +setInterval(function () { + if (danmukuBoxLoaded) return + + var danmukuBox = document.getElementById('danmukuBox') + if (danmukuBox) { + danmukuBoxLoaded = true + setTimeout(function () { + var vKey = '' + for (const key in danmukuBox?.dataset) { + if (key.startsWith('v-')) { + vKey = key + break + } + } + + const iframe = document.createElement('iframe') + iframe.id = 'bilibili-subtitle-iframe' + iframe.src = chrome.runtime.getURL('index.html') + iframe.style = 'border: none; width: 100%; height: 44px;' + iframe.allow = 'clipboard-read; clipboard-write;' + if (vKey) { + iframe.dataset[vKey] = danmukuBox?.dataset[vKey] + } + //insert before first child + danmukuBox?.insertBefore(iframe, danmukuBox?.firstChild) + }, 1500) + } +}, 1000) + +let aid = 0 +let title = '' +let pages = [] +let pagesMap = {} + +let lastAidOrBvid = null +const refreshVideoInfo = async () => { + const iframe = document.getElementById('bilibili-subtitle-iframe') + if (!iframe) return + + let path = location.pathname + if (path.endsWith('/')) { + path = path.slice(0, -1) + } + const paths = path.split('/') + const aidOrBvid = paths[paths.length - 1] + + if (aidOrBvid !== lastAidOrBvid) { + // console.debug('refreshVideoInfo') + + lastAidOrBvid = aidOrBvid + if (aidOrBvid) { + //aid,pages + let cid + let subtitles + if (aidOrBvid.toLowerCase().startsWith('av')) {//avxxx + title = '' + aid = aidOrBvid.slice(2) + cid = 1 + pages = await fetch(`https://api.bilibili.com/x/player/pagelist?aid=${aid}`, {credentials: 'include'}).then(res => res.json()).then(res => res.data) + subtitles = await fetch(`https://api.bilibili.com/x/player/v2?aid=${aid}&cid=${cid}`, {credentials: 'include'}).then(res => res.json()).then(res => res.data.subtitle.subtitles) + } else {//bvxxx + pages = await fetch(`https://api.bilibili.com/x/web-interface/view?bvid=${aidOrBvid}`, {credentials: 'include'}).then(res => res.json()).then(res => { + title = res.data.title + aid = res.data.aid + cid = res.data.cid + subtitles = res.data.subtitle.list + return res.data.pages + }) + } + + //pagesMap + pagesMap = {} + pages.forEach(page => { + pagesMap[page.page + ''] = page + }) + + console.debug('refreshVideoInfo: ', aid, cid, pages, subtitles) + + //send setVideoInfo + iframe.contentWindow.postMessage({ + type: 'setVideoInfo', + title, + aid, + pages, + infos: subtitles, + }, '*') + } + } +} + +let lastAid = null +let lastCid = null +const refreshSubtitles = () => { + const iframe = document.getElementById('bilibili-subtitle-iframe') + if (!iframe) return + + const urlSearchParams = new URLSearchParams(window.location.search) + const p = urlSearchParams.get('p') || 1 + const page = pagesMap[p] + if (!page) return + const cid = page.cid + + if (aid !== lastAid || cid !== lastCid) { + console.debug('refreshSubtitles', aid, cid) + + lastAid = aid + lastCid = cid + if (aid && cid) { + fetch(`https://api.bilibili.com/x/player/v2?aid=${aid}&cid=${cid}`, { + credentials: 'include', + }) + .then(res => res.json()) + .then(res => { + // console.log('refreshSubtitles: ', aid, cid, res) + iframe.contentWindow.postMessage({ + type: 'setInfos', + infos: res.data.subtitle.subtitles + }, '*') + }) + } + } +} + +// 监听消息 +window.addEventListener("message", (event) => { + const {data} = event + + if (data.type === 'fold') { + const iframe = document.getElementById('bilibili-subtitle-iframe') + iframe.style.height = (data.fold ? HEADER_HEIGHT : totalHeight) + 'px' + } + + if (data.type === 'move') { + const video = getVideoElement() + if (video) { + video.currentTime = data.time + } + } + + //刷新视频信息 + if (data.type === 'refreshVideoInfo') { + refreshVideoInfo().catch(console.error) + } + //刷新字幕 + if (data.type === 'refreshSubtitles') { + refreshSubtitles() + } + if (data.type === 'getSubtitle') { + let url = data.info.subtitle_url + if (url.startsWith('http://')) { + url = url.replace('http://', 'https://') + } + fetch(url).then(res => res.json()).then(res => { + event.source.postMessage({ + data: { + info: data.info, + data: res, + }, type: 'setSubtitle' + }, '*') + }) + } + + if (data.type === 'getCurrentTime') { + const video = getVideoElement() + if (video) { + event.source.postMessage({ + data: { + currentTime: video.currentTime + }, type: 'setCurrentTime' + }, '*') + } + } + + if (data.type === 'getSettings') { + const videoElement = getVideoElement() + totalHeight = videoElement ? Math.min(Math.max(videoElement.offsetHeight, TOTAL_HEIGHT_MIN), TOTAL_HEIGHT_MAX) : TOTAL_HEIGHT_DEF + event.source.postMessage({ + data: { + noVideo: !videoElement, + totalHeight, + }, type: 'setSettings' + }, '*') + } + + if (data.type === 'downloadAudio') { + const html = document.getElementsByTagName('html')[0].innerHTML + const playInfo = JSON.parse(html.match(/window.__playinfo__=(.+?)<\/script/)[1]) + const audioUrl = playInfo.data.dash.audio[0].baseUrl + + fetch(audioUrl).then(res => res.blob()).then(blob => { + const a = document.createElement('a') + a.href = URL.createObjectURL(blob) + a.download = `${title}.m4s` + a.click() + }) + } + + if (data.type === 'updateTransResult') { + const trans = data.result??'' + let text = document.getElementById('trans-result-text') + if (text) { + text.innerHTML = trans + } else { + const container = document.getElementsByClassName('bpx-player-subtitle-panel-wrap')?.[0] + if (container) { + const div = document.createElement('div') + div.style.display = 'flex' + div.style.justifyContent = 'center' + div.style.margin = '2px' + text = document.createElement('text') + text.id = 'trans-result-text' + text.innerHTML = trans + text.style.fontSize = '1rem' + text.style.padding = '5px' + text.style.color = 'white' + text.style.background = 'rgba(0, 0, 0, 0.4)' + div.append(text) + + container.append(div) + } + } + text.style.display = trans ? 'block' : 'none' + } +}, false); + +setInterval(() => { + refreshVideoInfo().catch(console.error) + refreshSubtitles() +}, 1000) diff --git a/src/chrome/openaiService.ts b/src/chrome/openaiService.ts new file mode 100644 index 0000000..efda32a --- /dev/null +++ b/src/chrome/openaiService.ts @@ -0,0 +1,20 @@ +import {getServerUrl} from '../util/biz_util' + +export const handleChatCompleteTask = async (task: Task) => { + const data = task.def.data + const serverUrl = getServerUrl(task.def.serverUrl) + const resp = await fetch(`${serverUrl}/v1/chat/completions`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + task.def.extra.apiKey, + }, + body: JSON.stringify(data), + }) + task.resp = await resp.json() + if (task.resp.usage) { + return (task.resp.usage.total_tokens??0) > 0 + } else { + throw new Error(`${task.resp.error.code as string??''} ${task.resp.error.message as string ??''}`) + } +} diff --git a/src/chrome/taskService.ts b/src/chrome/taskService.ts new file mode 100644 index 0000000..d4c85e4 --- /dev/null +++ b/src/chrome/taskService.ts @@ -0,0 +1,51 @@ +import {TASK_EXPIRE_TIME} from '../const' +import {handleChatCompleteTask} from './openaiService' + +export const tasksMap = new Map() + +export const handleTask = async (task: Task) => { + console.debug(`处理任务: ${task.id} (type: ${task.def.type})`) + try { + task.status = 'running' + switch (task.def.type) { + case 'chatComplete': + await handleChatCompleteTask(task) + break + default: + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + throw new Error(`任务类型不支持: ${task.def.type}`) + } + + console.debug(`处理任务成功: ${task.id} (type: ${task.def.type})`) + } catch (e: any) { + task.error = e.message + console.debug(`处理任务失败: ${task.id} (type: ${task.def.type})`, e.message) + } + task.status = 'done' + task.endTime = Date.now() +} + +export const initTaskService = () => { + // 处理任务: tasksMap + setInterval(() => { + for (const [_, task] of tasksMap) { + if (task.status === 'pending') { + handleTask(task).catch(console.error) + break + } else if (task.status === 'running') { + break + } + } + }, 1000) + // 检测清理tasksMap + setInterval(() => { + const now = Date.now() + + for (const [taskId, task] of tasksMap) { + if (task.startTime < now - TASK_EXPIRE_TIME) { + tasksMap.delete(taskId) + console.debug(`清理任务: ${task.id} (type: ${task.def.type})`) + } + } + }, 10000) +} diff --git a/src/components/Popover.module.less b/src/components/Popover.module.less new file mode 100644 index 0000000..2d349d8 --- /dev/null +++ b/src/components/Popover.module.less @@ -0,0 +1,32 @@ +.arrow, .arrow::before { + position: absolute; + width: 8px; + height: 8px; + background: inherit; +} + +.arrow { + visibility: hidden; +} + +.arrow::before { + visibility: visible; + content: ''; + transform: rotate(45deg); +} + +.tooltip[data-popper-placement^='top'] > .arrow { + bottom: -4px; +} + +.tooltip[data-popper-placement^='bottom'] > .arrow { + top: -4px; +} + +.tooltip[data-popper-placement^='left'] > .arrow { + right: -4px; +} + +.tooltip[data-popper-placement^='right'] > .arrow { + left: -4px; +} diff --git a/src/components/Popover.tsx b/src/components/Popover.tsx new file mode 100644 index 0000000..2924cca --- /dev/null +++ b/src/components/Popover.tsx @@ -0,0 +1,40 @@ +import {PropsWithChildren, useState} from 'react' +import {Modifier, usePopper} from 'react-popper' +import popoverStyles from './Popover.module.less' +import * as PopperJS from '@popperjs/core' +import classNames from 'classnames' + +interface Props extends PropsWithChildren { + /** + * 用于定位弹出框的元素 + */ + refElement: Element | PopperJS.VirtualElement | null + className?: string | undefined + arrowClassName?: string | undefined + options?: Omit, 'modifiers'> & { + createPopper?: typeof PopperJS.createPopper + modifiers?: ReadonlyArray> + } +} + +const Popover = (props: Props) => { + const {children, className, arrowClassName, refElement, options} = props + + const [popperElement, setPopperElement] = useState(null) + const [arrowElement, setArrowElement] = useState(null) + const { styles, attributes } = usePopper(refElement, popperElement, { + placement: 'top', + modifiers: [ + {name: 'arrow', options: {element: arrowElement}}, + {name: 'offset', options: {offset: [0, 8]}}, + ], + ...options??{}, + }) + + return
    +
    + {children} +
    +} + +export default Popover diff --git a/src/const.tsx b/src/const.tsx new file mode 100644 index 0000000..0f3c739 --- /dev/null +++ b/src/const.tsx @@ -0,0 +1,76 @@ +export const APP_DOM_ID = 'bilibili-subtitle' + +export const STORAGE_ENV = 'bilibili-subtitle_env' + +export const EVENT_EXPAND = 'expand' + +export const TASK_EXPIRE_TIME = 15*60*1000 + +export const PAGE_MAIN = 'main' +export const PAGE_SETTINGS = 'settings' + +export const TRANSLATE_COOLDOWN = 5*1000 +export const TRANSLATE_FETCH_DEFAULT = 15 +export const TRANSLATE_FETCH_MIN = 5 +export const TRANSLATE_FETCH_MAX = 25 +export const TRANSLATE_FETCH_STEP = 5 +export const LANGUAGE_DEFAULT = 'en' + +export const TOTAL_HEIGHT_MIN = 400 +export const TOTAL_HEIGHT_DEF = 520 +export const TOTAL_HEIGHT_MAX = 800 +export const HEADER_HEIGHT = 44 +export const TITLE_HEIGHT = 24 + +export const WORDS_DEFAULT = import.meta.env.VITE_ENV === 'web-dev'?500:2000 +export const WORDS_MIN = 1000 +export const WORDS_MAX = 3000 +export const WORDS_STEP = 500 +export const SUMMARIZE_THRESHOLD = 100 +export const SUMMARIZE_LANGUAGE_DEFAULT = 'cn' +export const SUMMARIZE_ALL_THRESHOLD = 5 + +export const SERVER_URL_OPENAI = 'https://api.openai.com' +export const SERVER_URL_THIRD = 'https://op.kongkongye.com' + +export const LANGUAGES = [{ + code: 'en', + name: 'English', +}, { + code: 'ena', + name: 'American English', +}, { + code: 'enb', + name: 'British English', +}, { + code: 'cn', + name: '中文简体', +}, { + code: 'cnt', + name: '中文繁体', +}, { + code: 'Spanish', + name: 'español', +}, { + code: 'French', + name: 'Français', +}, { + code: 'Arabic', + name: 'العربية', +}, { + code: 'Russian', + name: 'русский', +}, { + code: 'German', + name: 'Deutsch', +}, { + code: 'Portuguese', + name: 'Português', +}, { + code: 'Italian', + name: 'Italiano', +}] +export const LANGUAGES_MAP: {[key: string]: typeof LANGUAGES[number]} = {} +for (const language of LANGUAGES) { + LANGUAGES_MAP[language.code] = language +} diff --git a/src/data/data.json b/src/data/data.json new file mode 100644 index 0000000..b3013f3 --- /dev/null +++ b/src/data/data.json @@ -0,0 +1,864 @@ +{ + "font_size": 0.4, + "font_color": "#FFFFFF", + "background_alpha": 0.5, + "background_color": "#9C27B0", + "Stroke": "none", + "type": "AIsubtitle", + "lang": "zh", + "version": "a1.3.0.2", + "body": [ + { + "from": 0.666, + "to": 1.799, + "location": 0, + "content": "各位听众朋友大家好" + }, + { + "from": 1.8, + "to": 4.3, + "location": 0, + "content": "欢迎来到旧世代电台我是Lunmos" + }, + { + "from": 4.4, + "to": 5.466, + "location": 0, + "content": "我们这期呢" + }, + { + "from": 5.466, + "to": 6.966, + "location": 0, + "content": "来聊一个真正的" + }, + { + "from": 6.966, + "to": 9.766, + "location": 0, + "content": "我觉得可能是新旧世代" + }, + { + "from": 10.3, + "to": 12.333, + "location": 0, + "content": "分界线的这么一件事情" + }, + { + "from": 12.733, + "to": 15.133, + "location": 0, + "content": "那首先呢还是来一个思维实验" + }, + { + "from": 15.2, + "to": 17.5, + "location": 0, + "content": "上期其实我们也已经提到了" + }, + { + "from": 17.5, + "to": 19.7, + "location": 0, + "content": "就是一个上世纪末的人" + }, + { + "from": 19.7, + "to": 22.4, + "location": 0, + "content": "如果穿越到了2023年的现在" + }, + { + "from": 22.733, + "to": 24.766, + "location": 0, + "content": "我们已经发展了20多年的" + }, + { + "from": 24.8, + "to": 26.3, + "location": 0, + "content": "这么一个21世纪" + }, + { + "from": 26.333, + "to": 27.766, + "location": 0, + "content": "就在此时此刻" + }, + { + "from": 28, + "to": 28.8, + "location": 0, + "content": "那么" + }, + { + "from": 29.7, + "to": 31.966, + "location": 0, + "content": "你问他他会被什么东西" + }, + { + "from": 32.4, + "to": 34.533, + "location": 0, + "content": "所吓尿所吓到" + }, + { + "from": 35.4, + "to": 35.933, + "location": 0, + "content": "那当然了" + }, + { + "from": 35.933, + "to": 37.133, + "location": 0, + "content": "看过上期电台的朋友" + }, + { + "from": 37.133, + "to": 39.099, + "location": 0, + "content": "已经知道我想说的那个答案了" + }, + { + "from": 39.1, + "to": 41.3, + "location": 0, + "content": "不妨我们可以先来试试" + }, + { + "from": 41.466, + "to": 42.966, + "location": 0, + "content": "感觉一下其他方面" + }, + { + "from": 42.966, + "to": 45.599, + "location": 0, + "content": "我们有哪些地方发展的还算可以" + }, + { + "from": 46.133, + "to": 47.599, + "location": 0, + "content": "比如说航空航天" + }, + { + "from": 47.6, + "to": 51.066, + "location": 0, + "content": "他会被现在的航空航天科技所震惊吗" + }, + { + "from": 51.066, + "to": 52.199, + "location": 0, + "content": "我觉得" + }, + { + "from": 52.6, + "to": 53.366, + "location": 0, + "content": "不见得对吧" + }, + { + "from": 53.366, + "to": 55.966, + "location": 0, + "content": "现在虽然说有了一些可回收的" + }, + { + "from": 55.966, + "to": 57.499, + "location": 0, + "content": "航空航天的一些" + }, + { + "from": 57.733, + "to": 59.599, + "location": 0, + "content": "科技虽然说有了一些" + }, + { + "from": 59.6, + "to": 61, + "location": 0, + "content": "当时人们可能没太" + }, + { + "from": 61, + "to": 62.466, + "location": 0, + "content": "见到的一些科技路线" + }, + { + "from": 62.466, + "to": 63.266, + "location": 0, + "content": "但是" + }, + { + "from": 63.966, + "to": 64.733, + "location": 0, + "content": "总体上来说" + }, + { + "from": 64.733, + "to": 65.099, + "location": 0, + "content": "还是" + }, + { + "from": 65.1, + "to": 67.8, + "location": 0, + "content": "现在的人被那个时候吓得还差不多" + }, + { + "from": 67.8, + "to": 69.666, + "location": 0, + "content": "上个时期的美苏争霸时期" + }, + { + "from": 69.666, + "to": 71.299, + "location": 0, + "content": "人们是有意愿在" + }, + { + "from": 71.566, + "to": 73.866, + "location": 0, + "content": "航空航天的科技上去点科技术的" + }, + { + "from": 73.866, + "to": 76.133, + "location": 0, + "content": "无论是为意志形态服务宣传也好" + }, + { + "from": 76.133, + "to": 76.933, + "location": 0, + "content": "还是为了" + }, + { + "from": 77.1, + "to": 78.9, + "location": 0, + "content": "真实可能存在的一种" + }, + { + "from": 79.133, + "to": 79.666, + "location": 0, + "content": "更高的" + }, + { + "from": 79.666, + "to": 82.666, + "location": 0, + "content": "所谓说更高维度的战争的形态也好" + }, + { + "from": 82.866, + "to": 84.766, + "location": 0, + "content": "那么人类愿意去倾斜资源" + }, + { + "from": 84.766, + "to": 86.966, + "location": 0, + "content": "去让那些在这些科技中" + }, + { + "from": 87.466, + "to": 90.266, + "location": 0, + "content": "引领了发展进步的人成为英雄" + }, + { + "from": 90.266, + "to": 91.399, + "location": 0, + "content": "那么这样" + }, + { + "from": 91.4, + "to": 91.9, + "location": 0, + "content": "才能够" + }, + { + "from": 91.9, + "to": 94.533, + "location": 0, + "content": "如愿以偿的得到他们想要的结果" + }, + { + "from": 96.066, + "to": 97.466, + "location": 0, + "content": "好航空航天不太行" + }, + { + "from": 97.466, + "to": 100.666, + "location": 0, + "content": "那么我们引以为豪的移动互联网" + }, + { + "from": 100.666, + "to": 101.666, + "location": 0, + "content": "社交网络" + }, + { + "from": 101.666, + "to": 103.366, + "location": 0, + "content": "这个你觉得可以吗" + }, + { + "from": 103.366, + "to": 104.766, + "location": 0, + "content": "我觉得也不太行对吧" + }, + { + "from": 104.766, + "to": 106.999, + "location": 0, + "content": "我们甚至很多现代人都觉得" + }, + { + "from": 107.566, + "to": 108.699, + "location": 0, + "content": "从这些移动互联网" + }, + { + "from": 108.7, + "to": 110.966, + "location": 0, + "content": "从这些社交网络中涉及到的东西" + }, + { + "from": 110.966, + "to": 113.366, + "location": 0, + "content": "不一定是一个什么那么好的东西" + }, + { + "from": 113.366, + "to": 114.466, + "location": 0, + "content": "那么他呢" + }, + { + "from": 114.466, + "to": 116.133, + "location": 0, + "content": "当然也会觉得很新奇" + }, + { + "from": 116.366, + "to": 118.266, + "location": 0, + "content": "但是他不会觉得这是一件" + }, + { + "from": 118.7, + "to": 121.133, + "location": 0, + "content": "多么真正的了不起的事情" + }, + { + "from": 121.133, + "to": 122.866, + "location": 0, + "content": "那无非就是把以前的摩尔定律" + }, + { + "from": 122.866, + "to": 123.999, + "location": 0, + "content": "继续进行下去" + }, + { + "from": 124, + "to": 126.266, + "location": 0, + "content": "然后不断的缩小计算机的体积" + }, + { + "from": 126.866, + "to": 127.266, + "location": 0, + "content": "最终呢" + }, + { + "from": 127.266, + "to": 129.533, + "location": 0, + "content": "总会能够实现的这么一件事对吧" + }, + { + "from": 129.533, + "to": 130.733, + "location": 0, + "content": "手机能上网" + }, + { + "from": 130.733, + "to": 132.266, + "location": 0, + "content": "无线网络如此之发达" + }, + { + "from": 132.4, + "to": 134.466, + "location": 0, + "content": "也是一个基础设施的扩展" + }, + { + "from": 134.466, + "to": 136.599, + "location": 0, + "content": "基础设施的扩张所能实现的事" + }, + { + "from": 136.7, + "to": 139.166, + "location": 0, + "content": "那么人们其实并不会太折服于" + }, + { + "from": 139.166, + "to": 140.899, + "location": 0, + "content": "使用大规模基础建设" + }, + { + "from": 140.9, + "to": 143.166, + "location": 0, + "content": "就能够实现的某件事情" + }, + { + "from": 143.166, + "to": 145.966, + "location": 0, + "content": "因为人们总会预期未来" + }, + { + "from": 146.466, + "to": 147.333, + "location": 0, + "content": "未来的某一天" + }, + { + "from": 147.333, + "to": 150.699, + "location": 0, + "content": "或慢或快的总会出现那么一个时代的" + }, + { + "from": 150.7, + "to": 152.466, + "location": 0, + "content": "那就比如说大航海时代的人" + }, + { + "from": 152.733, + "to": 153.799, + "location": 0, + "content": "他们也会想" + }, + { + "from": 153.8, + "to": 156.5, + "location": 0, + "content": "未来的航路海运可能会非常的发达" + }, + { + "from": 156.5, + "to": 158.733, + "location": 0, + "content": "那未来可能遍地都是像阿姆斯特丹" + }, + { + "from": 158.733, + "to": 160.299, + "location": 0, + "content": "像伦敦这样的港口" + }, + { + "from": 160.666, + "to": 161.799, + "location": 0, + "content": "虽然现在不是这样" + }, + { + "from": 161.8, + "to": 162.166, + "location": 0, + "content": "但是" + }, + { + "from": 162.166, + "to": 164.866, + "location": 0, + "content": "处在他们能想象的社会发展的极限" + }, + { + "from": 165, + "to": 166.333, + "location": 0, + "content": "那我们也提到过游戏" + }, + { + "from": 166.333, + "to": 168.533, + "location": 0, + "content": "但也就像有朋友在弹幕中提到的" + }, + { + "from": 168.533, + "to": 170.599, + "location": 0, + "content": "想想时之笛是什么年代的游戏" + }, + { + "from": 170.6, + "to": 171.3, + "location": 0, + "content": "那现在呢" + }, + { + "from": 171.3, + "to": 174.066, + "location": 0, + "content": "甚至还在很多的游戏排行榜中" + }, + { + "from": 174.066, + "to": 174.899, + "location": 0, + "content": "排在第一" + }, + { + "from": 175.3, + "to": 176.8, + "location": 0, + "content": "那你想让那个时候的人" + }, + { + "from": 176.8, + "to": 178.933, + "location": 0, + "content": "真正折服于现在的游戏呢" + }, + { + "from": 179.466, + "to": 180.599, + "location": 0, + "content": "也没有那么容易对吧" + }, + { + "from": 180.6, + "to": 181.7, + "location": 0, + "content": "在图形学上" + }, + { + "from": 181.866, + "to": 182.399, + "location": 0, + "content": "我们也提到" + }, + { + "from": 182.4, + "to": 183.3, + "location": 0, + "content": "图形学的发展" + }, + { + "from": 183.3, + "to": 185.4, + "location": 0, + "content": "是不断把离线变成实时的过程" + }, + { + "from": 185.666, + "to": 187.333, + "location": 0, + "content": "那么他们见过离线的东西" + }, + { + "from": 187.333, + "to": 188.299, + "location": 0, + "content": "他们可以预测" + }, + { + "from": 188.3, + "to": 191.4, + "location": 0, + "content": "这样的离线动画在将来会变成实时" + }, + { + "from": 191.6, + "to": 193.166, + "location": 0, + "content": "那所以呢也不会觉得" + }, + { + "from": 193.666, + "to": 194.899, + "location": 0, + "content": "超出认知对吧" + }, + { + "from": 195.466, + "to": 196.933, + "location": 0, + "content": "那比如说生物医疗呢" + }, + { + "from": 196.966, + "to": 198.899, + "location": 0, + "content": "那虽然说可以说有不少的进" + }, + { + "from": 198.9, + "to": 199.566, + "location": 0, + "content": "展但还" + }, + { + "from": 199.566, + "to": 201.733, + "location": 0, + "content": "是建立在去完善20世纪" + }, + { + "from": 201.733, + "to": 203.066, + "location": 0, + "content": "这样一个科学大厦" + }, + { + "from": 203.066, + "to": 204.566, + "location": 0, + "content": "生物大厦的基础上" + }, + { + "from": 204.566, + "to": 205.866, + "location": 0, + "content": "对他进行了一些完善" + }, + { + "from": 206.2, + "to": 208.166, + "location": 0, + "content": "你要说那些折磨着现代人的" + }, + { + "from": 208.166, + "to": 209.399, + "location": 0, + "content": "各种各样的疾病" + }, + { + "from": 209.466, + "to": 210.733, + "location": 0, + "content": "那个时候没有攻克的" + }, + { + "from": 210.733, + "to": 213.366, + "location": 0, + "content": "现在有多少是被真正攻克了的呢" + }, + { + "from": 213.366, + "to": 215.133, + "location": 0, + "content": "那其实也很少对吧" + }, + { + "from": 215.266, + "to": 217.733, + "location": 0, + "content": "甚至可能我们连他的致病机理" + }, + { + "from": 217.733, + "to": 219.499, + "location": 0, + "content": "还没有完全的搞清楚" + }, + { + "from": 220.466, + "to": 221.699, + "location": 0, + "content": "其他可能还有一些比如" + }, + { + "from": 221.933, + "to": 223.199, + "location": 0, + "content": "像可控核聚变" + }, + { + "from": 223.2, + "to": 225.533, + "location": 0, + "content": "想更高效的电池技术这些" + }, + { + "from": 226.3, + "to": 228.766, + "location": 0, + "content": "那就是目前可能还在发展的地方" + }, + { + "from": 228.766, + "to": 229.899, + "location": 0, + "content": "怎么怎么说呢" + }, + { + "from": 229.9, + "to": 230.733, + "location": 0, + "content": "就是到他" + }, + { + "from": 230.733, + "to": 233.166, + "location": 0, + "content": "真正的出现了可以使用的成果之后呢" + }, + { + "from": 233.166, + "to": 235.866, + "location": 0, + "content": "我们才能够去拿下来" + }, + { + "from": 235.866, + "to": 238.533, + "location": 0, + "content": "让那些旧世代人的那些人" + }, + { + "from": 238.533, + "to": 239.599, + "location": 0, + "content": "感到比较的震惊" + }, + { + "from": 239.6, + "to": 239.9, + "location": 0, + "content": "但是" + }, + { + "from": 239.9, + "to": 243.266, + "location": 0, + "content": "现在可能还没到那个完成的时间点吧" + }, + { + "from": 244.4, + "to": 245.133, + "location": 0, + "content": "那么延续了" + }, + { + "from": 245.133, + "to": 247.466, + "location": 0, + "content": "上个世纪的第三次科技革命中的" + }, + { + "from": 247.466, + "to": 249.366, + "location": 0, + "content": "计算机软硬件的发展呢" + }, + { + "from": 249.566, + "to": 251.599, + "location": 0, + "content": "其实惊喜也没有那么多" + }, + { + "from": 251.6, + "to": 253.766, + "location": 0, + "content": "就上世纪的那些互联网应用" + }, + { + "from": 253.9, + "to": 256.133, + "location": 0, + "content": "那很多时候其实已经挺好用了" + }, + { + "from": 256.266, + "to": 257.733, + "location": 0, + "content": "论坛是上世纪的" + }, + { + "from": 257.8, + "to": 260.133, + "location": 0, + "content": "那么i m软件是上世纪的" + }, + { + "from": 260.133, + "to": 261.066, + "location": 0, + "content": "现在的互联网呢" + }, + { + "from": 261.066, + "to": 264.766, + "location": 0, + "content": "是把他更多的做的是大规模是吧是吧" + }, + { + "from": 264.766, + "to": 267.499, + "location": 0, + "content": "越来越多的人纳入到了这个体系中" + }, + { + "from": 267.5, + "to": 269.566, + "location": 0, + "content": "所产生的这么一个规模效应" + }, + { + "from": 269.933, + "to": 272.399, + "location": 0, + "content": "就当年操作系统能完成能做的事情呢" + } + ] +} diff --git a/src/data/keyPoints.json b/src/data/keyPoints.json new file mode 100644 index 0000000..58ce550 --- /dev/null +++ b/src/data/keyPoints.json @@ -0,0 +1,22 @@ +[ + { + "time": "00:10", + "emoji": "👍", + "key": "人们喜欢短。" + }, + { + "time": "01:00", + "emoji": "👍", + "key": "晶体智力和流体智力" + }, + { + "time": "03:00", + "emoji": "👍", + "key": "外向成长是围绕外界展开的成长活动,以输出为输入可以带来正向反馈。" + }, + { + "time": "05:00", + "emoji": "👍", + "key": "制定学习计划时,要专注打造自己的外向晶体和木子,即找到清晰的输出点,搜刮对应的项目和参考,借鉴晶体。" + } +] diff --git a/src/hooks/redux.ts b/src/hooks/redux.ts new file mode 100644 index 0000000..3feb16e --- /dev/null +++ b/src/hooks/redux.ts @@ -0,0 +1,6 @@ +import {TypedUseSelectorHook, useDispatch, useSelector} from 'react-redux' +import type {AppDispatch, RootState} from '../store' + +// Use throughout your app instead of plain `useDispatch` and `useSelector` +export const useAppDispatch: () => AppDispatch = useDispatch +export const useAppSelector: TypedUseSelectorHook = useSelector diff --git a/src/hooks/useSubtitle.ts b/src/hooks/useSubtitle.ts new file mode 100644 index 0000000..a63eedf --- /dev/null +++ b/src/hooks/useSubtitle.ts @@ -0,0 +1,20 @@ +import {useAppDispatch} from './redux' +import React, {useCallback} from 'react' +import {setNeedScroll} from '../redux/envReducer' + +const useSubtitle = () => { + const dispatch = useAppDispatch() + + const move = useCallback((time: number) => { + window.parent.postMessage({type: 'move', time}, '*') + }, []) + + const scrollIntoView = useCallback((ref: React.RefObject) => { + ref.current?.scrollIntoView({behavior: 'smooth', block: 'center'}) + dispatch(setNeedScroll(false)) + }, [dispatch]) + + return {move, scrollIntoView} +} + +export default useSubtitle diff --git a/src/hooks/useSubtitleService.ts b/src/hooks/useSubtitleService.ts new file mode 100644 index 0000000..259f589 --- /dev/null +++ b/src/hooks/useSubtitleService.ts @@ -0,0 +1,219 @@ +import {useAppDispatch, useAppSelector} from './redux' +import {useContext, useEffect} from 'react' +import { + setCurFetched, + setCurIdx, + setCurInfo, + setCurrentTime, + setData, + setInfos, + setNoVideo, + setSegmentFold, + setSegments, + setTitle, + setTotalHeight, +} from '../redux/envReducer' +import {EventBusContext} from '../Router' +import {EVENT_EXPAND, TOTAL_HEIGHT_MAX, TOTAL_HEIGHT_MIN, WORDS_DEFAULT, WORDS_MAX, WORDS_MIN} from '../const' +import {useInterval} from 'ahooks' +import {getWholeText} from '../util/biz_util' + +/** + * Service是单例,类似后端的服务概念 + */ +const useSubtitleService = () => { + const dispatch = useAppDispatch() + const infos = useAppSelector(state => state.env.infos) + const curInfo = useAppSelector(state => state.env.curInfo) + const curFetched = useAppSelector(state => state.env.curFetched) + const fold = useAppSelector(state => state.env.fold) + const envReady = useAppSelector(state => state.env.envReady) + const envData = useAppSelector(state => state.env.envData) + const data = useAppSelector(state => state.env.data) + const currentTime = useAppSelector(state => state.env.currentTime) + const curIdx = useAppSelector(state => state.env.curIdx) + const eventBus = useContext(EventBusContext) + const needScroll = useAppSelector(state => state.env.needScroll) + const segments = useAppSelector(state => state.env.segments) + const transResults = useAppSelector(state => state.env.transResults) + const hideOnDisableAutoTranslate = useAppSelector(state => state.env.envData.hideOnDisableAutoTranslate) + const autoTranslate = useAppSelector(state => state.env.autoTranslate) + + // 设置屏安具 + + // 监听消息 + useEffect(() => { + const listener = (event: MessageEvent) => { + const data = event.data + + if (data.type === 'setVideoInfo') { + dispatch(setInfos(data.infos)) + dispatch(setTitle(data.title)) + console.debug('video title: ', data.title) + } + + if (data.type === 'setInfos') { + dispatch(setInfos(data.infos)) + dispatch(setCurInfo(undefined)) + dispatch(setCurFetched(false)) + dispatch(setData(undefined)) + // console.log('setInfos', data.infos) + } + + if (data.type === 'setSubtitle') { + const data_ = data.data.data + data_?.body?.forEach((item: TranscriptItem, idx: number) => { + item.idx = idx + }) + // dispatch(setCurInfo(data.data.info)) + dispatch(setCurFetched(true)) + dispatch(setData(data_)) + // console.log('setSubtitle', data.data) + } + + if (data.type === 'setCurrentTime') { + dispatch(setCurrentTime(data.data.currentTime)) + } + if (data.type === 'setSettings') { + dispatch(setNoVideo(data.data.noVideo)) + if (data.data.totalHeight) { + dispatch(setTotalHeight(Math.min(Math.max(data.data.totalHeight, TOTAL_HEIGHT_MIN), TOTAL_HEIGHT_MAX))) + } + } + } + + window.addEventListener('message', listener) + + return () => { + window.removeEventListener('message', listener) + } + }, [dispatch, eventBus]) + + // 有数据时自动展开 + useEffect(() => { + if ((data != null) && data.body.length > 0) { + eventBus.emit({ + type: EVENT_EXPAND + }) + } + }, [data, eventBus]) + + // 当前未展示 & (未折叠 | 自动展开) & 有列表 => 展示第一个 + useEffect(() => { + if (!curInfo && (!fold || (envReady && envData.autoExpand)) && (infos != null) && infos.length > 0) { + dispatch(setCurInfo(infos[0])) + dispatch(setCurFetched(false)) + } + }, [curInfo, dispatch, envData.autoExpand, envReady, fold, infos]) + // 获取 + useEffect(() => { + if (curInfo && !curFetched) { + window.parent.postMessage({type: 'getSubtitle', info: curInfo}, '*') + } + }, [curFetched, curInfo]) + + useEffect(() => { + // 初始获取列表 + window.parent.postMessage({type: 'refreshVideoInfo'}, '*') + // 初始获取设置信息 + window.parent.postMessage({type: 'getSettings'}, '*') + }, []) + + // 更新当前位置 + useEffect(() => { + let curIdx + if (((data?.body) != null) && currentTime) { + for (let i=0; i segment自动展开 + useEffect(() => { + if (needScroll && curIdx != null) { // 需要滚动 + for (const segment of segments??[]) { // 检测segments + if (segment.startIdx <= curIdx && curIdx <= segment.endIdx) { // 找到对应的segment + if (segment.fold) { // 需要展开 + dispatch(setSegmentFold({ + segmentStartIdx: segment.startIdx, + fold: false + })) + } + break + } + } + } + }, [curIdx, dispatch, needScroll, segments]) + + // data等变化时自动刷新segments + useEffect(() => { + let segments: Segment[] | undefined + const items = data?.body + if (items != null) { + if (envData.summarizeEnable) { // 分段 + let size = envData.words??WORDS_DEFAULT + size = Math.min(Math.max(size, WORDS_MIN), WORDS_MAX) + + segments = [] + let transcriptItems: TranscriptItem[] = [] + let totalLength = 0 + for (let i = 0; i < items.length; i++) { + const item = items[i] + transcriptItems.push(item) + totalLength += item.content.length + if (totalLength >= size || i === items.length-1) { // new segment or last + // add + segments.push({ + items: transcriptItems, + startIdx: transcriptItems[0].idx, + endIdx: transcriptItems[transcriptItems.length - 1].idx, + text: getWholeText(transcriptItems.map(item => item.content)), + summaries: {}, + }) + // reset + transcriptItems = [] + totalLength = 0 + } + } + } else { // 都放一个分段 + segments = [{ + items, + startIdx: 0, + endIdx: items.length-1, + text: getWholeText(items.map(item => item.content)), + summaries: {}, + }] + } + } + dispatch(setSegments(segments)) + }, [data?.body, dispatch, envData.summarizeEnable, envData.words]) + + // 每秒更新当前视频时间 + useInterval(() => { + window.parent.postMessage({type: 'getCurrentTime'}, '*') + }, 500) + + // show translated text in the video + useEffect(() => { + if (hideOnDisableAutoTranslate && !autoTranslate) { + window.parent.postMessage({type: 'updateTransResult'}, '*') + return + } + + const transResult = curIdx?transResults[curIdx]:undefined + if (transResult?.code === '200' && transResult.data) { + window.parent.postMessage({type: 'updateTransResult', result: transResult.data}, '*') + } else { + window.parent.postMessage({type: 'updateTransResult'}, '*') + } + }, [autoTranslate, curIdx, hideOnDisableAutoTranslate, transResults]) +} + +export default useSubtitleService diff --git a/src/hooks/useTranslate.ts b/src/hooks/useTranslate.ts new file mode 100644 index 0000000..31b306d --- /dev/null +++ b/src/hooks/useTranslate.ts @@ -0,0 +1,310 @@ +import {useAppDispatch, useAppSelector} from './redux' +import {useCallback} from 'react' +import { + addTaskId, + addTransResults, + delTaskId, + setLastSummarizeTime, + setLastTransTime, + setSummaryContent, + setSummaryError, + setSummaryStatus +} from '../redux/envReducer' +import { + LANGUAGE_DEFAULT, + LANGUAGES_MAP, + SUMMARIZE_LANGUAGE_DEFAULT, + SUMMARIZE_THRESHOLD, + TRANSLATE_COOLDOWN, + TRANSLATE_FETCH_DEFAULT, +} from '../const' +import toast from 'react-hot-toast' +import {useMemoizedFn} from 'ahooks/es' +import {extractJsonArray, extractJsonObject} from '../util/biz_util' +import {formatTime} from '../util/util' + +const useTranslate = () => { + const dispatch = useAppDispatch() + const data = useAppSelector(state => state.env.data) + const curIdx = useAppSelector(state => state.env.curIdx) + const lastTransTime = useAppSelector(state => state.env.lastTransTime) + const transResults = useAppSelector(state => state.env.transResults) + const envData = useAppSelector(state => state.env.envData) + const language = LANGUAGES_MAP[envData.language??LANGUAGE_DEFAULT] + const summarizeLanguage = LANGUAGES_MAP[envData.summarizeLanguage??SUMMARIZE_LANGUAGE_DEFAULT] + + /** + * 获取下一个需要翻译的行 + * 会检测冷却 + */ + const getFetch = useCallback(() => { + if (data?.body != null && data.body.length > 0) { + const curIdx_ = curIdx ?? 0 + + // check lastTransTime + if (lastTransTime && Date.now() - lastTransTime < TRANSLATE_COOLDOWN) { + return + } + + let nextIdleIdx + for (let i = curIdx_; i < data.body.length; i++) { + if (transResults[i] == null) { + nextIdleIdx = i + break + } + } + if (nextIdleIdx != null && nextIdleIdx - curIdx_ <= Math.ceil((envData.fetchAmount??TRANSLATE_FETCH_DEFAULT)/2)) { + return nextIdleIdx + } + } + }, [curIdx, data?.body, envData.fetchAmount, lastTransTime, transResults]) + + const addTask = useCallback(async (startIdx: number) => { + if ((data?.body) != null) { + const lines: string[] = data.body.slice(startIdx, startIdx + (envData.fetchAmount??TRANSLATE_FETCH_DEFAULT)).map((item: any) => item.content) + if (lines.length > 0) { + const linesMap: {[key: string]: string} = {} + lines.forEach((line, idx) => { + linesMap[(idx + 1)+''] = line + }) + let lineStr = JSON.stringify(linesMap).replaceAll('\n', '') + lineStr = '```' + lineStr + '```' + const taskDef: TaskDef = { + type: 'chatComplete', + serverUrl: envData.serverUrl, + data: { + model: 'gpt-3.5-turbo', + messages: [ + { + role: 'system', + content: 'You are a professional translator.' + }, + { + role: 'user', + content: `Translate following video subtitles to language '${language.name}'. +Preserve incomplete sentence. +Translate in the same json format. +Answer in markdown json format. + +video subtitles: + +\`\`\` +${lineStr} +\`\`\`` + } + ], + temperature: 0, + n: 1, + stream: false, + }, + extra: { + type: 'translate', + apiKey: envData.apiKey, + startIdx, + size: lines.length, + } + } + console.debug('addTask', taskDef) + dispatch(setLastTransTime(Date.now())) + // addTransResults + const result: { [key: number]: TransResult } = {} + lines.forEach((line, idx) => { + result[startIdx + idx] = { + // idx: startIdx + idx, + } + }) + dispatch(addTransResults(result)) + const task = await chrome.runtime.sendMessage({type: 'addTask', taskDef}) + dispatch(addTaskId(task.id)) + } + } + }, [data?.body, dispatch, envData.apiKey, envData.fetchAmount, envData.serverUrl, language.name]) + + const addSummarizeTask = useCallback(async (title: string | undefined, type: SummaryType, segment: Segment) => { + if (segment.text.length >= SUMMARIZE_THRESHOLD && envData.apiKey) { + const title_ = title?`The video's title is '${title}'.`:'' + let subtitles = '' + for (const item of segment.items) { + subtitles += formatTime(item.from) + ' ' + item.content + '\n' + } + let content + if (type === 'overview') { + content = `You are a helpful assistant that summarize key points of video subtitle. +Summarize 3 to 8 brief key points in language '${summarizeLanguage.name}'. +Answer in markdown json format. +The emoji should be related to the key point and 1 char length. + +example output format: + +\`\`\`json +[ + { + "time": "03:00", + "emoji": "👍", + "key": "key point 1" + }, + { + "time": "10:05", + "emoji": "😊", + "key": "key point 2" + } +] +\`\`\` + +The video's title: '''${title_}'''. +The video's subtitles: + +''' +${subtitles} +'''` + } else if (type === 'keypoint') { + content = `You are a helpful assistant that summarize key points of video subtitle. +Summarize brief key points in language '${summarizeLanguage.name}'. +Answer in markdown json format. + +example output format: + +\`\`\`json +[ + "key point 1", + "key point 2" +] +\`\`\` + +The video's title: '''${title_}'''. +The video's subtitles: + +''' +${segment.text} +'''` + } else if (type === 'brief') { + content = `You are a helpful assistant that summarize video subtitle. +Summarize in language '${summarizeLanguage.name}'. +Answer in markdown json format. + +example output format: + +\`\`\`json +{ + "summary": "brief summary" +} +\`\`\` + +The video's title: '''${title_}'''. +The video's subtitles: + +''' +${segment.text} +'''` + } + const taskDef: TaskDef = { + type: 'chatComplete', + serverUrl: envData.serverUrl, + data: { + model: 'gpt-3.5-turbo', + messages: [ + { + role: 'user', + content, + } + ], + temperature: 0, + n: 1, + stream: false, + }, + extra: { + type: 'summarize', + summaryType: type, + startIdx: segment.startIdx, + apiKey: envData.apiKey, + } + } + console.debug('addSummarizeTask', taskDef) + dispatch(setSummaryStatus({segmentStartIdx: segment.startIdx, type, status: 'pending'})) + dispatch(setLastSummarizeTime(Date.now())) + const task = await chrome.runtime.sendMessage({type: 'addTask', taskDef}) + dispatch(addTaskId(task.id)) + } + }, [dispatch, envData.apiKey, envData.serverUrl, summarizeLanguage.name]) + + const handleTranslate = useMemoizedFn((task: Task, content: string) => { + let map: {[key: string]: string} = {} + try { + content = extractJsonObject(content) + map = JSON.parse(content) + } catch (e) { + console.debug(e) + } + const {startIdx, size} = task.def.extra + if (startIdx != null) { + const result: { [key: number]: TransResult } = {} + for (let i = 0; i < size; i++) { + const item = map[(i + 1)+''] + if (item) { + result[startIdx + i] = { + // idx: startIdx + i, + code: '200', + data: item, + } + } else { + result[startIdx + i] = { + // idx: startIdx + i, + code: '500', + } + } + } + dispatch(addTransResults(result)) + console.debug('addTransResults', map, size) + } + }) + + const handleSummarize = useMemoizedFn((task: Task, content?: string) => { + const summaryType = task.def.extra.summaryType + content = summaryType === 'brief'?extractJsonObject(content??''):extractJsonArray(content??'') + let obj + try { + obj = JSON.parse(content) + } catch (e) { + task.error = 'failed' + } + + dispatch(setSummaryContent({ + segmentStartIdx: task.def.extra.startIdx, + type: summaryType, + content: obj, + })) + dispatch(setSummaryStatus({segmentStartIdx: task.def.extra.startIdx, type: summaryType, status: 'done'})) + dispatch(setSummaryError({segmentStartIdx: task.def.extra.startIdx, type: summaryType, error: task.error})) + console.debug('setSummary', task.def.extra.startIdx, summaryType, obj, task.error) + }) + + const getTask = useCallback(async (taskId: string) => { + const taskResp = await chrome.runtime.sendMessage({type: 'getTask', taskId}) + if (taskResp.code === 'ok') { + console.debug('getTask', taskResp.task) + const task: Task = taskResp.task + const taskType: string | undefined = task.def.extra?.type + const content = task.resp?.choices?.[0]?.message?.content?.trim() + if (task.status === 'done') { + // 异常提示 + if (task.error) { + toast.error(task.error) + } + // 删除任务 + dispatch(delTaskId(taskId)) + // 处理结果 + if (taskType === 'translate') { // 翻译 + handleTranslate(task, content) + } else if (taskType === 'summarize') { // 总结 + handleSummarize(task, content) + } + } + } else { + dispatch(delTaskId(taskId)) + } + }, [dispatch, handleSummarize, handleTranslate]) + + return {getFetch, getTask, addTask, addSummarizeTask} +} + +export default useTranslate diff --git a/src/hooks/useTranslateService.ts b/src/hooks/useTranslateService.ts new file mode 100644 index 0000000..090e65a --- /dev/null +++ b/src/hooks/useTranslateService.ts @@ -0,0 +1,55 @@ +import {useAppDispatch, useAppSelector} from './redux' +import {useEffect} from 'react' +import {clearTransResults} from '../redux/envReducer' +import {useInterval, useMemoizedFn} from 'ahooks' +import useTranslate from './useTranslate' + +/** + * Service是单例,类似后端的服务概念 + */ +const useTranslateService = () => { + const dispatch = useAppDispatch() + const autoTranslate = useAppSelector(state => state.env.autoTranslate) + const data = useAppSelector(state => state.env.data) + const taskIds = useAppSelector(state => state.env.taskIds) + const curIdx = useAppSelector(state => state.env.curIdx) + const {getFetch, addTask, getTask} = useTranslate() + + // data变化时清空翻译结果 + useEffect(() => { + dispatch(clearTransResults()) + console.debug('清空翻译结果') + }, [data, dispatch]) + + // autoTranslate开启时立即查询 + const addTaskNow = useMemoizedFn(() => { + addTask(curIdx??0).catch(console.error) + }) + useEffect(() => { + if (autoTranslate) { + addTaskNow() + console.debug('立即查询翻译') + } + }, [autoTranslate, addTaskNow]) + + // 每3秒检测翻译 + useInterval(async () => { + if (autoTranslate) { + const fetchStartIdx = getFetch() + if (fetchStartIdx != null) { + await addTask(fetchStartIdx) + } + } + }, 3000) + + // 每0.5秒检测获取结果 + useInterval(async () => { + if (taskIds != null) { + for (const taskId of taskIds) { + await getTask(taskId) + } + } + }, 500) +} + +export default useTranslateService diff --git a/src/index.less b/src/index.less new file mode 100644 index 0000000..cd10dba --- /dev/null +++ b/src/index.less @@ -0,0 +1,28 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + font-size: 16px; +} +body { + font-size: 100%; +} + +#bilibili-subtitle { + font-family: PingFang SC, HarmonyOS_Regular, Helvetica Neue, Microsoft YaHei, sans-serif; + font-size: 16px; + text-align: left; +} + +.desc { + @apply text-base-content/80; +} + +.desc-lighter { + @apply text-base-content/60; +} + +.flex-center { + @apply flex items-center; +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..01ea0e9 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,22 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import './index.less' +import store from './store' +import {Provider} from 'react-redux' +import Router from './Router' +import {APP_DOM_ID} from './const' + +const body = document.querySelector('body') +const app = document.createElement('div') +app.id = APP_DOM_ID +if (body != null) { + body.prepend(app) +} + +ReactDOM.createRoot(document.getElementById(APP_DOM_ID) as HTMLElement).render( + + + + + +) diff --git a/src/redux/envReducer.ts b/src/redux/envReducer.ts new file mode 100644 index 0000000..dbe133c --- /dev/null +++ b/src/redux/envReducer.ts @@ -0,0 +1,246 @@ +import {createSlice, PayloadAction} from '@reduxjs/toolkit' +import {find} from 'lodash-es' +import {getDevData} from '../util/biz_util' +import {SERVER_URL_OPENAI, TOTAL_HEIGHT_DEF} from '../const' + +interface EnvState { + envData: EnvData + envReady: boolean + + fold: boolean // fold app + foldAll?: boolean // fold all segments + page?: string + autoTranslate?: boolean + autoScroll?: boolean + checkAutoScroll?: boolean + curOffsetTop?: number + compact?: boolean // 是否紧凑视图 + floatKeyPointsSegIdx?: number // segment的startIdx + + noVideo?: boolean + totalHeight: number + curIdx?: number // 从0开始 + needScroll?: boolean + currentTime?: number + downloadType?: string + infos?: any[] + curInfo?: any + curFetched?: boolean + data?: Transcript + uploadedTranscript?: Transcript + segments?: Segment[] + title?: string + curSummaryType: SummaryType + + taskIds?: string[] + transResults: {[key: number]: TransResult} + lastTransTime?: number + lastSummarizeTime?: number +} + +const initialState: EnvState = { + envData: { + serverUrl: SERVER_URL_OPENAI, + translateEnable: true, + summarizeEnable: true, + theme: 'light', + }, + totalHeight: TOTAL_HEIGHT_DEF, + autoScroll: true, + currentTime: import.meta.env.VITE_ENV === 'web-dev'? 30: undefined, + envReady: false, + fold: true, + data: import.meta.env.VITE_ENV === 'web-dev'? getDevData(): undefined, + transResults: {}, + curSummaryType: 'overview', +} + +export const slice = createSlice({ + name: 'env', + initialState, + reducers: { + setEnvData: (state, action: PayloadAction) => { + state.envData = { + ...state.envData, + ...action.payload, + } + }, + setEnvReady: (state) => { + state.envReady = true + }, + setFloatKeyPointsSegIdx: (state, action: PayloadAction) => { + state.floatKeyPointsSegIdx = action.payload + }, + setFoldAll: (state, action: PayloadAction) => { + state.foldAll = action.payload + }, + setCurSummaryType: (state, action: PayloadAction) => { + state.curSummaryType = action.payload + }, + setCompact: (state, action: PayloadAction) => { + state.compact = action.payload + }, + setPage: (state, action: PayloadAction) => { + state.page = action.payload + }, + setTotalHeight: (state, action: PayloadAction) => { + state.totalHeight = action.payload + }, + setTaskIds: (state, action: PayloadAction) => { + state.taskIds = action.payload + }, + setLastTransTime: (state, action: PayloadAction) => { + state.lastTransTime = action.payload + }, + setLastSummarizeTime: (state, action: PayloadAction) => { + state.lastSummarizeTime = action.payload + }, + addTaskId: (state, action: PayloadAction) => { + state.taskIds = [...(state.taskIds??[]), action.payload] + }, + delTaskId: (state, action: PayloadAction) => { + state.taskIds = state.taskIds?.filter(id => id !== action.payload) + }, + addTransResults: (state, action: PayloadAction<{[key: number]: TransResult}>) => { + // 不要覆盖TransResult里code为200的 + for (const payloadKey in action.payload) { + const payloadItem = action.payload[payloadKey] + const stateItem = state.transResults[payloadKey] + if (!stateItem || stateItem.code !== '200') { + state.transResults[payloadKey] = payloadItem + } else if (stateItem.code === '200') { // 保留data + state.transResults[payloadKey] = { + ...payloadItem, + data: stateItem.data, + } + } + } + }, + setSummaryContent: (state, action: PayloadAction<{ + segmentStartIdx: number + type: SummaryType + content?: any + }>) => { + const segment = find(state.segments, {startIdx: action.payload.segmentStartIdx}) + if (segment != null) { + let summary = segment.summaries[action.payload.type] + if (!summary) { + summary = { + type: action.payload.type, + status: 'done', + content: action.payload.content, + } + segment.summaries[action.payload.type] = summary + } else { + summary.content = action.payload.content + } + } + }, + setSummaryStatus: (state, action: PayloadAction<{ + segmentStartIdx: number + type: SummaryType + status: SummaryStatus + }>) => { + const segment = find(state.segments, {startIdx: action.payload.segmentStartIdx}) + if (segment != null) { + let summary = segment.summaries[action.payload.type] + if (summary) { + summary.status = action.payload.status + } else { + summary = { + type: action.payload.type, + status: action.payload.status, + } + segment.summaries[action.payload.type] = summary + } + } + }, + setSummaryError: (state, action: PayloadAction<{ + segmentStartIdx: number + type: SummaryType + error?: string + }>) => { + const segment = find(state.segments, {startIdx: action.payload.segmentStartIdx}) + if (segment != null) { + let summary = segment.summaries[action.payload.type] + if (summary) { + summary.error = action.payload.error + } else { + summary = { + type: action.payload.type, + status: 'done', + error: action.payload.error, + } + segment.summaries[action.payload.type] = summary + } + } + }, + setSegmentFold: (state, action: PayloadAction<{ + segmentStartIdx: number + fold: boolean + }>) => { + const segment = find(state.segments, {startIdx: action.payload.segmentStartIdx}) + if (segment != null) { + segment.fold = action.payload.fold + } + }, + clearTransResults: (state) => { + state.transResults = {} + }, + setCurIdx: (state, action: PayloadAction) => { + state.curIdx = action.payload + }, + setAutoTranslate: (state, action: PayloadAction) => { + state.autoTranslate = action.payload + }, + setAutoScroll: (state, action: PayloadAction) => { + state.autoScroll = action.payload + }, + setCheckAutoScroll: (state, action: PayloadAction) => { + state.checkAutoScroll = action.payload + }, + setCurOffsetTop: (state, action: PayloadAction) => { + state.curOffsetTop = action.payload + }, + setNoVideo: (state, action: PayloadAction) => { + state.noVideo = action.payload + }, + setDownloadType: (state, action: PayloadAction) => { + state.downloadType = action.payload + }, + setNeedScroll: (state, action: PayloadAction) => { + state.needScroll = action.payload + }, + setCurrentTime: (state, action: PayloadAction) => { + state.currentTime = action.payload + }, + setTitle: (state, action: PayloadAction) => { + state.title = action.payload + }, + setInfos: (state, action: PayloadAction) => { + state.infos = action.payload + }, + setCurInfo: (state, action: PayloadAction) => { + state.curInfo = action.payload + }, + setCurFetched: (state, action: PayloadAction) => { + state.curFetched = action.payload + }, + setData: (state, action: PayloadAction) => { + state.data = action.payload + }, + setUploadedTranscript: (state, action: PayloadAction) => { + state.uploadedTranscript = action.payload + }, + setSegments: (state, action: PayloadAction) => { + state.segments = action.payload + }, + setFold: (state, action: PayloadAction) => { + state.fold = action.payload + }, + }, +}) + +export const { setCurSummaryType, setUploadedTranscript, setTotalHeight, setCheckAutoScroll, setCurOffsetTop, setFloatKeyPointsSegIdx, setFoldAll, setCompact, setSegmentFold, setSummaryContent, setSummaryStatus, setSummaryError, setTitle, setSegments, setLastSummarizeTime, setPage, setLastTransTime, clearTransResults, addTransResults, addTaskId, delTaskId, setTaskIds, setDownloadType, setAutoTranslate, setAutoScroll, setNoVideo, setNeedScroll, setCurIdx, setEnvData, setEnvReady, setCurrentTime, setInfos, setCurInfo, setCurFetched, setData, setFold } = slice.actions + +export default slice.reducer diff --git a/src/store.ts b/src/store.ts new file mode 100644 index 0000000..dcc8c9d --- /dev/null +++ b/src/store.ts @@ -0,0 +1,14 @@ +import {configureStore} from '@reduxjs/toolkit' +import envReducer from './redux/envReducer' + +const store = configureStore({ + reducer: { + env: envReducer, + }, +}) + +export default store +// Infer the `RootState` and `AppDispatch` types from the store itself +export type RootState = ReturnType +// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState} +export type AppDispatch = typeof store.dispatch diff --git a/src/typings.d.ts b/src/typings.d.ts new file mode 100644 index 0000000..9a40d7e --- /dev/null +++ b/src/typings.d.ts @@ -0,0 +1,106 @@ +interface EnvData { + autoExpand?: boolean + flagDot?: boolean + apiKey?: string + serverUrl?: string + translateEnable?: boolean + language?: string + hideOnDisableAutoTranslate?: boolean + transDisplay?: 'target' | 'originPrimary' | 'targetPrimary' + fetchAmount?: number + summarizeEnable?: boolean + summarizeLanguage?: string + words?: number + summarizeFloat?: boolean + theme?: 'system' | 'light' | 'dark' + fontSize?: 'normal' | 'large' +} + +interface TaskDef { + type: 'chatComplete' + serverUrl?: string + data: any + extra?: any +} + +interface Task { + id: string + startTime: number + endTime?: number + def: TaskDef + + status: 'pending' | 'running' | 'done' + error?: string + resp?: any +} + +interface TransResult { + // idx: number + code?: '200' | '500' + data?: string +} + +type ShowElement = string | JSX.Element | undefined + +interface Transcript { + body: TranscriptItem[] +} + +interface TranscriptItem { + from: number + to: number + content: string + + idx: number +} + +interface Segment { + items: TranscriptItem[] + startIdx: number // 从1开始 + endIdx: number + text: string + fold?: boolean + summaries: { + [type: string]: Summary + } +} + +interface OverviewItem { + time: string + emoji: string + key: string +} + +interface Summary { + type: SummaryType + + status: SummaryStatus + error?: string + content?: any +} + +/** + * 概览 + */ +interface OverviewSummary extends Summary { + content?: OverviewItem[] +} + +/** + * 要点 + */ +interface KeypointSummary extends Summary { + content?: string[] +} + +/** + * 总结 + */ +interface BriefSummary extends Summary { + content?: { + summary: string + } +} + +type SummaryStatus = 'init' | 'pending' | 'done' +type SummaryType = 'overview' | 'keypoint' | 'brief' diff --git a/src/util/biz_util.ts b/src/util/biz_util.ts new file mode 100644 index 0000000..4a7f9ed --- /dev/null +++ b/src/util/biz_util.ts @@ -0,0 +1,277 @@ +import devData from '../data/data.json' +import {APP_DOM_ID} from '../const' +import {isDarkMode} from '@kky002/kky-util' +import toast from 'react-hot-toast' +import {findIndex} from 'lodash-es' + +/** + * 获取译文 + */ +export const getTransText = (transResult: TransResult, hideOnDisableAutoTranslate: boolean | undefined, autoTranslate: boolean | undefined) => { + if (transResult && (!transResult.code || transResult.code === '200') && (autoTranslate === true || !hideOnDisableAutoTranslate) && transResult.data) { + return transResult.data + } +} + +export const getDisplay = (transDisplay_: EnvData['transDisplay'], content: string, transText: string | undefined) => { + const transDisplay = transDisplay_ ?? 'originPrimary' + let main, sub + // main + if (transText && (transDisplay === 'targetPrimary' || transDisplay === 'target')) { + main = transText + } else { + main = content + } + // sub + switch (transDisplay) { + case 'originPrimary': + sub = transText + break + case 'targetPrimary': + if (transText) { + sub = content + } + break + default: + break + } + // return + return { + main, + sub, + } +} + +export const getWholeText = (items: string[]) => { + return items.join(',').replaceAll('\n', ' ') +} + +export const getLastTime = (seconds: number) => { + if (seconds > 60 * 60) { + return `${Math.floor(seconds / 60 / 60)}小时` + } + if (seconds > 60) { + return `${Math.floor(seconds / 60)}分钟` + } + return `${Math.floor(seconds)}秒` +} + +/** + * 00:00:00 + */ +export const getTimeDisplay = (seconds: number) => { + const h = Math.floor(seconds / 60 / 60) + const m = Math.floor(seconds / 60 % 60) + const s = Math.floor(seconds % 60) + return `${h < 10 ? '0' : ''}${h}:${m < 10 ? '0' : ''}${m}:${s < 10 ? '0' : ''}${s}` +} + +export const getDevData = () => { + // add idx + const body = devData.body.map((item, idx) => ({ + ...item, + idx, + })) + return { + ...devData, + body, + } +} + +export const isSummaryEmpty = (summary: Summary) => { + if (summary.type === 'overview') { + const content: OverviewItem[] = summary.content??[] + return content.length === 0 + } else if (summary.type === 'keypoint') { + const content: string[] = summary.content??[] + return content.length === 0 + } else if (summary.type === 'brief') { + const content: string[] = summary.content??'' + return content.length === 0 + } + return true +} + +export const getSummaryStr = (summary: Summary) => { + let s = '' + if (summary.type === 'overview') { + const content: OverviewItem[] = summary.content ?? [] + for (const overviewItem of content) { + s += (overviewItem.emoji ?? '') + overviewItem.time + ' ' + overviewItem.key + '\n' + } + } else if (summary.type === 'keypoint') { + const content: string[] = summary.content ?? [] + for (const keypoint of content) { + s += '- ' + keypoint + '\n' + } + } else if (summary.type === 'brief') { + const content: { summary: string } = summary.content ?? { + summary: '' + } + s += content.summary + } + return s +} + +export const getServerUrl = (serverUrl?: string) => { + if (!serverUrl) { + return 'https://api.openai.com' + } + if (serverUrl.endsWith('/')) { + serverUrl = serverUrl.slice(0, -1) + } + return serverUrl +} + +export const setTheme = (theme: EnvData['theme']) => { + const appRoot = document.getElementById(APP_DOM_ID) + if (appRoot != null) { + // system + theme = theme ?? 'system' + if (!theme || theme === 'system') { + theme = isDarkMode() ? 'dark' : 'light' + } + + appRoot.setAttribute('data-theme', theme) + if (theme === 'dark') { + appRoot.classList.add('dark') + appRoot.classList.remove('light') + } else { + appRoot.classList.add('light') + appRoot.classList.remove('dark') + } + } +} + +export const getSummarize = (title: string | undefined, segments: Segment[] | undefined, type: SummaryType): [boolean, string] => { + if (segments == null) { + return [false, ''] + } + + let content = `${title ?? ''}\n\n` + let success = false + for (const segment of segments) { + if (segment.items.length > 0) { + content += `${getTimeDisplay(segment.items[0].from)}\n` + } + const summary = segment.summaries[type] + if (summary && !isSummaryEmpty(summary)) { + success = true + content += getSummaryStr(summary) + } else { + content += '无总结\n' + } + + content += '\n' + } + + if (!success) { + toast.error('未找到总结') + } + + return [success, content] +} + +/** + * @param time '03:10' + */ +export const parseStrTimeToSeconds = (time: string): number => { + const parts = time.split(':') + return parseInt(parts[0]) * 60 + parseInt(parts[1]) +} + +/** + * @param time '00:04:11,599' or '00:04:11.599' or '04:11,599' or '04:11.599' + * @return seconds, 4.599 + */ +export const parseTime = (time: string): number => { + const separator = time.includes(',') ? ',' : '.' + const parts = time.split(':') + const ms = parts[parts.length-1].split(separator) + if (parts.length === 3) { + return parseInt(parts[0]) * 60 * 60 + parseInt(parts[1]) * 60 + parseInt(ms[0]) + parseInt(ms[1]) / 1000 + } else { + return parseInt(parts[0]) * 60 + parseInt(ms[0]) + parseInt(ms[1]) / 1000 + } +} + +export const parseTranscript = (filename: string, text: string | ArrayBuffer): Transcript => { + const items: TranscriptItem[] = [] + // convert /r/n to /n + text = (text as string).trim().replace(/\r\n/g, '\n') + // .srt: + if (filename.toLowerCase().endsWith('.srt')) { + const lines = text.split('\n\n') + for (const line of lines) { + const lines = line.split('\n') + if (lines.length >= 3) { + const time = lines[1].split(' --> ') + const from = parseTime(time[0]) + const to = parseTime(time[1]) + const content = lines.slice(2).join('\n') + items.push({ + from, + to, + content, + idx: items.length, + }) + } + } + } + // .vtt: + if (filename.toLowerCase().endsWith('.vtt')) { + const lines = text.split('\n\n') + for (const line of lines) { + const lines = line.split('\n') + const timeIdx = findIndex(lines, (line) => line.includes('-->')) + if (timeIdx >= 0) { + const time = lines[timeIdx].split(' --> ') + const from = parseTime(time[0]) + const to = parseTime(time[1]) + const content = lines.slice(timeIdx + 1).join('\n') + items.push({ + from, + to, + content, + idx: items.length, + }) + } + } + } + // return + return { + body: items, + } +} + +export const extractJsonObject = (content: string) => { + // get content between ``` and ``` + const start = content.indexOf('```') + const end = content.lastIndexOf('```') + if (start >= 0 && end >= 0) { + content = content.slice(start + 3, end) + } + // get content between { and } + const start2 = content.indexOf('{') + const end2 = content.lastIndexOf('}') + if (start2 >= 0 && end2 >= 0) { + content = content.slice(start2, end2 + 1) + } + return content +} + +export const extractJsonArray = (content: string) => { + // get content between ``` and ``` + const start = content.indexOf('```') + const end = content.lastIndexOf('```') + if (start >= 0 && end >= 0) { + content = content.slice(start + 3, end) + } + // get content between [ and ] + const start3 = content.indexOf('[') + const end3 = content.lastIndexOf(']') + if (start3 >= 0 && end3 >= 0) { + content = content.slice(start3, end3 + 1) + } + return content +} diff --git a/src/util/util.ts b/src/util/util.ts new file mode 100644 index 0000000..cec8842 --- /dev/null +++ b/src/util/util.ts @@ -0,0 +1,43 @@ +import {SyntheticEvent} from 'react' + +export const formatTime = (time: number) => { + if (!time) return '00:00' + + const minutes = Math.floor(time / 60) + const seconds = Math.floor(time % 60) + return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}` +} + +/** + * @param time 2.82 + */ +export const formatSrtTime = (time: number) => { + if (!time) return '00:00:00,000' + + const hours = Math.floor(time / 60 / 60) + const minutes = Math.floor(time / 60 % 60) + const seconds = Math.floor(time % 60) + const ms = Math.floor((time % 1) * 1000) + return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')},${ms.toString().padStart(3, '0')}` +} + +/** + * @param time 2.82 + */ +export const formatVttTime = (time: number) => { + if (!time) return '00:00:00.000' + + const hours = Math.floor(time / 60 / 60) + const minutes = Math.floor(time / 60 % 60) + const seconds = Math.floor(time % 60) + const ms = Math.floor((time % 1) * 1000) + return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}.${ms.toString().padStart(3, '0')}` +} + +export const preventFunc = (e: SyntheticEvent) => { + e.preventDefault() +} + +export const stopPopFunc = (e: SyntheticEvent) => { + e.stopPropagation() +} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..4361dd3 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1,8 @@ +/// + +interface ImportMetaEnv { +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/tailwind.config.cjs b/tailwind.config.cjs new file mode 100644 index 0000000..ffe1321 --- /dev/null +++ b/tailwind.config.cjs @@ -0,0 +1,35 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + darkMode: 'class', + content: ["./src/**/*.{js,ts,jsx,tsx}"], + theme: { + extend: {}, + }, + plugins: [ + require('tailwind-scrollbar-hide'), + require('@tailwindcss/line-clamp'), + require('@tailwindcss/typography'), + require('daisyui'), + ], + + daisyui: { + styled: true, + themes: [{ + light: { + ...require("daisyui/src/colors/themes")["[data-theme=light]"], + "--rounded-btn": "0.15rem", + }, + }, { + dark: { + ...require("daisyui/src/colors/themes")["[data-theme=dark]"], + "--rounded-btn": "0.15rem", + } + }], + base: true, + utils: true, + logs: true, + rtl: false, + prefix: "", + darkTheme: "dark", + }, +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..9539005 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "types": [ + "@types/chrome" + ] + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..e229c97 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true + }, + "include": ["vite.config.ts", "manifest.json"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..e07aa2b --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,29 @@ +import {defineConfig, PluginOption} from 'vite' +import react from '@vitejs/plugin-react' +import {visualizer} from "rollup-plugin-visualizer"; +import {crx} from '@crxjs/vite-plugin' +// @ts-ignore +import manifest from './manifest.json' + +// https://vitejs.dev/config/ +export default ({mode}) => { + const plugins = [ + react(), + visualizer() as PluginOption, + ] + // @ts-ignore + if (mode === 'production_chrome') { + plugins.push(crx({ + manifest, + })) + } + return defineConfig({ + base: '/', + plugins, + css: { + modules: { + localsConvention: "camelCase" + } + } + }) +}